1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 00:32:42 +01:00

Remove the execution time limit (if any) before sinking HTTP responses

Summary:
Ref T12907. At least part of the problem is that we can hit PHP's `max_execution_time` limit on the file download pathway.

We don't currently set this to anything in the application itself, but PHP often sets it to 30s by default (and we have it set to 30s in production).

When writing responses, remove this limit. This limit is mostly a protection against accidental loops/recurison/etc., not a process slot protection. It doesn't really protect process slots anyway, since it doesn't start counting until the request starts executing, so you can (by default) //send// the request as slowly as you want without hitting this limit.

By releasing the limit this late, hopefully all the loops and recursion issues have already been caught and we're left with mostly smooth sailing.

We already remove this limit when sending `git clone` responses in `DiffusionServeController` and nothing has blown up. This affects `git clone http://` and similar.

(I may have had this turned off locally and/or just be too impatient to wait 30s, which is why I haven't caught this previously.)

Test Plan:
  - Poked around and downloaded some files.
  - Will `curl ...` in production and see if that goes better.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T12907

Differential Revision: https://secure.phabricator.com/D19547
This commit is contained in:
epriestley 2018-07-30 09:40:47 -07:00
parent 9cf3b3bbf8
commit 81a7c9ac43
2 changed files with 27 additions and 1 deletions

View file

@ -54,7 +54,16 @@ abstract class AphrontResponse extends Phobject {
public function getContentIterator() {
return array($this->buildResponseString());
// By default, make sure responses are truly returning a string, not some
// kind of object that behaves like a string.
// We're going to remove the execution time limit before dumping the
// response into the sink, and want any rendering that's going to occur
// to happen BEFORE we release the limit.
return array(
(string)$this->buildResponseString(),
);
}
public function buildResponseString() {

View file

@ -112,6 +112,23 @@ abstract class AphrontHTTPSink extends Phobject {
$response->getHTTPResponseMessage());
$this->writeHeaders($all_headers);
// Allow clients an unlimited amount of time to download the response.
// This allows clients to perform a "slow loris" attack, where they
// download a large response very slowly to tie up process slots. However,
// concurrent connection limits and "RequestReadTimeout" already prevent
// this attack. We could add our own minimum download rate here if we want
// to make this easier to configure eventually.
// For normal page responses, we've fully rendered the page into a string
// already so all that's left is writing it to the client.
// For unusual responses (like large file downloads) we may still be doing
// some meaningful work, but in theory that work is intrinsic to streaming
// the response.
set_time_limit(0);
$abort = false;
foreach ($data as $block) {
if (!$this->isWritable()) {