diff --git a/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php --- a/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php @@ -25,11 +25,18 @@ $content_type = idx($_SERVER, 'CONTENT_TYPE'); $is_form_data = preg_match('@^multipart/form-data@i', $content_type); - $raw_input = PhabricatorStartup::getRawInput(); - if (strlen($raw_input) && !$is_form_data) { - $data += $parser->parseQueryString($raw_input); - } else if ($_POST) { - $data += $_POST; + $request_method = idx($_SERVER, 'REQUEST_METHOD'); + if ($request_method === 'PUT') { + // For PUT requests, do nothing: in particular, do NOT read input. This + // allows us to stream input later and process very large PUT requests, + // like those coming from Git LFS. + } else { + $raw_input = PhabricatorStartup::getRawInput(); + if (strlen($raw_input) && !$is_form_data) { + $data += $parser->parseQueryString($raw_input); + } else if ($_POST) { + $data += $_POST; + } } $data += $parser->parseQueryString(idx($_SERVER, 'QUERY_STRING', '')); diff --git a/support/PhabricatorStartup.php b/support/PhabricatorStartup.php --- a/support/PhabricatorStartup.php +++ b/support/PhabricatorStartup.php @@ -83,6 +83,26 @@ * @task info */ public static function getRawInput() { + if (self::$rawInput === null) { + $stream = new AphrontRequestStream(); + + if (isset($_SERVER['HTTP_CONTENT_ENCODING'])) { + $encoding = trim($_SERVER['HTTP_CONTENT_ENCODING']); + $stream->setEncoding($encoding); + } + + $input = ''; + do { + $bytes = $stream->readData(); + if ($bytes === null) { + break; + } + $input .= $bytes; + } while (true); + + self::$rawInput = $input; + } + return self::$rawInput; } @@ -128,47 +148,6 @@ self::detectPostMaxSizeTriggered(); self::beginOutputCapture(); - - if (isset($_SERVER['HTTP_CONTENT_ENCODING'])) { - $encoding = trim($_SERVER['HTTP_CONTENT_ENCODING']); - } else { - $encoding = null; - } - - $input_stream = fopen('php://input', 'rb'); - if (!$input_stream) { - self::didFatal( - 'Unable to open "php://input" to read HTTP request body.'); - } - - 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; }