From 7c4c8f0ae3c69eedb5c6954b170928d4ab9ed264 Mon Sep 17 00:00:00 2001 From: pfk84 Date: Mon, 29 Apr 2024 15:34:48 +0200 Subject: [PATCH 1/2] Support for request method override SAPI: Added support for overriding the request method via either the X-HTTP-Method-Override header or _method "magic" parameter. This is useful due to known shortcomings of PHP not passing any parameters for other methods than POST. --- src/Io/SapiHandler.php | 6 ++++++ tests/Io/SapiHandlerTest.php | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/Io/SapiHandler.php b/src/Io/SapiHandler.php index fc2eeb1..9174093 100644 --- a/src/Io/SapiHandler.php +++ b/src/Io/SapiHandler.php @@ -92,6 +92,12 @@ public function requestFromGlobals(): ServerRequestInterface } $request = $request->withParsedBody($_POST); + // Method override via POST _method "magic" parameter or X-HTTP-Method-Override header, only for POST requests + $method_override = strtoupper($_POST["_method"] ?? $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ?? ""); + if ($request->getMethod() === "POST" && in_array($method_override, ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", "TRACE", "CONNECT"], true)) { + $request = $request->withMethod($method_override); + } + // Content-Length / Content-Type are special <3 if ($request->getHeaderLine('Content-Length') === '') { $request = $request->withoutHeader('Content-Length'); diff --git a/tests/Io/SapiHandlerTest.php b/tests/Io/SapiHandlerTest.php index a18b390..e0db12a 100644 --- a/tests/Io/SapiHandlerTest.php +++ b/tests/Io/SapiHandlerTest.php @@ -478,4 +478,40 @@ public function testRunWillSendResponseHeadersFromDeferredHandler(): void $this->assertEquals(['Content-Type:', 'Content-Length: 0'], xdebug_get_headers()); } + + public function testRequestFromGlobalsObeysMagicMethodOverride(): void + { + header_remove(); + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['_method'] = 'PUT'; + + $sapi = new SapiHandler(); + $request = $sapi->requestFromGlobals(); + + $this->assertEquals('PUT', $request->getMethod()); + } + + public function testRequestFromGlobalsObeysXHttpMethodOverrideHeader(): void + { + header_remove(); + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT'; + + $sapi = new SapiHandler(); + $request = $sapi->requestFromGlobals(); + + $this->assertEquals('PUT', $request->getMethod()); + } + + public function testRequestFromGlobalsIgnoresInvalidMethodOverride(): void + { + header_remove(); + $_SERVER['REQUEST_METHOD'] = 'PUT'; + $_POST['_method'] = 'POST'; + + $sapi = new SapiHandler(); + $request = $sapi->requestFromGlobals(); + + $this->assertEquals('PUT', $request->getMethod()); + } } From edc64a225289040333325e83f737f84cb8e8a424 Mon Sep 17 00:00:00 2001 From: pfk84 Date: Mon, 29 Apr 2024 21:09:22 +0200 Subject: [PATCH 2/2] Update SapiHandler.php Reduced override methods to PUT, PATCH & DELETE --- src/Io/SapiHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Io/SapiHandler.php b/src/Io/SapiHandler.php index 9174093..461cd41 100644 --- a/src/Io/SapiHandler.php +++ b/src/Io/SapiHandler.php @@ -94,7 +94,7 @@ public function requestFromGlobals(): ServerRequestInterface // Method override via POST _method "magic" parameter or X-HTTP-Method-Override header, only for POST requests $method_override = strtoupper($_POST["_method"] ?? $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ?? ""); - if ($request->getMethod() === "POST" && in_array($method_override, ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", "TRACE", "CONNECT"], true)) { + if ($request->getMethod() === "POST" && in_array($method_override, ["PUT", "PATCH", "DELETE"], true)) { $request = $request->withMethod($method_override); }