Skip to content

Commit 04607d0

Browse files
committed
Asynchronously handle streamed responses
1 parent 09fb0ae commit 04607d0

File tree

1 file changed

+26
-18
lines changed

1 file changed

+26
-18
lines changed

Bridges/HttpKernel.php

+26-18
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,20 @@ public function onRequest(ReactRequest $request, HttpResponse $response)
7878

7979
$syRequest = $this->mapRequest($request);
8080

81-
//start buffering the output, so cgi is not sending any http headers
82-
//this is necessary because it would break session handling since
83-
//headers_sent() returns true if any unbuffered output reaches cgi stdout.
84-
ob_start();
85-
8681
try {
82+
// start buffering the output, so cgi is not sending any http headers
83+
// this is necessary because it would break session handling since
84+
// headers_sent() returns true if any unbuffered output reaches cgi stdout.
85+
ob_start();
86+
8787
if ($this->bootstrap instanceof HooksInterface) {
8888
$this->bootstrap->preHandle($this->application);
8989
}
9090

9191
$syResponse = $this->application->handle($syRequest);
92+
93+
// should not receive output from application->handle()
94+
ob_end_clean();
9295
} catch (\Exception $exception) {
9396
$response->writeHead(500); // internal server error
9497
$response->end();
@@ -170,15 +173,10 @@ protected function mapRequest(ReactRequest $reactRequest)
170173
*/
171174
protected function mapResponse(HttpResponse $reactResponse, SymfonyResponse $syResponse)
172175
{
173-
//end active session
176+
// end active session
174177
if (PHP_SESSION_ACTIVE === session_status()) {
175178
session_write_close();
176-
session_unset(); //reset $_SESSION
177-
}
178-
179-
$content = $syResponse->getContent();
180-
if ($syResponse instanceof SymfonyStreamedResponse) {
181-
$syResponse->sendContent();
179+
session_unset(); // reset $_SESSION
182180
}
183181

184182
$nativeHeaders = [];
@@ -200,8 +198,8 @@ protected function mapResponse(HttpResponse $reactResponse, SymfonyResponse $syR
200198
}
201199
}
202200

203-
//after reading all headers we need to reset it, so next request
204-
//operates on a clean header.
201+
// after reading all headers we need to reset it, so next request
202+
// operates on a clean header.
205203
header_remove();
206204

207205
$headers = array_merge($nativeHeaders, $syResponse->headers->allPreserveCase());
@@ -240,12 +238,22 @@ protected function mapResponse(HttpResponse $reactResponse, SymfonyResponse $syR
240238

241239
$reactResponse->writeHead($syResponse->getStatusCode(), $headers);
242240

243-
$stdOut = '';
244-
while ($buffer = @ob_get_clean()) {
245-
$stdOut .= $buffer;
241+
// asynchronously get content
242+
ob_start(function($buffer) use ($reactResponse) {
243+
$reactResponse->write($buffer);
244+
return '';
245+
}, 4096);
246+
247+
if ($syResponse instanceof SymfonyStreamedResponse) {
248+
$syResponse->sendContent();
249+
}
250+
else {
251+
echo($syResponse->getContent());
246252
}
247253

248-
$reactResponse->end($stdOut . $content);
254+
// flush remaining content
255+
@ob_end_flush();
256+
$reactResponse->end();
249257
}
250258

251259
/**

0 commit comments

Comments
 (0)