Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15411657
D21116.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
6 KB
Referenced Files
None
Subscribers
None
D21116.diff
View Options
diff --git a/src/aphront/configuration/AphrontApplicationConfiguration.php b/src/aphront/configuration/AphrontApplicationConfiguration.php
--- a/src/aphront/configuration/AphrontApplicationConfiguration.php
+++ b/src/aphront/configuration/AphrontApplicationConfiguration.php
@@ -771,12 +771,21 @@
);
}
+ $raw_input = @file_get_contents('php://input');
+ if ($raw_input !== false) {
+ $base64_input = base64_encode($raw_input);
+ } else {
+ $base64_input = null;
+ }
+
$result = array(
'path' => $path,
'params' => $params,
'user' => idx($_SERVER, 'PHP_AUTH_USER'),
'pass' => idx($_SERVER, 'PHP_AUTH_PW'),
+ 'raw.base64' => $base64_input,
+
// This just makes sure that the response compresses well, so reasonable
// algorithms should want to gzip or deflate it.
'filler' => str_repeat('Q', 1024 * 16),
diff --git a/src/aphront/requeststream/AphrontRequestStream.php b/src/aphront/requeststream/AphrontRequestStream.php
--- a/src/aphront/requeststream/AphrontRequestStream.php
+++ b/src/aphront/requeststream/AphrontRequestStream.php
@@ -89,4 +89,24 @@
return $stream;
}
+ public static function supportsGzip() {
+ if (!function_exists('gzencode') || !function_exists('gzdecode')) {
+ return false;
+ }
+
+ $has_zlib = false;
+
+ // NOTE: At least locally, this returns "zlib.*", which is not terribly
+ // reassuring. We care about "zlib.inflate".
+
+ $filters = stream_get_filters();
+ foreach ($filters as $filter) {
+ if (preg_match('/^zlib\\./', $filter)) {
+ $has_zlib = true;
+ }
+ }
+
+ return $has_zlib;
+ }
+
}
diff --git a/src/applications/config/check/PhabricatorWebServerSetupCheck.php b/src/applications/config/check/PhabricatorWebServerSetupCheck.php
--- a/src/applications/config/check/PhabricatorWebServerSetupCheck.php
+++ b/src/applications/config/check/PhabricatorWebServerSetupCheck.php
@@ -50,6 +50,20 @@
new PhutilOpaqueEnvelope($expect_pass))
->setTimeout(5);
+ if (AphrontRequestStream::supportsGzip()) {
+ $gzip_uncompressed = str_repeat('Quack! ', 128);
+ $gzip_compressed = gzencode($gzip_uncompressed);
+
+ $gzip_future = id(new HTTPSFuture($base_uri))
+ ->addHeader('X-Phabricator-SelfCheck', 1)
+ ->addHeader('Content-Encoding', 'gzip')
+ ->setTimeout(5)
+ ->setData($gzip_compressed);
+
+ } else {
+ $gzip_future = null;
+ }
+
// Make a request to the metadata service available on EC2 instances,
// to test if we're running on a T2 instance in AWS so we can warn that
// this is a bad idea. Outside of AWS, this request will just fail.
@@ -61,12 +75,16 @@
$self_future,
$ec2_future,
);
+
+ if ($gzip_future) {
+ $futures[] = $gzip_future;
+ }
+
$futures = new FutureIterator($futures);
foreach ($futures as $future) {
// Just resolve the futures here.
}
-
try {
list($body) = $ec2_future->resolvex();
$body = trim($body);
@@ -259,6 +277,107 @@
->setMessage($message);
}
+ if ($gzip_future) {
+ $this->checkGzipResponse(
+ $gzip_future,
+ $gzip_uncompressed,
+ $gzip_compressed);
+ }
+ }
+
+ private function checkGzipResponse(
+ Future $future,
+ $uncompressed,
+ $compressed) {
+
+ try {
+ list($body, $headers) = $future->resolvex();
+ } catch (Exception $ex) {
+ return;
+ }
+
+ try {
+ $structure = phutil_json_decode(trim($body));
+ } catch (Exception $ex) {
+ return;
+ }
+
+ $raw_body = idx($structure, 'raw.base64');
+ $raw_body = base64_decode($raw_body);
+
+ // The server received the exact compressed bytes we expected it to, so
+ // everything is working great.
+ if ($raw_body === $compressed) {
+ return;
+ }
+
+ // If the server received a prefix of the raw uncompressed string, it
+ // is almost certainly configured to decompress responses inline. Guide
+ // users to this problem narrowly.
+
+ // Otherwise, something is wrong but we don't have much of a clue what.
+
+ $message = array();
+ $message[] = pht(
+ 'Phabricator sent itself a test request that was compressed with '.
+ '"Content-Encoding: gzip", but received different bytes than it '.
+ 'sent.');
+
+ $prefix_len = min(strlen($raw_body), strlen($uncompressed));
+ if ($prefix_len > 16 && !strncmp($raw_body, $uncompressed, $prefix_len)) {
+ $message[] = pht(
+ 'The request body that the server received had already been '.
+ 'decompressed. This strongly suggests your webserver is configured '.
+ 'to decompress requests inline, before they reach PHP.');
+ $message[] = pht(
+ 'If you are using Apache, your server may be configured with '.
+ '"SetInputFilter DEFLATE". This directive destructively mangles '.
+ 'requests and emits them with "Content-Length" and '.
+ '"Content-Encoding" headers that no longer match the data in the '.
+ 'request body.');
+ } else {
+ $message[] = pht(
+ 'This suggests your webserver is configured to decompress or mangle '.
+ 'compressed requests.');
+
+ $message[] = pht(
+ 'The request body Phabricator sent began:');
+ $message[] = $this->snipBytes($compressed);
+
+ $message[] = pht(
+ 'The request body Phabricator received began:');
+ $message[] = $this->snipBytes($raw_body);
+ }
+
+ $message[] = pht(
+ 'Identify the component in your webserver configuration which is '.
+ 'decompressing or mangling requests and disable it. Phabricator '.
+ 'will not work properly until you do.');
+
+ $message = phutil_implode_html("\n\n", $message);
+
+ $this->newIssue('webserver.accept-gzip')
+ ->setName(pht('Compressed Requests Not Received Properly'))
+ ->setSummary(
+ pht(
+ 'Your webserver is not handling compressed request bodies '.
+ 'properly.'))
+ ->setMessage($message);
+ }
+
+ private function snipBytes($raw) {
+ if (!strlen($raw)) {
+ $display = pht('<empty>');
+ } else {
+ $snip = substr($raw, 0, 24);
+ $display = phutil_loggable_string($snip);
+
+ if (strlen($snip) < strlen($raw)) {
+ $display .= '...';
+ }
+ }
+
+ return phutil_tag('tt', array(), $display);
}
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Mar 20, 9:31 AM (15 h, 14 m ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7389109
Default Alt Text
D21116.diff (6 KB)
Attached To
Mode
D21116: Add a setup warning to detect "SetInputFilter DEFLATE" and other "Content-Encoding" request mangling
Attached
Detach File
Event Timeline
Log In to Comment