From 1d52ad6c4add0d86e0fb3da8ea4a72451e88f4be Mon Sep 17 00:00:00 2001 From: Dorian Savina Date: Thu, 4 Nov 2021 17:49:54 +0100 Subject: [PATCH 1/4] Use 'ServerRequestInterface::getParsedBody' with non-JSON requests as well --- src/Server/Helper.php | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Server/Helper.php b/src/Server/Helper.php index 3278b1b8d..2b6ff5133 100644 --- a/src/Server/Helper.php +++ b/src/Server/Helper.php @@ -525,11 +525,9 @@ public function parsePsrRequest(RequestInterface $request) $this->assertJsonObjectOrArray($bodyParams); } else { - parse_str((string) $request->getBody(), $bodyParams); - - if (! is_array($bodyParams)) { - throw new RequestError('Unexpected content type: ' . Utils::printSafeJson($contentType[0])); - } + $bodyParams = $request instanceof ServerRequestInterface + ? $request->getParsedBody() + : $this->decodeContent((string) $request->getBody(), $contentType[0]); } } @@ -558,6 +556,22 @@ protected function decodeJson(string $rawBody) return $bodyParams; } + /** + * @return array + * + * @throws RequestError + */ + protected function decodeContent(string $rawBody, string $contentType): array + { + parse_str($rawBody, $bodyParams); + + if (! is_array($bodyParams)) { + throw new RequestError('Unexpected content type: ' . Utils::printSafeJson($contentType)); + } + + return $bodyParams; + } + /** * @param mixed $bodyParams * From 56d3d98e6fd6b8b8665efbd71db49316d558f3fb Mon Sep 17 00:00:00 2001 From: Dorian Savina Date: Fri, 5 Nov 2021 12:04:56 +0100 Subject: [PATCH 2/4] Test parsing of a `application/x-www-form-urlencoded` ServerRequest --- tests/Server/RequestParsingTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Server/RequestParsingTest.php b/tests/Server/RequestParsingTest.php index c5592fc00..c0305b679 100644 --- a/tests/Server/RequestParsingTest.php +++ b/tests/Server/RequestParsingTest.php @@ -10,6 +10,7 @@ use GraphQL\Server\RequestError; use InvalidArgumentException; use Nyholm\Psr7\Request; +use Nyholm\Psr7\ServerRequest; use Nyholm\Psr7\Stream; use Nyholm\Psr7\Uri; use PHPUnit\Framework\TestCase; @@ -110,6 +111,7 @@ public function testParsesUrlencodedRequest(): void $parsed = [ 'raw' => $this->parseRawFormUrlencodedRequest($post), 'psr' => $this->parsePsrFormUrlEncodedRequest($post), + 'serverRequest' => $this->parsePsrFormUrlEncodedServerRequest($post), ]; foreach ($parsed as $method => $parsedBody) { @@ -155,6 +157,19 @@ private function parsePsrFormUrlEncodedRequest($postValue) ); } + private function parsePsrFormUrlEncodedServerRequest($postValue) + { + $helper = new Helper(); + + return $helper->parsePsrRequest( + (new ServerRequest( + 'POST', + '', + ['Content-Type' => 'application/x-www-form-urlencoded'], + ))->withParsedBody($postValue) + ); + } + public function testParsesGetRequest(): void { $query = '{my query}'; From 319798f62f7f6013e8c4c7f63b001c9448a1de57 Mon Sep 17 00:00:00 2001 From: Dorian Savina Date: Fri, 5 Nov 2021 13:22:28 +0100 Subject: [PATCH 3/4] Fallback to 'RequestInterface::getBody()' when empty 'ServerRequestInterface::getParsedBody()' --- src/Server/Helper.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Server/Helper.php b/src/Server/Helper.php index 2b6ff5133..8105bbb0a 100644 --- a/src/Server/Helper.php +++ b/src/Server/Helper.php @@ -525,9 +525,11 @@ public function parsePsrRequest(RequestInterface $request) $this->assertJsonObjectOrArray($bodyParams); } else { - $bodyParams = $request instanceof ServerRequestInterface - ? $request->getParsedBody() - : $this->decodeContent((string) $request->getBody(), $contentType[0]); + if ($request instanceof ServerRequestInterface) { + $bodyParams = $request->getParsedBody(); + } + + $bodyParams ??= $this->decodeContent((string) $request->getBody(), $contentType[0]); } } From 40d31cd361e14a9307c757118268b6393b2d93f1 Mon Sep 17 00:00:00 2001 From: Dorian Savina Date: Fri, 5 Nov 2021 13:23:05 +0100 Subject: [PATCH 4/4] Test both empty 'body' and empty 'parsedBody' --- tests/Server/RequestParsingTest.php | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/Server/RequestParsingTest.php b/tests/Server/RequestParsingTest.php index c0305b679..914f3749e 100644 --- a/tests/Server/RequestParsingTest.php +++ b/tests/Server/RequestParsingTest.php @@ -111,7 +111,8 @@ public function testParsesUrlencodedRequest(): void $parsed = [ 'raw' => $this->parseRawFormUrlencodedRequest($post), 'psr' => $this->parsePsrFormUrlEncodedRequest($post), - 'serverRequest' => $this->parsePsrFormUrlEncodedServerRequest($post), + 'serverRequest' => $this->parsePsrFormUrlEncodedServerRequest($post, false), + 'parsedServerRequest' => $this->parsePsrFormUrlEncodedServerRequest($post, true), ]; foreach ($parsed as $method => $parsedBody) { @@ -157,17 +158,22 @@ private function parsePsrFormUrlEncodedRequest($postValue) ); } - private function parsePsrFormUrlEncodedServerRequest($postValue) + private function parsePsrFormUrlEncodedServerRequest($postValue, bool $parsed) { $helper = new Helper(); - return $helper->parsePsrRequest( - (new ServerRequest( - 'POST', - '', - ['Content-Type' => 'application/x-www-form-urlencoded'], - ))->withParsedBody($postValue) + $request = new ServerRequest( + 'POST', + '', + ['Content-Type' => 'application/x-www-form-urlencoded'], + $parsed ? null : http_build_query($postValue), ); + + if ($parsed) { + $request = $request->withParsedBody($postValue); + } + + return $helper->parsePsrRequest($request); } public function testParsesGetRequest(): void