Skip to content

Commit 2b5b4d0

Browse files
authored
fix: RoadRunner streaming through generators (#939)
* fix: RoadRunner streaming through generators * Update RoadRunnerClient.php
1 parent 4657dcf commit 2b5b4d0

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

src/RoadRunner/RoadRunnerClient.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Laravel\Octane\RoadRunner;
44

5+
use Generator;
56
use Illuminate\Foundation\Application;
67
use Illuminate\Http\Request;
78
use Laravel\Octane\Contracts\Client;
@@ -10,6 +11,7 @@
1011
use Laravel\Octane\Octane;
1112
use Laravel\Octane\OctaneResponse;
1213
use Laravel\Octane\RequestContext;
14+
use ReflectionFunction;
1315
use Spiral\RoadRunner\Http\PSR7Worker;
1416
use Symfony\Component\HttpFoundation\BinaryFileResponse;
1517
use Symfony\Component\HttpFoundation\StreamedResponse;
@@ -47,6 +49,20 @@ public function respond(RequestContext $context, OctaneResponse $octaneResponse)
4749
);
4850
}
4951

52+
if (
53+
($octaneResponse->response instanceof StreamedResponse) &&
54+
($responseCallback = $octaneResponse->response->getCallback()) &&
55+
((new ReflectionFunction($responseCallback))->getReturnType()?->getName() === Generator::class)
56+
) {
57+
$this->client->getHttpWorker()->respond(
58+
$octaneResponse->response->getStatusCode(),
59+
$responseCallback(),
60+
$this->toPsr7Response($octaneResponse->response)->getHeaders(),
61+
);
62+
63+
return;
64+
}
65+
5066
$this->client->respond($this->toPsr7Response($octaneResponse->response));
5167
}
5268

tests/RoadRunnerClientTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace Laravel\Octane\Tests;
44

55
use Exception;
6+
use Generator;
7+
use Hamcrest\Core\IsInstanceOf;
68
use Illuminate\Http\Request;
79
use Illuminate\Http\Response;
810
use Laminas\Diactoros\ServerRequestFactory;
@@ -11,6 +13,7 @@
1113
use Laravel\Octane\RoadRunner\RoadRunnerClient;
1214
use Mockery;
1315
use Psr\Http\Message\ResponseInterface;
16+
use Spiral\RoadRunner\Http\HttpWorker;
1417
use Spiral\RoadRunner\Http\PSR7Worker;
1518
use Symfony\Component\HttpFoundation\StreamedResponse;
1619

@@ -63,6 +66,32 @@ public function test_respond_method_send_streamed_response_to_roadrunner()
6366
}, 200)));
6467
}
6568

69+
/** @doesNotPerformAssertions @test */
70+
public function test_respond_method_send_streamed_generator_response_to_roadrunner()
71+
{
72+
$client = new RoadRunnerClient($psr7Client = Mockery::mock(PSR7Worker::class));
73+
74+
$psr7Request = (new ServerRequestFactory)->createServerRequest('GET', '/home');
75+
$psr7Request = $psr7Request->withQueryParams(['name' => 'Taylor']);
76+
77+
$httpWorker = Mockery::mock(HttpWorker::class);
78+
79+
$responseCallback = function (): Generator {
80+
yield 'Hello World';
81+
};
82+
83+
$psr7Client->shouldReceive('getHttpWorker')->once()->andReturn($httpWorker);
84+
$httpWorker->shouldReceive('respond')->once()->with(
85+
200,
86+
IsInstanceOf::anInstanceOf(Generator::class),
87+
Mockery::hasKey('cache-control'),
88+
);
89+
90+
$client->respond(new RequestContext([
91+
'psr7Request' => $psr7Request,
92+
]), new OctaneResponse(new StreamedResponse($responseCallback, 200)));
93+
}
94+
6695
/** @doesNotPerformAssertions @test */
6796
public function test_error_method_sends_error_response_to_roadrunner()
6897
{

0 commit comments

Comments
 (0)