From 88c89d0eeffb41ea92cad945f04a1f5c2ceebea5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 10:10:37 +0900 Subject: [PATCH 01/24] refactor!: remove $upper functionality in Request::getMethod() --- app/Config/Feature.php | 13 +++++++++ system/CodeIgniter.php | 4 +-- system/Filters/Filters.php | 7 +++-- system/HTTP/CLIRequest.php | 2 +- system/HTTP/CURLRequest.php | 29 +++++-------------- system/HTTP/IncomingRequest.php | 2 +- system/HTTP/OutgoingRequest.php | 10 +++---- system/HTTP/OutgoingRequestInterface.php | 9 ++---- system/HTTP/Request.php | 14 --------- tests/system/CodeIgniterTest.php | 4 +-- tests/system/HTTP/CLIRequestTest.php | 3 +- .../HTTP/CURLRequestDoNotShareOptionsTest.php | 26 ++++++++--------- tests/system/HTTP/CURLRequestTest.php | 26 ++++++++--------- tests/system/HTTP/IncomingRequestTest.php | 2 +- tests/system/HTTP/RequestTest.php | 3 +- tests/system/Test/ControllerTestTraitTest.php | 2 +- tests/system/Validation/ValidationTest.php | 14 ++++----- 17 files changed, 76 insertions(+), 94 deletions(-) diff --git a/app/Config/Feature.php b/app/Config/Feature.php index 39a37676183c..c8f2cafcccd0 100644 --- a/app/Config/Feature.php +++ b/app/Config/Feature.php @@ -18,4 +18,17 @@ class Feature extends BaseConfig * Use filter execution order in 4.4 or before. */ public bool $oldFilterOrder = false; + + /** + * Use lowercase HTTP method names like "get", "post" in Config\Filters::$methods. + * + * But the HTTP method is case-sensitive. So using lowercase is wrong. + * We should disable this and use uppercase names like "GET", "POST", etc. + * + * The method token is case-sensitive because it might be used as a gateway + * to object-based systems with case-sensitive method names. By convention, + * standardized methods are defined in all-uppercase US-ASCII letters. + * https://www.rfc-editor.org/rfc/rfc9110#name-overview + */ + public bool $lowerCaseFilterMethods = true; } diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 68cb5a9f5497..3eecebfbed31 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -1027,7 +1027,7 @@ public function storePreviousURL($uri) public function spoofRequestMethod() { // Only works with POSTED forms - if (strtolower($this->request->getMethod()) !== 'post') { + if ($this->request->getMethod() !== 'POST') { return; } @@ -1038,7 +1038,7 @@ public function spoofRequestMethod() } // Only allows PUT, PATCH, DELETE - if (in_array(strtoupper($method), ['PUT', 'PATCH', 'DELETE'], true)) { + if (in_array($method, ['PUT', 'PATCH', 'DELETE'], true)) { $this->request = $this->request->setMethod($method); } } diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index 8a28aeb0118e..5349d9d5060b 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -494,8 +494,11 @@ protected function processMethods() return; } - // Request method won't be set for CLI-based requests - $method = strtolower($this->request->getMethod()) ?? 'cli'; + $method = $this->request->getMethod(); + + if (config(Feature::class)->lowerCaseFilterMethods) { + $method = strtolower($method); + } if (array_key_exists($method, $this->config->methods)) { if (config(Feature::class)->oldFilterOrder) { diff --git a/system/HTTP/CLIRequest.php b/system/HTTP/CLIRequest.php index 878e8a1d66c6..2b12694d86b9 100644 --- a/system/HTTP/CLIRequest.php +++ b/system/HTTP/CLIRequest.php @@ -56,7 +56,7 @@ class CLIRequest extends Request * * @var string */ - protected $method = 'cli'; + protected $method = 'CLI'; /** * Constructor diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index c8b3b9fe9f92..48605b1e8274 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -130,7 +130,7 @@ public function __construct(App $config, URI $uri, ?ResponseInterface $response * Sends an HTTP request to the specified $url. If this is a relative * URL, it will be merged with $this->baseURI to form a complete URL. * - * @param string $method + * @param string $method HTTP method */ public function request($method, string $url, array $options = []): ResponseInterface { @@ -177,7 +177,7 @@ protected function resetOptions() */ public function get(string $url, array $options = []): ResponseInterface { - return $this->request('get', $url, $options); + return $this->request('GET', $url, $options); } /** @@ -185,7 +185,7 @@ public function get(string $url, array $options = []): ResponseInterface */ public function delete(string $url, array $options = []): ResponseInterface { - return $this->request('delete', $url, $options); + return $this->request('DELETE', $url, $options); } /** @@ -193,7 +193,7 @@ public function delete(string $url, array $options = []): ResponseInterface */ public function head(string $url, array $options = []): ResponseInterface { - return $this->request('head', $url, $options); + return $this->request('HEAD', $url, $options); } /** @@ -201,7 +201,7 @@ public function head(string $url, array $options = []): ResponseInterface */ public function options(string $url, array $options = []): ResponseInterface { - return $this->request('options', $url, $options); + return $this->request('OPTIONS', $url, $options); } /** @@ -209,7 +209,7 @@ public function options(string $url, array $options = []): ResponseInterface */ public function patch(string $url, array $options = []): ResponseInterface { - return $this->request('patch', $url, $options); + return $this->request('PATCH', $url, $options); } /** @@ -217,7 +217,7 @@ public function patch(string $url, array $options = []): ResponseInterface */ public function post(string $url, array $options = []): ResponseInterface { - return $this->request('post', $url, $options); + return $this->request('POST', $url, $options); } /** @@ -225,7 +225,7 @@ public function post(string $url, array $options = []): ResponseInterface */ public function put(string $url, array $options = []): ResponseInterface { - return $this->request('put', $url, $options); + return $this->request('PUT', $url, $options); } /** @@ -339,17 +339,6 @@ protected function prepareURL(string $url): string ); } - /** - * Get the request method. Overrides the Request class' method - * since users expect a different answer here. - * - * @param bool|false $upper Whether to return in upper or lower case. - */ - public function getMethod(bool $upper = false): string - { - return ($upper) ? strtoupper($this->method) : strtolower($this->method); - } - /** * Fires the actual cURL request. * @@ -446,8 +435,6 @@ protected function applyRequestHeaders(array $curlOptions = []): array */ protected function applyMethod(string $method, array $curlOptions): array { - $method = strtoupper($method); - $this->method = $method; $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index e9365f79a85f..1144fe91f536 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -406,7 +406,7 @@ public function is(string $type): bool $httpMethods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'PATCH', 'OPTIONS']; if (in_array($valueUpper, $httpMethods, true)) { - return strtoupper($this->getMethod()) === $valueUpper; + return $this->getMethod() === $valueUpper; } if ($valueUpper === 'JSON') { diff --git a/system/HTTP/OutgoingRequest.php b/system/HTTP/OutgoingRequest.php index 698cde263bc1..5738b1aea2e7 100644 --- a/system/HTTP/OutgoingRequest.php +++ b/system/HTTP/OutgoingRequest.php @@ -66,15 +66,13 @@ private function getHostFromUri(URI $uri): string } /** - * Get the request method. + * Retrieves the HTTP method of the request. * - * @param bool $upper Whether to return in upper or lower case. - * - * @deprecated The $upper functionality will be removed and this will revert to its PSR-7 equivalent + * @return string Returns the request method. */ - public function getMethod(bool $upper = false): string + public function getMethod(): string { - return ($upper) ? strtoupper($this->method) : strtolower($this->method); + return $this->method; } /** diff --git a/system/HTTP/OutgoingRequestInterface.php b/system/HTTP/OutgoingRequestInterface.php index 3839b64fd8e1..b4a62dfde73f 100644 --- a/system/HTTP/OutgoingRequestInterface.php +++ b/system/HTTP/OutgoingRequestInterface.php @@ -21,14 +21,11 @@ interface OutgoingRequestInterface extends MessageInterface { /** - * Get the request method. - * An extension of PSR-7's getMethod to allow casing. + * Retrieves the HTTP method of the request. * - * @param bool $upper Whether to return in upper or lower case. - * - * @deprecated The $upper functionality will be removed and this will revert to its PSR-7 equivalent + * @return string Returns the request method. */ - public function getMethod(bool $upper = false): string; + public function getMethod(): string; /** * Return an instance with the provided HTTP method. diff --git a/system/HTTP/Request.php b/system/HTTP/Request.php index baf60c0305b6..462cb5731952 100644 --- a/system/HTTP/Request.php +++ b/system/HTTP/Request.php @@ -49,20 +49,6 @@ public function __construct($config = null) // @phpstan-ignore-line } } - /** - * Get the request method. - * - * @param bool $upper Whether to return in upper or lower case. - * - * @deprecated 4.0.5 The $upper functionality will be removed and this will revert to its PSR-7 equivalent - * - * @codeCoverageIgnore - */ - public function getMethod(bool $upper = false): string - { - return ($upper) ? strtoupper($this->method) : strtolower($this->method); - } - /** * Sets the request method. Used when spoofing the request. * diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index 505d1f5e5a7b..948e9c2dcd5d 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -733,7 +733,7 @@ public function testSpoofRequestMethodCanUsePUT(): void $this->codeigniter->run(); ob_get_clean(); - $this->assertSame('put', Services::incomingrequest()->getMethod()); + $this->assertSame('PUT', Services::incomingrequest()->getMethod()); } public function testSpoofRequestMethodCannotUseGET(): void @@ -758,7 +758,7 @@ public function testSpoofRequestMethodCannotUseGET(): void $this->codeigniter->run(); ob_get_clean(); - $this->assertSame('post', Services::incomingrequest()->getMethod()); + $this->assertSame('POST', Services::incomingrequest()->getMethod()); } /** diff --git a/tests/system/HTTP/CLIRequestTest.php b/tests/system/HTTP/CLIRequestTest.php index e15f0fca4f87..3c6293131d70 100644 --- a/tests/system/HTTP/CLIRequestTest.php +++ b/tests/system/HTTP/CLIRequestTest.php @@ -525,8 +525,7 @@ public function testGetIPAddressDefault(): void public function testMethodReturnsRightStuff(): void { // Defaults method to CLI now. - $this->assertSame('cli', $this->request->getMethod()); - $this->assertSame('CLI', $this->request->getMethod(true)); + $this->assertSame('CLI', $this->request->getMethod()); } public function testMethodIsCliReturnsAlwaysTrue(): void diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php index d8e96424dae5..c9710616e2d2 100644 --- a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php +++ b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php @@ -103,7 +103,7 @@ public function testGetSetsCorrectMethod(): void { $this->request->get('http://example.com'); - $this->assertSame('get', $this->request->getMethod()); + $this->assertSame('GET', $this->request->getMethod()); $options = $this->request->curl_options; @@ -115,7 +115,7 @@ public function testDeleteSetsCorrectMethod(): void { $this->request->delete('http://example.com'); - $this->assertSame('delete', $this->request->getMethod()); + $this->assertSame('DELETE', $this->request->getMethod()); $options = $this->request->curl_options; @@ -127,7 +127,7 @@ public function testHeadSetsCorrectMethod(): void { $this->request->head('http://example.com'); - $this->assertSame('head', $this->request->getMethod()); + $this->assertSame('HEAD', $this->request->getMethod()); $options = $this->request->curl_options; @@ -139,7 +139,7 @@ public function testOptionsSetsCorrectMethod(): void { $this->request->options('http://example.com'); - $this->assertSame('options', $this->request->getMethod()); + $this->assertSame('OPTIONS', $this->request->getMethod()); $options = $this->request->curl_options; @@ -281,7 +281,7 @@ public function testPatchSetsCorrectMethod(): void { $this->request->patch('http://example.com'); - $this->assertSame('patch', $this->request->getMethod()); + $this->assertSame('PATCH', $this->request->getMethod()); $options = $this->request->curl_options; @@ -293,7 +293,7 @@ public function testPostSetsCorrectMethod(): void { $this->request->post('http://example.com'); - $this->assertSame('post', $this->request->getMethod()); + $this->assertSame('POST', $this->request->getMethod()); $options = $this->request->curl_options; @@ -305,7 +305,7 @@ public function testPutSetsCorrectMethod(): void { $this->request->put('http://example.com'); - $this->assertSame('put', $this->request->getMethod()); + $this->assertSame('PUT', $this->request->getMethod()); $options = $this->request->curl_options; @@ -322,19 +322,19 @@ public function testCustomMethodSetsCorrectMethod(): void $options = $this->request->curl_options; $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('CUSTOM', $options[CURLOPT_CUSTOMREQUEST]); + $this->assertSame('custom', $options[CURLOPT_CUSTOMREQUEST]); } public function testRequestMethodGetsSanitized(): void { $this->request->request('', 'http://example.com'); - $this->assertSame('custom', $this->request->getMethod()); + $this->assertSame('Custom', $this->request->getMethod()); $options = $this->request->curl_options; $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('CUSTOM', $options[CURLOPT_CUSTOMREQUEST]); + $this->assertSame('Custom', $options[CURLOPT_CUSTOMREQUEST]); } public function testRequestSetsBasicCurlOptions(): void @@ -951,7 +951,7 @@ public function testPostFormEncoded(): void 'form_params' => $params, ]); - $this->assertSame('post', $this->request->getMethod()); + $this->assertSame('POST', $this->request->getMethod()); $options = $this->request->curl_options; @@ -974,7 +974,7 @@ public function testPostFormMultipart(): void 'multipart' => $params, ]); - $this->assertSame('post', $this->request->getMethod()); + $this->assertSame('POST', $this->request->getMethod()); $options = $this->request->curl_options; @@ -1022,7 +1022,7 @@ public function testJSONData(): void 'json' => $params, ]); - $this->assertSame('post', $this->request->getMethod()); + $this->assertSame('POST', $this->request->getMethod()); $expected = json_encode($params); $this->assertSame( diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index 186284da6ba6..2ca18aa87282 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -103,7 +103,7 @@ public function testGetSetsCorrectMethod(): void { $this->request->get('http://example.com'); - $this->assertSame('get', $this->request->getMethod()); + $this->assertSame('GET', $this->request->getMethod()); $options = $this->request->curl_options; @@ -115,7 +115,7 @@ public function testDeleteSetsCorrectMethod(): void { $this->request->delete('http://example.com'); - $this->assertSame('delete', $this->request->getMethod()); + $this->assertSame('DELETE', $this->request->getMethod()); $options = $this->request->curl_options; @@ -127,7 +127,7 @@ public function testHeadSetsCorrectMethod(): void { $this->request->head('http://example.com'); - $this->assertSame('head', $this->request->getMethod()); + $this->assertSame('HEAD', $this->request->getMethod()); $options = $this->request->curl_options; @@ -139,7 +139,7 @@ public function testOptionsSetsCorrectMethod(): void { $this->request->options('http://example.com'); - $this->assertSame('options', $this->request->getMethod()); + $this->assertSame('OPTIONS', $this->request->getMethod()); $options = $this->request->curl_options; @@ -264,7 +264,7 @@ public function testPatchSetsCorrectMethod(): void { $this->request->patch('http://example.com'); - $this->assertSame('patch', $this->request->getMethod()); + $this->assertSame('PATCH', $this->request->getMethod()); $options = $this->request->curl_options; @@ -276,7 +276,7 @@ public function testPostSetsCorrectMethod(): void { $this->request->post('http://example.com'); - $this->assertSame('post', $this->request->getMethod()); + $this->assertSame('POST', $this->request->getMethod()); $options = $this->request->curl_options; @@ -288,7 +288,7 @@ public function testPutSetsCorrectMethod(): void { $this->request->put('http://example.com'); - $this->assertSame('put', $this->request->getMethod()); + $this->assertSame('PUT', $this->request->getMethod()); $options = $this->request->curl_options; @@ -305,19 +305,19 @@ public function testCustomMethodSetsCorrectMethod(): void $options = $this->request->curl_options; $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('CUSTOM', $options[CURLOPT_CUSTOMREQUEST]); + $this->assertSame('custom', $options[CURLOPT_CUSTOMREQUEST]); } public function testRequestMethodGetsSanitized(): void { $this->request->request('', 'http://example.com'); - $this->assertSame('custom', $this->request->getMethod()); + $this->assertSame('Custom', $this->request->getMethod()); $options = $this->request->curl_options; $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('CUSTOM', $options[CURLOPT_CUSTOMREQUEST]); + $this->assertSame('Custom', $options[CURLOPT_CUSTOMREQUEST]); } public function testRequestSetsBasicCurlOptions(): void @@ -934,7 +934,7 @@ public function testPostFormEncoded(): void 'form_params' => $params, ]); - $this->assertSame('post', $this->request->getMethod()); + $this->assertSame('POST', $this->request->getMethod()); $options = $this->request->curl_options; @@ -957,7 +957,7 @@ public function testPostFormMultipart(): void 'multipart' => $params, ]); - $this->assertSame('post', $this->request->getMethod()); + $this->assertSame('POST', $this->request->getMethod()); $options = $this->request->curl_options; @@ -1005,7 +1005,7 @@ public function testJSONData(): void 'json' => $params, ]); - $this->assertSame('post', $this->request->getMethod()); + $this->assertSame('POST', $this->request->getMethod()); $expected = json_encode($params); $this->assertSame($expected, $this->request->getBody()); diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index b8d0680a19ae..dc537093632e 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -840,7 +840,7 @@ public function testGetFile(): void public function testSpoofing(): void { $this->request->setMethod('WINK'); - $this->assertSame('wink', $this->request->getMethod()); + $this->assertSame('WINK', $this->request->getMethod()); } /** diff --git a/tests/system/HTTP/RequestTest.php b/tests/system/HTTP/RequestTest.php index be20b4ff8f5b..269156fc1982 100644 --- a/tests/system/HTTP/RequestTest.php +++ b/tests/system/HTTP/RequestTest.php @@ -639,7 +639,6 @@ public function testGetIPAddressThruProxyOutofSubnet(): void public function testMethodReturnsRightStuff(): void { // Defaults method to GET now. - $this->assertSame('get', $this->request->getMethod()); - $this->assertSame('GET', $this->request->getMethod(true)); + $this->assertSame('GET', $this->request->getMethod()); } } diff --git a/tests/system/Test/ControllerTestTraitTest.php b/tests/system/Test/ControllerTestTraitTest.php index ab45c6372d41..ac470ce3ce56 100644 --- a/tests/system/Test/ControllerTestTraitTest.php +++ b/tests/system/Test/ControllerTestTraitTest.php @@ -150,7 +150,7 @@ public function testRequestPassthrough(): void ->execute('popper'); $req = $result->request(); - $this->assertSame('get', $req->getMethod()); + $this->assertSame('GET', $req->getMethod()); } public function testFailureResponse(): void diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 780faece2751..28bee306ab88 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -849,7 +849,7 @@ public function testRawInput(): void $rules = [ 'role' => 'required|min_length[5]', ]; - $result = $this->validation->withRequest($request->withMethod('patch'))->setRules($rules)->run(); + $result = $this->validation->withRequest($request->withMethod('PATCH'))->setRules($rules)->run(); $this->assertTrue($result); $this->assertSame([], $this->validation->getErrors()); @@ -874,7 +874,7 @@ public function testJsonInput(): void 'role' => 'required|min_length[5]', ]; $result = $this->validation - ->withRequest($request->withMethod('patch')) + ->withRequest($request->withMethod('PATCH')) ->setRules($rules) ->run(); @@ -930,7 +930,7 @@ public function testJsonInputObjectArray(): void 'p' => 'required|array_count[2]', ]; $result = $this->validation - ->withRequest($request->withMethod('patch')) + ->withRequest($request->withMethod('PATCH')) ->setRules($rules) ->run(); @@ -1113,7 +1113,7 @@ public function testRulesForArrayField(array $body, array $rules, array $results $request = new IncomingRequest($config, new SiteURI($config), http_build_query($body), new UserAgent()); $this->validation->setRules($rules); - $this->validation->withRequest($request->withMethod('post'))->run($body); + $this->validation->withRequest($request->withMethod('POST'))->run($body); $this->assertSame($results, $this->validation->getErrors()); } @@ -1196,7 +1196,7 @@ public function testRulesForSingleRuleWithAsteriskWillReturnNoError(): void 'name_user.*' => 'alpha_numeric', ]); - $this->validation->withRequest($request->withMethod('post'))->run(); + $this->validation->withRequest($request->withMethod('POST'))->run(); $this->assertSame([], $this->validation->getErrors()); } @@ -1231,7 +1231,7 @@ public function testRulesForSingleRuleWithAsteriskWillReturnError(): void 'contacts.friends.*.name' => 'required', ]); - $this->validation->withRequest($request->withMethod('post'))->run(); + $this->validation->withRequest($request->withMethod('POST'))->run(); $this->assertSame([ 'id_user.0' => 'The id_user.* field must contain only numbers.', 'name_user.0' => 'The name_user.* field may only contain alphabetical characters.', @@ -1265,7 +1265,7 @@ public function testRulesForSingleRuleWithSingleValue(): void 'id_user' => 'numeric', ]); - $this->validation->withRequest($request->withMethod('post'))->run(); + $this->validation->withRequest($request->withMethod('POST'))->run(); $this->assertSame([ 'id_user' => 'The id_user field must contain only numbers.', ], $this->validation->getErrors()); From 5bd6cbbceb854508385ae2950c0a57e152435d08 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 10:12:43 +0900 Subject: [PATCH 02/24] refactor: remove strtoupper()/strtolower() for $request->getMethod() --- app/Views/errors/html/error_exception.php | 2 +- system/Debug/Exceptions.php | 2 +- system/Debug/Toolbar.php | 2 +- system/Security/Security.php | 2 +- system/Validation/Validation.php | 2 +- tests/system/HTTP/OutgoingRequestTest.php | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php index 1c094d728872..d27d52fdc576 100644 --- a/app/Views/errors/html/error_exception.php +++ b/app/Views/errors/html/error_exception.php @@ -205,7 +205,7 @@ HTTP Method - getMethod())) ?> + getMethod()) ?> IP Address diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index 0f66f060f349..12c1930279e2 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -128,7 +128,7 @@ public function exceptionHandler(Throwable $exception) if ($this->config->log === true && ! in_array($statusCode, $this->config->ignoreCodes, true)) { $uri = $this->request->getPath() === '' ? '/' : $this->request->getPath(); - $routeInfo = '[Method: ' . strtoupper($this->request->getMethod()) . ', Route: ' . $uri . ']'; + $routeInfo = '[Method: ' . $this->request->getMethod() . ', Route: ' . $uri . ']'; log_message('critical', "{message}\n{routeInfo}\nin {exFile} on line {exLine}.\n{trace}", [ 'message' => $exception->getMessage(), diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 4a7a20632fd7..b2d54c5d52cc 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -79,7 +79,7 @@ public function run(float $startTime, float $totalTime, RequestInterface $reques $data = []; // Data items used within the view. $data['url'] = current_url(); - $data['method'] = strtoupper($request->getMethod()); + $data['method'] = $request->getMethod(); $data['isAJAX'] = $request->isAJAX(); $data['startTime'] = $startTime; $data['totalTime'] = $totalTime * 1000; diff --git a/system/Security/Security.php b/system/Security/Security.php index 4ba665639f36..3868b19f8d84 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -280,7 +280,7 @@ public function getCSRFTokenName(): string public function verify(RequestInterface $request) { // Protects POST, PUT, DELETE, PATCH - $method = strtoupper($request->getMethod()); + $method = $request->getMethod(); $methodsToProtect = ['POST', 'PUT', 'DELETE', 'PATCH']; if (! in_array($method, $methodsToProtect, true)) { return $this; diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 747ac66d9bc4..ae4f030907b4 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -501,7 +501,7 @@ public function withRequest(RequestInterface $request): ValidationInterface return $this; } - if (in_array(strtolower($request->getMethod()), ['put', 'patch', 'delete'], true) + if (in_array($request->getMethod(), ['PUT', 'PATCH', 'DELETE'], true) && strpos($request->getHeaderLine('Content-Type'), 'multipart/form-data') === false ) { $this->data = $request->getRawInput(); diff --git a/tests/system/HTTP/OutgoingRequestTest.php b/tests/system/HTTP/OutgoingRequestTest.php index 51b2bab6a3fe..d857297d49ef 100644 --- a/tests/system/HTTP/OutgoingRequestTest.php +++ b/tests/system/HTTP/OutgoingRequestTest.php @@ -44,8 +44,8 @@ public function testWithMethod(): void $newRequest = $request->withMethod('POST'); - $this->assertSame('GET', strtoupper($request->getMethod())); - $this->assertSame('POST', strtoupper($newRequest->getMethod())); + $this->assertSame('GET', $request->getMethod()); + $this->assertSame('POST', $newRequest->getMethod()); } public function testWithUri(): void From 111d73b4e072821e9b3e21596aa902fe59fec5d7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 10:22:07 +0900 Subject: [PATCH 03/24] chore: update phpstan-baseline.php --- phpstan-baseline.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index e584035c7ba1..9c06aa1d95b4 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -1926,11 +1926,6 @@ 'count' => 2, 'path' => __DIR__ . '/system/Filters/Filters.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Expression on left side of \\?\\? is not nullable\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Filters/Filters.php', -]; $ignoreErrors[] = [ 'message' => '#^Only booleans are allowed in a negated boolean, array given\\.$#', 'count' => 1, From 38e0f587ba4e425dc05079e29a7521c13e0c3663 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 10:37:00 +0900 Subject: [PATCH 04/24] docs: add doc comment --- system/HTTP/IncomingRequest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 1144fe91f536..f1f0b740239d 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -396,7 +396,8 @@ public function negotiate(string $type, array $supported, bool $strictMatch = fa /** * Checks this request type. * - * @param string $type HTTP verb or 'json' or 'ajax' + * @param string $type HTTP verb or 'json' or 'ajax'. + * HTTP verb should be case-sensitive, but this is case-insensitive. * @phpstan-param string|'get'|'post'|'put'|'delete'|'head'|'patch'|'options'|'json'|'ajax' $type */ public function is(string $type): bool From 7d866e2511771c7b278fe19dec19ea69499bf83e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 10:53:58 +0900 Subject: [PATCH 05/24] docs: update existing docs --- .../source/incoming/incomingrequest.rst | 19 +++++++++++-------- .../source/incoming/incomingrequest/005.php | 2 +- user_guide_src/source/incoming/request.rst | 8 ++------ .../source/incoming/request/003.php | 4 +--- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index c6db5b28fe4c..83a456196c1e 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -47,7 +47,10 @@ is() .. versionadded:: 4.3.0 -Since v4.3.0, you can use the ``is()`` method. It returns boolean. +Since v4.3.0, you can use the ``is()`` method. It accepts a HTTP method, ``'ajax'``, +or ``'json'``, and returns boolean. + +.. note:: HTTP method should be case-sensitive, but the parameter is case-insensitive. .. literalinclude:: incomingrequest/040.php @@ -58,16 +61,16 @@ You can check the HTTP method that this request represents with the ``getMethod( .. literalinclude:: incomingrequest/005.php -By default, the method is returned as a lower-case string (i.e., ``'get'``, ``'post'``, etc). +The HTTP method is case-sensitive, and by convention, standardized methods are +defined in all-uppercase US-ASCII letters. -.. important:: The functionality to convert the return value to lower case is deprecated. - It will be removed in the future version, and this method will be PSR-7 equivalent. +.. note:: Prior to v4.5.0, by default, the method was returned as a lower-case + string (i.e., ``'get'``, ``'post'``, etc). But it was a bug. -You can get an -uppercase version by wrapping the call in ``strtoupper()``:: +You can get an lowercase version by wrapping the call in ``strtolower()``:: - // Returns 'GET' - $method = strtoupper($request->getMethod()); + // Returns 'get' + $method = strtolower($request->getMethod()); You can also check if the request was made through and HTTPS connection with the ``isSecure()`` method: diff --git a/user_guide_src/source/incoming/incomingrequest/005.php b/user_guide_src/source/incoming/incomingrequest/005.php index 3c93e74b7664..37e6f490ef85 100644 --- a/user_guide_src/source/incoming/incomingrequest/005.php +++ b/user_guide_src/source/incoming/incomingrequest/005.php @@ -1,4 +1,4 @@ getMethod(); diff --git a/user_guide_src/source/incoming/request.rst b/user_guide_src/source/incoming/request.rst index d15da89ec14e..545c42f7e019 100644 --- a/user_guide_src/source/incoming/request.rst +++ b/user_guide_src/source/incoming/request.rst @@ -57,16 +57,12 @@ Class Reference Accepts an optional second string parameter of ``ipv4`` or ``ipv6`` to specify an IP format. The default checks for both formats. - .. php:method:: getMethod([$upper = false]) + .. php:method:: getMethod() - .. important:: Use of the ``$upper`` parameter is deprecated. It will be removed in future releases. - - :param bool $upper: Whether to return the request method name in upper or lower case :returns: HTTP request method :rtype: string - Returns the ``$_SERVER['REQUEST_METHOD']``, with the option to set it - in uppercase or lowercase. + Returns the ``$_SERVER['REQUEST_METHOD']``. .. literalinclude:: request/003.php diff --git a/user_guide_src/source/incoming/request/003.php b/user_guide_src/source/incoming/request/003.php index 4b0b537b801f..d448962cb55a 100644 --- a/user_guide_src/source/incoming/request/003.php +++ b/user_guide_src/source/incoming/request/003.php @@ -1,5 +1,3 @@ getMethod(true); // Outputs: POST -echo $request->getMethod(false); // Outputs: post -echo $request->getMethod(); // Outputs: post +echo $request->getMethod(); // Outputs: POST From aca22d1645c240361cb1dd4d53bb9c5455452b37 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 11:06:33 +0900 Subject: [PATCH 06/24] refactor: remove feature flag --- app/Config/Feature.php | 13 ------------- system/Filters/Filters.php | 12 ++++++++++-- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/app/Config/Feature.php b/app/Config/Feature.php index c8f2cafcccd0..39a37676183c 100644 --- a/app/Config/Feature.php +++ b/app/Config/Feature.php @@ -18,17 +18,4 @@ class Feature extends BaseConfig * Use filter execution order in 4.4 or before. */ public bool $oldFilterOrder = false; - - /** - * Use lowercase HTTP method names like "get", "post" in Config\Filters::$methods. - * - * But the HTTP method is case-sensitive. So using lowercase is wrong. - * We should disable this and use uppercase names like "GET", "POST", etc. - * - * The method token is case-sensitive because it might be used as a gateway - * to object-based systems with case-sensitive method names. By convention, - * standardized methods are defined in all-uppercase US-ASCII letters. - * https://www.rfc-editor.org/rfc/rfc9110#name-overview - */ - public bool $lowerCaseFilterMethods = true; } diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index 5349d9d5060b..0a79fee7a593 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -496,11 +496,19 @@ protected function processMethods() $method = $this->request->getMethod(); - if (config(Feature::class)->lowerCaseFilterMethods) { + $found = false; + + if (array_key_exists($method, $this->config->methods)) { + $found = true; + } + // Checks lowercase HTTP method for backward compatibility. + // @TODO remove this in the future. + elseif (array_key_exists(strtolower($method), $this->config->methods)) { + $found = true; $method = strtolower($method); } - if (array_key_exists($method, $this->config->methods)) { + if ($found) { if (config(Feature::class)->oldFilterOrder) { $this->filters['before'] = array_merge($this->filters['before'], $this->config->methods[$method]); } else { From 0b6a273f754f20ff6afee45bce4f3d16820dc6c4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 11:15:05 +0900 Subject: [PATCH 07/24] docs: change Filters::$methods keys to uppercase --- app/Config/Filters.php | 2 +- user_guide_src/source/incoming/filters/008.php | 4 ++-- user_guide_src/source/installation/upgrade_415/001.php | 4 ++-- user_guide_src/source/libraries/security/009.php | 4 ++-- user_guide_src/source/libraries/throttler/004.php | 2 +- user_guide_src/source/tutorial/create_news_items/001.php | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/Config/Filters.php b/app/Config/Filters.php index ac37b414c45c..6ebe0f3100ac 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -50,7 +50,7 @@ class Filters extends BaseConfig * particular HTTP method (GET, POST, etc.). * * Example: - * 'post' => ['foo', 'bar'] + * 'POST' => ['foo', 'bar'] * * If you use this, you should disable auto-routing because auto-routing * permits any HTTP method to access a controller. Accessing the controller diff --git a/user_guide_src/source/incoming/filters/008.php b/user_guide_src/source/incoming/filters/008.php index 8d417fd436aa..7538a199394a 100644 --- a/user_guide_src/source/incoming/filters/008.php +++ b/user_guide_src/source/incoming/filters/008.php @@ -9,8 +9,8 @@ class Filters extends BaseConfig // ... public array $methods = [ - 'post' => ['invalidchars', 'csrf'], - 'get' => ['csrf'], + 'POST' => ['invalidchars', 'csrf'], + 'GET' => ['csrf'], ]; // ... diff --git a/user_guide_src/source/installation/upgrade_415/001.php b/user_guide_src/source/installation/upgrade_415/001.php index 9d51911e38eb..272f9e2f1fab 100644 --- a/user_guide_src/source/installation/upgrade_415/001.php +++ b/user_guide_src/source/installation/upgrade_415/001.php @@ -9,8 +9,8 @@ class Filters extends BaseConfig // ... public $methods = [ - 'get' => ['csrf'], - 'post' => ['csrf'], + 'GET' => ['csrf'], + 'POST' => ['csrf'], ]; // ... } diff --git a/user_guide_src/source/libraries/security/009.php b/user_guide_src/source/libraries/security/009.php index bd6bc93cfeb6..fb9d114b026e 100644 --- a/user_guide_src/source/libraries/security/009.php +++ b/user_guide_src/source/libraries/security/009.php @@ -7,8 +7,8 @@ class Filters extends BaseConfig { public $methods = [ - 'get' => ['csrf'], - 'post' => ['csrf'], + 'GET' => ['csrf'], + 'POST' => ['csrf'], ]; // ... diff --git a/user_guide_src/source/libraries/throttler/004.php b/user_guide_src/source/libraries/throttler/004.php index ab4d91257f8f..246b034d035e 100644 --- a/user_guide_src/source/libraries/throttler/004.php +++ b/user_guide_src/source/libraries/throttler/004.php @@ -7,7 +7,7 @@ class Filters extends BaseConfig { public $methods = [ - 'post' => ['throttle'], + 'POST' => ['throttle'], ]; // ... diff --git a/user_guide_src/source/tutorial/create_news_items/001.php b/user_guide_src/source/tutorial/create_news_items/001.php index 8c5ce7508349..3fc800af1a22 100644 --- a/user_guide_src/source/tutorial/create_news_items/001.php +++ b/user_guide_src/source/tutorial/create_news_items/001.php @@ -9,7 +9,7 @@ class Filters extends BaseConfig // ... public $methods = [ - 'post' => ['csrf'], + 'POST' => ['csrf'], ]; // ... From f54e4203e7f1d67b42aa0315b93bec7f403181a5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 11:17:13 +0900 Subject: [PATCH 08/24] test: change Filters::$methods keys to uppercase --- tests/system/Filters/FiltersTest.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php index 7faf127f4647..f2412b289aa7 100644 --- a/tests/system/Filters/FiltersTest.php +++ b/tests/system/Filters/FiltersTest.php @@ -89,7 +89,7 @@ public function testProcessMethodDetectsCLI(): void 'aliases' => ['foo' => ''], 'globals' => [], 'methods' => [ - 'cli' => ['foo'], + 'CLI' => ['foo'], ], ]; $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config); @@ -113,7 +113,7 @@ public function testProcessMethodDetectsGetRequests(): void 'aliases' => ['foo' => ''], 'globals' => [], 'methods' => [ - 'get' => ['foo'], + 'GET' => ['foo'], ], ]; $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config); @@ -137,8 +137,8 @@ public function testProcessMethodRespectsMethod(): void ], 'globals' => [], 'methods' => [ - 'post' => ['foo'], - 'get' => ['bar'], + 'POST' => ['foo'], + 'GET' => ['bar'], ], ]; $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config); @@ -162,8 +162,8 @@ public function testProcessMethodIgnoresMethod(): void ], 'globals' => [], 'methods' => [ - 'post' => ['foo'], - 'get' => ['bar'], + 'POST' => ['foo'], + 'GET' => ['bar'], ], ]; $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config); @@ -348,8 +348,8 @@ public function testProcessMethodProcessesCombined(): void ], ], 'methods' => [ - 'post' => ['foo'], - 'get' => ['bar'], + 'POST' => ['foo'], + 'GET' => ['bar'], ], 'filters' => [ 'foof' => [ @@ -391,7 +391,7 @@ public function testProcessMethodProcessesCombinedAfterForToolbar(): void ], ], 'methods' => [ - 'get' => ['bar'], + 'GET' => ['bar'], ], 'filters' => [ 'foof' => [ From d397154fb8100e370a3eeb2238f74fce01ce3184 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 11:46:50 +0900 Subject: [PATCH 09/24] docs: add changelog and upgrade --- user_guide_src/source/changelogs/v4.5.0.rst | 31 +++++++++++-- .../source/installation/upgrade_450.rst | 45 +++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.5.0.rst b/user_guide_src/source/changelogs/v4.5.0.rst index f2440ac5cc92..3649a9e0b100 100644 --- a/user_guide_src/source/changelogs/v4.5.0.rst +++ b/user_guide_src/source/changelogs/v4.5.0.rst @@ -21,6 +21,23 @@ BREAKING Behavior Changes ================ +Lowercase HTTP Method Name +-------------------------- + +For historical reasons, the framework used HTTP method names in lower case like +"get", "post". +But the method token is case-sensitive because it might be used as a gateway +to object-based systems with case-sensitive method names. By convention, +standardized methods are defined in all-uppercase US-ASCII letters. +See https://www.rfc-editor.org/rfc/rfc9110#name-overview. + +Now the framework uses the correct HTTP method names like "GET", "POST". + +- ``Request::getMethod()`` returns uppercase HTTP methods. +- ``CURLRequest::request()`` does not change the accepted HTTP methods to uppercase. + +See :ref:`upgrade-450-lowercase-http-method-name` for details. + Filter Execution Order ---------------------- @@ -118,6 +135,16 @@ Others Removed Deprecated Items ======================== +Request +------- + +- The ``$upper`` parameter in ``getMethod()`` in ``RequestInterface`` and ``Request`` + has been removed. See :ref:`upgrade-450-lowercase-http-method-name`. +- The deprecated ``isValidIP()`` method in ``RequestInterface`` and ``Request`` + has been removed. +- The visibility of the deprecated properties ``$uri`` and ``$config`` in + ``IncomingRequest`` has been changed to protected. + Filters ------- @@ -183,10 +210,6 @@ Spark Commands Others ------ -- **IncomingRequest:** The visibility of the deprecated properties ``$uri`` and - ``$config`` has been changed to protected. -- **RequestInterface:** The deprecated ``isValidIP()`` method has been removed. -- **Request:** The deprecated ``isValidIP()`` method has been removed. - **Config:** The deprecated ``CodeIgniter\Config\Config`` class has been removed. Enhancements diff --git a/user_guide_src/source/installation/upgrade_450.rst b/user_guide_src/source/installation/upgrade_450.rst index 04607dde6489..ae39f2a36b91 100644 --- a/user_guide_src/source/installation/upgrade_450.rst +++ b/user_guide_src/source/installation/upgrade_450.rst @@ -18,6 +18,51 @@ Mandatory File Changes Breaking Changes **************** +.. _upgrade-450-lowercase-http-method-name: + +Lowercase HTTP Method Name +========================== + +For historical reasons, ``Request::getMethod()`` returned HTTP method names in +lower case by default. + +But the method token is case-sensitive because it might be used as a gateway +to object-based systems with case-sensitive method names. By convention, +standardized methods are defined in all-uppercase US-ASCII letters. +See https://www.rfc-editor.org/rfc/rfc9110#name-overview. + +Now the deprecated ``$upper`` parameter in ``Request::getMethod()`` has been +removed, and the ``getMethod()`` returns the as-is HTTP method name. That is, +uppercase like "GET", "POST", and so on. + +If you want lowercase HTTP method names, use PHP's ``strtolower()`` function:: + + strtolower($request->getMethod()) + +And you should use uppercase HTTP method names in your app code. You should update +the keys in ``$methods`` in **app/Config/Filters.php**:: + + public array $methods = [ + 'POST' => ['invalidchars', 'csrf'], + 'GET' => ['csrf'], + ]; + +CURLRequest::request() +---------------------- + +In previous versions, you could pass lowercase HTTP methods to the ``request()`` +method. But this bug has been fixed. + +Now you must pass the correct HTTP method names like "GET", "POST". Otherwise +you would get the error response:: + + $client = \Config\Services::curlrequest(); + $response = $client->request('get', 'https://www.google.com/', [ + 'http_errors' => false, + ]); + $response->getStatusCode(); // In previous versions: 200 + // In this verrsion: 405 + .. _upgrade-450-nested-route-groups-and-options: Nested Route Groups and Options From 905c3d12682575f6092fde5c794393d86585b3da Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 12:03:01 +0900 Subject: [PATCH 10/24] test: fix $routes->match() HTTP verbs --- tests/system/Router/RouteCollectionTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/system/Router/RouteCollectionTest.php b/tests/system/Router/RouteCollectionTest.php index 985326dcf66d..9ebe27c3a8b8 100644 --- a/tests/system/Router/RouteCollectionTest.php +++ b/tests/system/Router/RouteCollectionTest.php @@ -148,7 +148,7 @@ public function testAddWorksWithCurrentHTTPMethods(): void $routes = $this->getCollector(); - $routes->match(['get'], 'home', 'controller'); + $routes->match(['GET'], 'home', 'controller'); $expects = [ 'home' => '\controller', @@ -180,7 +180,7 @@ public function testMatchIgnoresInvalidHTTPMethods(): void $routes = $this->getCollector(); - $routes->match(['put'], 'home', 'controller'); + $routes->match(['PUT'], 'home', 'controller'); $routes = $routes->getRoutes(); @@ -816,12 +816,12 @@ public function testMatchSupportsMultipleMethods(): void $expected = ['here' => '\there']; - $routes->match(['get', 'post'], 'here', 'there'); + $routes->match(['GET', 'POST'], 'here', 'there'); $this->assertSame($expected, $routes->getRoutes()); Services::request()->setMethod('post'); $routes = $this->getCollector(); - $routes->match(['get', 'post'], 'here', 'there'); + $routes->match(['GET', 'POST'], 'here', 'there'); $this->assertSame($expected, $routes->getRoutes()); } From a09e750b967d978a8eeb9ead23e06e60e06bc5a6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 12:10:26 +0900 Subject: [PATCH 11/24] test: fix $request->setMethod() HTTP verbs --- tests/system/Router/RouteCollectionTest.php | 72 ++++++++++----------- tests/system/Router/RouterTest.php | 2 +- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/tests/system/Router/RouteCollectionTest.php b/tests/system/Router/RouteCollectionTest.php index 9ebe27c3a8b8..32989e952d57 100644 --- a/tests/system/Router/RouteCollectionTest.php +++ b/tests/system/Router/RouteCollectionTest.php @@ -144,7 +144,7 @@ public function testAddIgnoresDefaultNamespaceWhenExists(): void public function testAddWorksWithCurrentHTTPMethods(): void { - Services::request()->setMethod('get'); + Services::request()->setMethod('GET'); $routes = $this->getCollector(); @@ -176,7 +176,7 @@ public function testAddWithLeadingSlash(): void public function testMatchIgnoresInvalidHTTPMethods(): void { - Services::request()->setMethod('get'); + Services::request()->setMethod('GET'); $routes = $this->getCollector(); @@ -189,7 +189,7 @@ public function testMatchIgnoresInvalidHTTPMethods(): void public function testAddWorksWithArrayOFHTTPMethods(): void { - Services::request()->setMethod('post'); + Services::request()->setMethod('POST'); $routes = $this->getCollector(); @@ -696,7 +696,7 @@ public function testPresenterScaffoldsCorrectly(): void public function testResourcesWithCustomController(): void { - Services::request()->setMethod('get'); + Services::request()->setMethod('GET'); $routes = $this->getCollector(); $routes->resource('photos', ['controller' => '