Skip to content

Fix edge case with StreamedResponse where headers are sent twice #20289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 24, 2016

Conversation

Nicofuma
Copy link
Contributor

Q A
Branch? 2.7
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes/no
Fixed tickets
License MIT
Doc PR

If you have PHPs output buffering enabled (output_buffering=4096 in your php.ini per example), there is an edge case with the StreamedResponse object where the headers are sent twice. Even if it is harmless most of the time, it can be critical sometimes (per example, if an Access-Control-Allow-Origin header is duplicated the browser will block the request).

Explanation: because the streamed response may need the request in order to generate the content, the StreamedResponseListener class calls the send method of the Response when the event kernel.response is fired. To prevent the content from being duplicated, a state has been introduced in the sendContent() method and it works fine.

But there is an edge case is the headers of the response. If the content generated by the sendContent() method is smaller than the value defined for output_buffering in the php.ini then the buffer won't be flushed and the headers_sent() function will return false.
Therefore when $response->send() is called for the second time (in the app.php file), the headers will be sent a second time.

@@ -28,6 +28,7 @@ class StreamedResponse extends Response
{
protected $callback;
protected $streamed;
protected $headersSent;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be private

@Nicofuma Nicofuma force-pushed the fix-duplicated-headers-stream branch from 59c8d69 to a79991f Compare October 24, 2016 14:36
@fabpot
Copy link
Member

fabpot commented Oct 24, 2016

Thank you @Nicofuma.

@fabpot fabpot merged commit a79991f into symfony:2.7 Oct 24, 2016
fabpot added a commit that referenced this pull request Oct 24, 2016
… twice (Nicofuma)

This PR was merged into the 2.7 branch.

Discussion
----------

Fix edge case with StreamedResponse where headers are sent twice

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes/no
| Fixed tickets |
| License       | MIT
| Doc PR        |

If you have PHPs output buffering enabled (`output_buffering=4096` in your php.ini per example), there is an edge case with the StreamedResponse object where the headers are sent twice. Even if it is harmless most of the time, it can be critical sometimes (per example, if an `Access-Control-Allow-Origin` header is duplicated the browser will block the request).

Explanation: because the streamed response may need the request in order to generate the content, the `StreamedResponseListener` class calls the send method of the `Response` when the event `kernel.response` is fired. To prevent the content from being duplicated, a state has been introduced in the `sendContent()` method and it works fine.

But there is an edge case is the headers of the response. If the content generated by the `sendContent()` method is smaller than the value defined for `output_buffering` in the `php.ini` then the buffer won't be flushed and the `headers_sent()` function will return false.
Therefore when `$response->send()` is called for the second time (in the `app.php` file), the headers will be sent a second time.

Commits
-------

a79991f Fix edge case with StreamedResponse where headers are sent twice
@HeahDude
Copy link
Contributor

thx Tristan :)

This was referenced Oct 27, 2016
@patrick-mcdougle
Copy link
Contributor

Not sure how this bug should be possible because the send method of the response class is supposed to take care of that by calling fastcgi_finish_request which should flush the ob. Unless I'm reading that wrong.

@Nicofuma
Copy link
Contributor Author

@patrick-mcdougle it is tied to the StreamResponse and StreamedResponseListener where Response::closeOutputBuffers() is only called in Kernel::terminate().

nicolas-grekas added a commit that referenced this pull request Oct 19, 2017
This PR was squashed before being merged into the 2.7 branch (closes #24626).

Discussion
----------

streamed response should return $this

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | may be yes?
| Deprecations? | no
| Tests pass?   | yes
| License       | MIT

---

`sendHeaders()` and `sendContent()` should return $this,  as in the parent class.

related PRs:
#2935
#20289

Commits
-------

058fb84 streamed response should return $this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants