diff --git a/src/swoole/src/SymfonyHttpBridge.php b/src/swoole/src/SymfonyHttpBridge.php index ca26c2e..8479099 100644 --- a/src/swoole/src/SymfonyHttpBridge.php +++ b/src/swoole/src/SymfonyHttpBridge.php @@ -5,7 +5,6 @@ use Swoole\Http\Request; use Swoole\Http\Response; use Symfony\Component\HttpFoundation\BinaryFileResponse; -use Symfony\Component\HttpFoundation\HeaderBag; use Symfony\Component\HttpFoundation\Request as SymfonyRequest; use Symfony\Component\HttpFoundation\Response as SymfonyResponse; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -21,18 +20,15 @@ final class SymfonyHttpBridge { public static function convertSwooleRequest(Request $request): SymfonyRequest { - $sfRequest = new SymfonyRequest( + return new SymfonyRequest( $request->get ?? [], $request->post ?? [], [], $request->cookie ?? [], $request->files ?? [], - array_change_key_case($request->server ?? [], CASE_UPPER), + self::buildServer($request), $request->rawContent() ); - $sfRequest->headers = new HeaderBag($request->header ?? []); - - return $sfRequest; } public static function reflectSymfonyResponse(SymfonyResponse $sfResponse, Response $response): void @@ -62,4 +58,25 @@ public static function reflectSymfonyResponse(SymfonyResponse $sfResponse, Respo $response->end($sfResponse->getContent()); } } + + /** + * We must add the headers to the server otherwise they will not be available in sub-requests + */ + private static function buildServer(Request $request): array + { + $serverHeaders = []; + /** Inspired by https://github.com/symfony/symfony/blob/85366b4767b1761f40701f4ea6692d5280e0d58d/src/Symfony/Component/HttpFoundation/Request.php#L546-L553 */ + foreach ($request->header ?? [] as $name => $value) { + $name = strtoupper(str_replace('-', '_', $name)); + if (false === in_array($name, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'])) { + $name = sprintf('HTTP_%s', $name); + } + $serverHeaders[$name] = $value; + } + + return array_merge( + array_change_key_case($request->server ?? [], CASE_UPPER), + $serverHeaders + ); + } } diff --git a/src/swoole/tests/Unit/SymfonyHttpBridgeTest.php b/src/swoole/tests/Unit/SymfonyHttpBridgeTest.php index b2ef8da..7d73680 100644 --- a/src/swoole/tests/Unit/SymfonyHttpBridgeTest.php +++ b/src/swoole/tests/Unit/SymfonyHttpBridgeTest.php @@ -23,7 +23,7 @@ public function testThatSwooleRequestIsConverted(): void { $request = $this->createMock(Request::class); $request->server = ['request_method' => 'post']; - $request->header = ['content-type' => 'application/json']; + $request->header = ['content-type' => 'application/json', 'x-upstream-use' => 'swoole', 'http-upstream' => 'swoole']; $request->cookie = ['foo' => 'cookie']; $request->get = ['foo' => 'get']; $request->post = ['foo' => 'post']; @@ -40,8 +40,17 @@ public function testThatSwooleRequestIsConverted(): void $sfRequest = SymfonyHttpBridge::convertSwooleRequest($request); - $this->assertSame(['REQUEST_METHOD' => 'post'], $sfRequest->server->all()); - $this->assertSame(['content-type' => ['application/json']], $sfRequest->headers->all()); + $this->assertSame([ + 'REQUEST_METHOD' => 'post', + 'CONTENT_TYPE' => 'application/json', + 'HTTP_X_UPSTREAM_USE' => 'swoole', + 'HTTP_HTTP_UPSTREAM' => 'swoole', + ], $sfRequest->server->all()); + $this->assertSame([ + 'content-type' => ['application/json'], + 'x-upstream-use' => ['swoole'], + 'http-upstream' => ['swoole'], + ], $sfRequest->headers->all()); $this->assertSame(['foo' => 'cookie'], $sfRequest->cookies->all()); $this->assertSame(['foo' => 'get'], $sfRequest->query->all()); $this->assertSame(['foo' => 'post'], $sfRequest->request->all()); @@ -148,4 +157,40 @@ public function testStreamedResponseWillRespondWithOneChunkAtATime(): void SymfonyHttpBridge::reflectSymfonyResponse($sfResponse, $response); } + + public function testThatSubRequestGetsParentRequestHeaders(): void + { + $request = $this->createMock(Request::class); + $request->server = ['request_method' => 'post']; + $request->header = ['host' => 'example.com', 'content-type' => 'application/json', 'x-upstream-use' => 'swoole', 'http-upstream' => 'swoole']; + $request->cookie = ['foo' => 'cookie']; + $request->get = ['foo' => 'get']; + $request->post = ['foo' => 'post']; + $request->files = [ + 'foo' => [ + 'name' => 'file', + 'type' => 'image/png', + 'tmp_name' => '/tmp/file', + 'error' => UPLOAD_ERR_CANT_WRITE, + 'size' => 0, + ], + ]; + + $sfRequest = SymfonyHttpBridge::convertSwooleRequest($request); + + // Simulating creating sub-request + $sfSubRequest = SymfonyRequest::create( + '/some-url', + 'get', + [], + $sfRequest->cookies->all(), + [], + $sfRequest->server->all() + ); + + $this->assertSame('example.com', $sfSubRequest->headers->get('host')); + $this->assertSame('application/json', $sfSubRequest->headers->get('content-type')); + $this->assertSame('swoole', $sfSubRequest->headers->get('x-upstream-use')); + $this->assertSame('swoole', $sfSubRequest->headers->get('http-upstream')); + } }