I'm sending a POST request from a client (tested with curl
and custom nodejs script) and don't get the response properly back. The whole thing works fine with PHP 5.6.
Environment
The whole thing is reduced as much as possible:
- everything running inside Vagrant VM Ubuntu 14.04 LTS
- nginx 1.9.7 from http://nginx.org/packages/ubuntu/
- PHP7 FPM compiled from official sources with
--disable-all --enable-fpm
The minimal nginx site config I'm using:
server {
listen 80;
server_name localhost;
location / {
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_pass unix:/var/run/php/php7.0-fpm-api.sock;
fastcgi_param SCRIPT_FILENAME /vagrant/index.php;
}
}
Example PHP script from /vagrant/index.php
:
<?php
echo str_repeat('.', 512);
flush(); // not necessary, only due testing
curl call I'm using: curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
NodeJS script I'm using:
'use strict';
var http = require('http');
var url = require('url');
var uri = url.parse(process.env.URL);
var options = {
method: 'POST', protocol: uri.protocol, hostname: uri.hostname,
port: uri.port, path: uri.path,
};
var data = '';
var httpRequest = http.request(options, function(res) {
res.on('data', function(chunk) {
console.log('received data', chunk.length);
data += chunk;
});
res.on('end', function() { console.log('final size', data.length); });
})
.on('error', function(err) { console.log(err); });
httpRequest.write('');
httpRequest.end();
Sending my test requests to PHP 5.6
$ curl http://localhost/
..........[cut off]
$ curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
..........[cut off]
$ URL=http://localhost/ node php7test.js
received data 512
final size 512
Sending my test requests to PHP 7.0
$ curl http://localhost/
..........[cut off]
$ URL=http://localhost/ node php7test.js
final size 0
$ curl -XPOST http://localhost/ -H "Transfer-Encoding: chunked" -d ''
curl: (18) transfer closed with outstanding read data remaining
Why am I mucking around with chunked encoding?
There's no business reason to do so, however I was using a very similar NodeJS code which defaults to chunked encoding which suddenly stopped working when switching to PHP7.
I've found the following to work from the nodejs side: explicitly setting a Content-Length
header removes the implicit Transfer-Encoding: chunked
header sent by NodeJS and thus works with both PHP versions.
However I'd like to understand why PHP7 behaves differently here and whether I'm in error or what's really going on here.
Update 1:
- I compared the
sapi/fpm/
sources between 5.6 and 7.0 and there's almost no difference I could spot except changes due PHP internal changes - The built-in server (
php -S
) is not affected, all tests
Update 2:
I bisected the PHP sources and was able to pinpoint when the behavior changed:
- last commit I was able to compile which works: https://github.com/php/php-src/commit/16265a59ac6bd433bfb636e4e44da1ad57cdcda9
- first commit I was able to compile again which didn't work: https://github.com/php/php-src/commit/86de98cabada88f4667839794c176ea37648498b
In between, output from git bisect
, commits I couldn't compile:
$ git bisect skip
There are only 'skip'ped commits left to test.
The first bad commit could be any of:
ba5ecf355fe792a5a2a8e6582d5e081d02b16fbf
e383cb4493031a7cd952cfcaed3297e583149c07
fef18f4bea1980a59a9283c2197bd090aaf500cb
18cf4e0a8a574034f60f4d123407c173e57e54ec
We cannot bisect more!
Having a feeling this could be a bug, I wrote this to internals, maybe they have some insights: https://marc.info/?l=php-internals&m=145090900217798&w=2