1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 11:30:55 +01:00

Fix HTTP body decompression in PHP 5.6

Summary:
Ref T10264. Under PHP 5.6, you are no longer allowed to use `compress.zlib://php://input` as an argument to either `fopen()` or `file_get_contents()`.

Instead, open `php://input` as a file handle, then add `zlib.inflate` as a stream wrapper. This requires some level of magic to work properly.

Test Plan:
First, I constructed a synthetic gzipped payload by typing some words into a file and using `gzcompress()` to compress it.

Then I used a `curl` command like this to make requests with it:

```
$ curl -X POST -H "Content-Length: 66" -H "Content-Type: text/plain" -H "Content-Encoding: gzip" --data-binary @payload.deflate -v http://127.0.0.1/
```

I modified Phabricator to just dump the raw request body and exit, and reproduced the issue under PHP 5.6 (no body, error in log) by brining up a micro instance in EC2 and installing php56 on it.

After this patch, it dumped the body properly instead, and PHP 5.5 also continued worked properly.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10264

Differential Revision: https://secure.phabricator.com/D15314
This commit is contained in:
epriestley 2016-02-20 11:51:33 -08:00
parent 929b4ccb5c
commit 42566379dc

View file

@ -135,13 +135,40 @@ final class PhabricatorStartup {
$encoding = null; $encoding = null;
} }
if ($encoding === 'gzip') { $input_stream = fopen('php://input', 'rb');
$source_stream = 'compress.zlib://php://input'; if (!$input_stream) {
} else { self::didFatal(
$source_stream = 'php://input'; 'Unable to open "php://input" to read HTTP request body.');
} }
self::$rawInput = (string)file_get_contents($source_stream); if ($encoding === 'gzip') {
$ok = stream_filter_append(
$input_stream,
'zlib.inflate',
STREAM_FILTER_READ,
array(
'window' => 30,
));
if (!$ok) {
self::didFatal(
'Failed to append gzip inflate filter to HTTP request body input '.
'stream.');
}
}
$input_data = '';
while (!feof($input_stream)) {
$read_bytes = fread($input_stream, 16 * 1024);
if ($read_bytes === false) {
self::didFatal(
'Failed to read input bytes from HTTP request body.');
}
$input_data .= $read_bytes;
}
fclose($input_stream);
self::$rawInput = $input_data;
} }