-
Notifications
You must be signed in to change notification settings - Fork 7.8k
curl responses mixed up with pcnt_fork #10633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I wonder If curl is trying to reuse the same connection in different forks: can you check verbose logs?
And after exec:
|
I changed the function request(\CurlMultiHandle $multi, string $url): int
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
$streamVerboseHandle = fopen('php://temp', 'w+');
curl_setopt($ch, CURLOPT_STDERR, $streamVerboseHandle);
curl_multi_add_handle($multi, $ch);
do {
$status = curl_multi_exec($multi, $active);
if ($active) {
curl_multi_select($multi);
}
} while ($active && $status === CURLM_OK);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
rewind($streamVerboseHandle);
echo stream_get_contents($streamVerboseHandle);
curl_multi_remove_handle($multi, $ch);
return (int)$httpCode;
} output: HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
X-Powered-By: PHP/8.1.16
Date: Mon, 20 Feb 2023 10:49:26 GMT
* Trying {remote_server}:9999...
* Connected to {remote_server} ({remote_server}) port 9999 (#0)
> HEAD /200 HTTP/1.1
Host: {remote_server}:9999
Accept: */*
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< X-Powered-By: PHP/8.1.16
< Date: Mon, 20 Feb 2023 10:49:26 GMT
<
* Connection #0 to host {remote_server} left intact
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
X-Powered-By: PHP/8.1.16
Date: Mon, 20 Feb 2023 10:49:26 GMT
* Found bundle for host {remote_server}: 0x56478f9ac6d0 [serially]
* Can not multiplex, even if we wanted to!
* Re-using existing connection! (#0) with host {remote_server}
* Connected to {remote_server} ({remote_server}) port 9999 (#0)
> HEAD /404 HTTP/1.1
Host: {remote_server}:9999
Accept: */*
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< X-Powered-By: PHP/8.1.16
< Date: Mon, 20 Feb 2023 10:49:26 GMT
<
* Excess found: excess = 129 url = /404 (zero-length body)
* Connection #0 to host {remote_server} left intact
GET /404 - 200
* Found bundle for host {remote_server}: 0x56478f9ac6d0 [serially]
* Can not multiplex, even if we wanted to!
* Re-using existing connection! (#0) with host {remote_server}
* Connected to {remote_server} ({remote_server}) port 9999 (#0)
> HEAD /200 HTTP/1.1
Host: {remote_server}:9999
Accept: */*
* Operation timed out after 5001 milliseconds with 0 bytes received
* Closing connection 0
GET /200 - 0 |
Yup, that exactly what is happening, one instance is consuming both responses. I don't know enough about curl to say if it's a bug or misuse or won't fix. Probably curl connection bundles should be dropped while forking. |
@adoy Can you help here? |
@iluuu1994 I'll try to have a look and see what I can find later this week. |
Hi guys. server.js const http = require('http');
http.createServer(function(request, response) {
let url = new URL(request.url, 'http://0.0.0.0:8888');
switch (true) {
case url.pathname.startsWith('/200'):
response.statusCode = 200;
response.end();
break;
case url.pathname.startsWith('/404'):
response.statusCode = 404;
response.end();
break
default:
response.statusCode = 500;
response.end();
}
}).listen(8888, (err) => {
if (err) {
return console.log('something bad happened', err);
}
console.log(`server is listening on 8888`);
}); main.c #include <stdlib.h>
#include <stdio.h>
#include <curl/curl.h>
#include <curl/multi.h>
#include <unistd.h>
size_t curl_write_function(void *ptr, size_t size, size_t nmemb, void *stream)
{
return size * nmemb;
}
int request(CURLM *multi, const char *url)
{
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1);
curl_easy_setopt(curl, CURLOPT_HEADER, 1L);
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_function);
curl_multi_add_handle(multi, curl);
int still_running;
do {
CURLMcode mc = curl_multi_perform(multi, &still_running);
if(!mc && still_running) {
curl_multi_poll(multi, NULL, 0, 200, NULL);
}
} while (still_running);
long response_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
curl_multi_remove_handle(multi, curl);
curl_easy_cleanup(curl);
return (int)response_code;
}
int main()
{
const char* url200 = "http://127.0.0.1:8888/200";
const char* url404 = "http://127.0.0.1:8888/404";
CURLM *multi = curl_multi_init();
request(multi, url200);// the request before fork() is important to reproduce the error
pid_t pid = fork();
if(pid == -1) {
return 1;
}
if (pid == 0) {
while(1) {
int response_code = request(multi, url200);
if(response_code != 200) {
printf("GET /200 - %d\n", response_code);
break;
}
}
} else {
while(1) {
int response_code = request(multi, url404);
if(response_code != 404) {
printf("GET /404 - %d\n", response_code);
break;
}
sleep(1);
}
}
return 0;
} start the server: node server.js reproduce the error: gcc main.c -o main -lcurl
./main
GET /200 - 404
GET /404 - 200 I hope this helps you. |
As this can apparently be reproduced in C without PHP being involved, this doesn't look like a PHP issue (and I don't think we should work-around). Actually, I'm not even sure this is a cURL issue; sharing a multi handle between a parent and (several) forked children is probably just not being supported ("undefined behavior"). Anyway, I'm not likely the best address to ask about |
Agreed this should not be shared and doesn't look like PHP issue to me either so closing. |
I think this might be fixed since curl 8.8.0 curl/curl#13625 |
Description
Hi!
I have a PHP daemon with two forks. Each fork makes an HTTP requests to a remote server.
Sometimes(often) responses in forks are mixed up.
How to reproduce
Remote server
server/index.php
Local server
client/test.php
Resulted in this output:
But I expected this output instead:
Error only reproduces with a remote(not local) server.
I tested it with two different remote servers.
PHP Version
8.1.0
Operating System
macOs BigSur 11.7.4
The text was updated successfully, but these errors were encountered: