Skip to content

curl responses mixed up with pcnt_fork #10633

@mrsuh

Description

@mrsuh

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

php -v
PHP 8.1.16 (cli) (built: Feb 14 2023 18:59:41) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.1.16, Copyright (c) Zend Technologies

server/index.php

<?php

switch ($_SERVER['REQUEST_URI']) {
    case '/200':
        http_response_code(200);
        break;
    case '/404':
        http_response_code(404);
        break;
    default:
        http_response_code(500);
}
symfony serve --no-tls --port=9999 --dir=server
 [OK] Web server listening
      The Web server is using PHP CGI 8.1.16
      http://127.0.0.1:9999
[Web Server ] Feb 15 15:02:25 |DEBUG  | PHP    Reloading PHP versions
[Web Server ] Feb 15 15:02:25 |DEBUG  | PHP    Using PHP version 8.1.16 (from default version in $PATH)
[Web Server ] Feb 15 15:02:25 |INFO   | PHP    listening path="/usr/bin/php-cgi" php="8.1.16" port=11238
[Web Server ] Feb 15 15:02:28 |INFO   | SERVER GET  (200) /200 ip=""
[Web Server ] Feb 15 15:02:28 |INFO   | SERVER GET  (200) /200
[Web Server ] Feb 15 15:02:28 |WARN   | SERVER GET  (404) /404
[Web Server ] Feb 15 15:02:29 |INFO   | SERVER GET  (200) /200
[Web Server ] Feb 15 15:02:29 |WARN   | SERVER GET  (404) /404
[Web Server ] Feb 15 15:02:30 |WARN   | SERVER GET  (404) /404
[Web Server ] Feb 15 15:02:30 |INFO   | SERVER GET  (200) /200
[Web Server ] Feb 15 15:02:31 |WARN   | SERVER GET  (404) /404
[Web Server ] Feb 15 15:02:31 |INFO   | SERVER GET  (200) /200
curl 'http://{remote_server}:9999/200' -I
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
X-Powered-By: PHP/8.1.16

curl 'http://{remote_server}:9999/404' -I
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=UTF-8
X-Powered-By: PHP/8.1.16

Local server

php -v
PHP 8.1.0 (cli) (built: Dec  2 2021 12:37:35) (ZTS)
Copyright (c) The PHP Group
Zend Engine v4.1.0, Copyright (c) Zend Technologies

client/test.php

<?php

$url200 = 'http://{remote_server}:9999/200';
$url404 = 'http://{remote_server}:9999/404';

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_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);
    curl_multi_remove_handle($multi, $ch);

    return (int)$httpCode;
}

$multi = curl_multi_init();

request($multi, $url200);// the request before pcntl_fork is important to reproduce error

$pid = pcntl_fork();
if ($pid === -1) {
    exit(1);
}

if ($pid) {
    $status = 0;
    while (pcntl_wait($status, WNOHANG | WUNTRACED) === 0) {
        $httpCode = request($multi, $url200);
        if ($httpCode !== 200) {
            printf("GET /200 - %d\n", $httpCode);
            break;
        }
        sleep(1);
    }
    posix_kill($pid, SIGKILL);
} else {
    while (true) {
        $httpCode = request($multi, $url404);
        if ($httpCode !== 404) {
            printf("GET /404 - %d\n", $httpCode);
            break;
        }

        sleep(1);
    }
}

Resulted in this output:

GET /404 - 200
GET /200 - 0 //timeout

But I expected this output instead:

GET /404 - 404
GET /200 - 200

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions