From 5f35f88144ac990f9b062d9b313f3b1a6c2bc518 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 11 Apr 2024 17:33:05 +0900 Subject: [PATCH 1/4] test: sync two test cases But not exactly the same. --- .../HTTP/CURLRequestDoNotShareOptionsTest.php | 71 ++++++++++++++++++- tests/system/HTTP/CURLRequestTest.php | 67 +++++++++++++++-- 2 files changed, 132 insertions(+), 6 deletions(-) diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php index 54de1004fb68..7e8afeb6b74b 100644 --- a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php +++ b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php @@ -35,7 +35,7 @@ protected function setUp(): void { parent::setUp(); - Services::reset(); + $this->resetServices(); $this->request = $this->getRequest(); } @@ -552,6 +552,21 @@ public function testSSLVerification(): void $this->assertSame(2, $options[CURLOPT_SSL_VERIFYHOST]); } + public function testNoSSL(): void + { + $this->request->request('get', 'http://example.com', [ + 'verify' => false, + ]); + + $options = $this->request->curl_options; + + $this->assertArrayHasKey(CURLOPT_SSL_VERIFYPEER, $options); + $this->assertFalse($options[CURLOPT_SSL_VERIFYPEER]); + + $this->assertArrayHasKey(CURLOPT_SSL_VERIFYHOST, $options); + $this->assertSame(0, $options[CURLOPT_SSL_VERIFYHOST]); + } + public function testSSLWithBadKey(): void { $file = 'something_obviously_bogus'; @@ -799,6 +814,21 @@ public function testSendContinuedWithManyHeaders(): void $this->assertSame(200, $response->getStatusCode()); } + public function testSendProxied(): void + { + $request = $this->getRequest([ + 'base_uri' => 'http://www.foo.com/api/v1/', + 'delay' => 100, + ]); + + $output = "HTTP/1.1 200 Connection established +Proxy-Agent: Fortinet-Proxy/1.0\x0d\x0a\x0d\x0aHTTP/1.1 200 OK\x0d\x0a\x0d\x0aHi there"; + $request->setOutput($output); + + $response = $request->get('answer'); + $this->assertSame('Hi there', $response->getBody()); + } + /** * See: https://github.com/codeigniter4/CodeIgniter4/issues/7394 */ @@ -1082,7 +1112,6 @@ public function testSetJSON(): void $expected, $this->request->curl_options[CURLOPT_POSTFIELDS] ); - $this->assertSame( 'Content-Type: application/json', $this->request->curl_options[CURLOPT_HTTPHEADER][0] @@ -1113,6 +1142,18 @@ public function testHTTPv11(): void $this->assertSame(CURL_HTTP_VERSION_1_1, $options[CURLOPT_HTTP_VERSION]); } + public function testHTTPv2(): void + { + $this->request->request('POST', '/post', [ + 'version' => 2.0, + ]); + + $options = $this->request->curl_options; + + $this->assertArrayHasKey(CURLOPT_HTTP_VERSION, $options); + $this->assertSame(CURL_HTTP_VERSION_2_0, $options[CURLOPT_HTTP_VERSION]); + } + public function testCookieOption(): void { $holder = SUPPORTPATH . 'HTTP/Files/CookiesHolder.txt'; @@ -1142,6 +1183,32 @@ public function testUserAgentOption(): void $this->assertSame($agent, $options[CURLOPT_USERAGENT]); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/8347 + */ + public function testMultipleHTTP100(): void + { + $jsonBody = '{"name":"John Doe","age":30}'; + + $output = "HTTP/1.1 100 Continue +Mark bundle as not supporting multiuse +HTTP/1.1 100 Continue +Mark bundle as not supporting multiuse +HTTP/1.1 200 OK +Server: Werkzeug/2.2.2 Python/3.7.17 +Date: Sun, 28 Jan 2024 06:05:36 GMT +Content-Type: application/json +Content-Length: 33\r\n\r\n" . $jsonBody; + + $this->request->setOutput($output); + + $response = $this->request->request('GET', 'http://example.com'); + + $this->assertSame($jsonBody, $response->getBody()); + + $this->assertSame(200, $response->getStatusCode()); + } + public function testGetHeaderLineContentType(): void { $output = 'HTTP/2 200 diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index 99c2f65fbac7..6657eb05c6c8 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -29,7 +29,7 @@ */ final class CURLRequestTest extends CIUnitTestCase { - private CURLRequest $request; + private MockCURLRequest $request; protected function setUp(): void { @@ -39,7 +39,7 @@ protected function setUp(): void $this->request = $this->getRequest(); } - protected function getRequest(array $options = []) + protected function getRequest(array $options = []): MockCURLRequest { $uri = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI(); $app = new App(); @@ -205,7 +205,7 @@ public function testOptionsHeadersNotUsingPopulate(): void $this->assertSame('', $request->header('Accept-Encoding')->getValue()); } - public function testOptionsAreSharedBetweenRequests(): void + public function testDefaultOptionsAreSharedBetweenRequests(): void { $options = [ 'form_params' => ['studio' => 1], @@ -868,6 +868,38 @@ public function testResponseHeadersWithMultipleRequests(): void $this->assertSame(200, $response->getStatusCode()); } + public function testResponseHeadersWithMultipleSetCookies(): void + { + $request = $this->getRequest([ + 'base_uri' => 'https://github.com/', + ]); + + $output = "HTTP/2 200 +server: GitHub.com +date: Sat, 11 Nov 2023 02:26:55 GMT +content-type: text/html; charset=utf-8 +set-cookie: _gh_sess=PlRlha1YumlLhLuo5MuNbIWJRO9RRuR%2FHfYsWRh5B0mkalFIZstlAbTmSstl8q%2FAC57IsWMVuFHWQc6L4qDHQJrwhuYVO5ZaigPCUjAStnhh%2FieZQVqIf92Al7vusuzx2o8XH%2Fv6nd9qzMTAWc2%2FkRsl8jxPQYGNaWeuUBY2w3%2FDORSikN4c0vHOyedhU7Xcv3Ryz5xD3DNxK9R8xKNZ6OSXLJ6bjX8iIT6LxvroVIf2HjvowW9cQsq0kN08mS6KtTnH0mD3ANWqsVVWeMzFNA%3D%3D--Jx830Q9Nmkfz9OGA--kEcPtNphvjNMopYqFDxUbw%3D%3D; Path=/; HttpOnly; Secure; SameSite=Lax +set-cookie: _octo=GH1.1.599292127.1699669625; Path=/; Domain=github.com; Expires=Mon, 11 Nov 2024 02:27:05 GMT; Secure; SameSite=Lax +set-cookie: logged_in=no; Path=/; Domain=github.com; Expires=Mon, 11 Nov 2024 02:27:05 GMT; HttpOnly; Secure; SameSite=Lax +accept-ranges: bytes\x0d\x0a\x0d\x0a"; + $request->setOutput($output); + + $response = $request->get('/'); + + $setCookieHeaders = $response->header('set-cookie'); + + $this->assertCount(3, $setCookieHeaders); + $this->assertSame( + 'logged_in=no; Path=/; Domain=github.com; Expires=Mon, 11 Nov 2024 02:27:05 GMT; HttpOnly; Secure; SameSite=Lax', + $setCookieHeaders[2]->getValue() + ); + + $this->assertSame( + '_octo=GH1.1.599292127.1699669625; Path=/; Domain=github.com; Expires=Mon, 11 Nov 2024 02:27:05 GMT; Secure; SameSite=Lax', + $setCookieHeaders[1]->getValueLine() + ); + } + public function testSplitResponse(): void { $request = $this->getRequest([ @@ -1026,6 +1058,10 @@ public function testJSONData(): void $this->assertSame('POST', $this->request->getMethod()); $expected = json_encode($params); + $this->assertSame( + $expected, + $this->request->curl_options[CURLOPT_POSTFIELDS] + ); $this->assertSame($expected, $this->request->getBody()); } @@ -1040,7 +1076,13 @@ public function testSetJSON(): void ]; $this->request->setJSON($params)->post('/post'); - $this->assertSame(json_encode($params), $this->request->getBody()); + $expected = json_encode($params); + $this->assertSame( + $expected, + $this->request->curl_options[CURLOPT_POSTFIELDS] + ); + $this->assertSame($expected, $this->request->getBody()); + $this->assertSame( 'Content-Type: application/json', $this->request->curl_options[CURLOPT_HTTPHEADER][0] @@ -1137,4 +1179,21 @@ public function testMultipleHTTP100(): void $this->assertSame(200, $response->getStatusCode()); } + + public function testGetHeaderLineContentType(): void + { + $output = 'HTTP/2 200 +date: Thu, 11 Apr 2024 07:26:00 GMT +content-type: text/html; charset=UTF-8 +cache-control: no-store, max-age=0, no-cache +server: cloudflare +content-encoding: br +alt-svc: h3=":443"; ma=86400' . "\x0d\x0a\x0d\x0aResponse Body"; + + $this->request->setOutput($output); + + $response = $this->request->request('get', 'http://example.com'); + + $this->assertSame('text/html; charset=UTF-8', $response->getHeaderLine('Content-Type')); + } } From 110798b9f9d40487963a4b1ab02f0e60c35470ec Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 11 Apr 2024 17:42:34 +0900 Subject: [PATCH 2/4] test: replace test class names CURLRequestTest is the main file. --- ...st.php => CURLRequestShareOptionsTest.php} | 42 ++++--------------- tests/system/HTTP/CURLRequestTest.php | 37 ++++++++++++++-- 2 files changed, 41 insertions(+), 38 deletions(-) rename tests/system/HTTP/{CURLRequestDoNotShareOptionsTest.php => CURLRequestShareOptionsTest.php} (97%) diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestShareOptionsTest.php similarity index 97% rename from tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php rename to tests/system/HTTP/CURLRequestShareOptionsTest.php index 7e8afeb6b74b..b4e3cb447967 100644 --- a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php +++ b/tests/system/HTTP/CURLRequestShareOptionsTest.php @@ -23,11 +23,14 @@ use CURLFile; /** + * This test case is for the case where shareOptions is true. + * The shareOptions should be set to false. + * * @internal * * @group Others */ -final class CURLRequestDoNotShareOptionsTest extends CIUnitTestCase +final class CURLRequestShareOptionsTest extends CIUnitTestCase { private MockCURLRequest $request; @@ -45,7 +48,7 @@ protected function getRequest(array $options = []): MockCURLRequest $app = new App(); $config = new ConfigCURLRequest(); - $config->shareOptions = false; + $config->shareOptions = true; Factories::injectMock('config', 'CURLRequest', $config); return new MockCURLRequest(($app), $uri, new Response($app), $options); @@ -226,23 +229,6 @@ public function testDefaultOptionsAreSharedBetweenRequests(): void $this->assertSame('CodeIgniter Framework v4', $request->curl_options[CURLOPT_USERAGENT]); } - public function testHeaderContentLengthNotSharedBetweenRequests(): void - { - $options = [ - 'base_uri' => 'http://www.foo.com/api/v1/', - ]; - $request = $this->getRequest($options); - - $request->post('example', [ - 'form_params' => [ - 'q' => 'keyword', - ], - ]); - $request->get('example'); - - $this->assertNull($request->header('Content-Length')); - } - /** * @backupGlobals enabled */ @@ -960,21 +946,6 @@ public function testApplyBodyByOptions(): void $this->assertSame('name=George', $request->curl_options[CURLOPT_POSTFIELDS]); } - public function testBodyIsResetOnSecondRequest(): void - { - $request = $this->getRequest([ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'delay' => 100, - ]); - $request->setBody('name=George'); - $request->setOutput('Hi there'); - - $request->post('answer'); - $request->post('answer'); - - $this->assertArrayNotHasKey(CURLOPT_POSTFIELDS, $request->curl_options); - } - public function testResponseHeaders(): void { $request = $this->getRequest([ @@ -1094,6 +1065,7 @@ public function testJSONData(): void $expected, $this->request->curl_options[CURLOPT_POSTFIELDS] ); + $this->assertSame($expected, $this->request->getBody()); } public function testSetJSON(): void @@ -1112,6 +1084,8 @@ public function testSetJSON(): void $expected, $this->request->curl_options[CURLOPT_POSTFIELDS] ); + $this->assertSame($expected, $this->request->getBody()); + $this->assertSame( 'Content-Type: application/json', $this->request->curl_options[CURLOPT_HTTPHEADER][0] diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index 6657eb05c6c8..32d6a4dd919d 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -45,7 +45,7 @@ protected function getRequest(array $options = []): MockCURLRequest $app = new App(); $config = new ConfigCURLRequest(); - $config->shareOptions = true; + $config->shareOptions = false; Factories::injectMock('config', 'CURLRequest', $config); return new MockCURLRequest(($app), $uri, new Response($app), $options); @@ -226,6 +226,23 @@ public function testDefaultOptionsAreSharedBetweenRequests(): void $this->assertSame('CodeIgniter Framework v4', $request->curl_options[CURLOPT_USERAGENT]); } + public function testHeaderContentLengthNotSharedBetweenRequests(): void + { + $options = [ + 'base_uri' => 'http://www.foo.com/api/v1/', + ]; + $request = $this->getRequest($options); + + $request->post('example', [ + 'form_params' => [ + 'q' => 'keyword', + ], + ]); + $request->get('example'); + + $this->assertNull($request->header('Content-Length')); + } + /** * @backupGlobals enabled */ @@ -943,6 +960,21 @@ public function testApplyBodyByOptions(): void $this->assertSame('name=George', $request->curl_options[CURLOPT_POSTFIELDS]); } + public function testBodyIsResetOnSecondRequest(): void + { + $request = $this->getRequest([ + 'base_uri' => 'http://www.foo.com/api/v1/', + 'delay' => 100, + ]); + $request->setBody('name=George'); + $request->setOutput('Hi there'); + + $request->post('answer'); + $request->post('answer'); + + $this->assertArrayNotHasKey(CURLOPT_POSTFIELDS, $request->curl_options); + } + public function testResponseHeaders(): void { $request = $this->getRequest([ @@ -1062,7 +1094,6 @@ public function testJSONData(): void $expected, $this->request->curl_options[CURLOPT_POSTFIELDS] ); - $this->assertSame($expected, $this->request->getBody()); } public function testSetJSON(): void @@ -1081,8 +1112,6 @@ public function testSetJSON(): void $expected, $this->request->curl_options[CURLOPT_POSTFIELDS] ); - $this->assertSame($expected, $this->request->getBody()); - $this->assertSame( 'Content-Type: application/json', $this->request->curl_options[CURLOPT_HTTPHEADER][0] From 83be00a72a3d6e052704f0ec174225562179704f Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 11 Apr 2024 17:50:37 +0900 Subject: [PATCH 3/4] test: refactoring with inheritance --- .../HTTP/CURLRequestShareOptionsTest.php | 1144 +---------------- tests/system/HTTP/CURLRequestTest.php | 6 +- 2 files changed, 13 insertions(+), 1137 deletions(-) diff --git a/tests/system/HTTP/CURLRequestShareOptionsTest.php b/tests/system/HTTP/CURLRequestShareOptionsTest.php index b4e3cb447967..bb0216466787 100644 --- a/tests/system/HTTP/CURLRequestShareOptionsTest.php +++ b/tests/system/HTTP/CURLRequestShareOptionsTest.php @@ -14,13 +14,9 @@ namespace CodeIgniter\HTTP; use CodeIgniter\Config\Factories; -use CodeIgniter\Config\Services; -use CodeIgniter\HTTP\Exceptions\HTTPException; -use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockCURLRequest; use Config\App; use Config\CURLRequest as ConfigCURLRequest; -use CURLFile; /** * This test case is for the case where shareOptions is true. @@ -30,18 +26,8 @@ * * @group Others */ -final class CURLRequestShareOptionsTest extends CIUnitTestCase +final class CURLRequestShareOptionsTest extends CURLRequestTest { - private MockCURLRequest $request; - - protected function setUp(): void - { - parent::setUp(); - - $this->resetServices(); - $this->request = $this->getRequest(); - } - protected function getRequest(array $options = []): MockCURLRequest { $uri = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI(); @@ -54,1149 +40,37 @@ protected function getRequest(array $options = []): MockCURLRequest return new MockCURLRequest(($app), $uri, new Response($app), $options); } - /** - * @see https://github.com/codeigniter4/CodeIgniter4/issues/4707 - */ - public function testPrepareURLIgnoresAppConfig(): void - { - config('App')->baseURL = 'http://example.com/fruit/'; - - $request = $this->getRequest(['base_uri' => 'http://example.com/v1/']); - - $method = $this->getPrivateMethodInvoker($request, 'prepareURL'); - - $this->assertSame('http://example.com/v1/bananas', $method('bananas')); - } - - /** - * @see https://github.com/codeigniter4/CodeIgniter4/issues/1029 - */ - public function testGetRemembersBaseURI(): void - { - $request = $this->getRequest(['base_uri' => 'http://www.foo.com/api/v1/']); - - $request->get('products'); - - $options = $request->curl_options; - - $this->assertSame('http://www.foo.com/api/v1/products', $options[CURLOPT_URL]); - } - - /** - * @see https://github.com/codeigniter4/CodeIgniter4/issues/1029 - */ - public function testGetRemembersBaseURIWithHelperMethod(): void - { - $request = Services::curlrequest(['base_uri' => 'http://www.foo.com/api/v1/']); - - $uri = $this->getPrivateProperty($request, 'baseURI'); - $this->assertSame('www.foo.com', $uri->getHost()); - $this->assertSame('/api/v1/', $uri->getPath()); - } - - public function testSendReturnsResponse(): void - { - $output = 'Howdy Stranger.'; - - $response = $this->request->setOutput($output)->send('get', 'http://example.com'); - - $this->assertInstanceOf(Response::class, $response); - $this->assertSame($output, $response->getBody()); - } - - public function testGetSetsCorrectMethod(): void - { - $this->request->get('http://example.com'); - - $this->assertSame('GET', $this->request->getMethod()); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('GET', $options[CURLOPT_CUSTOMREQUEST]); - } - - public function testDeleteSetsCorrectMethod(): void - { - $this->request->delete('http://example.com'); - - $this->assertSame('DELETE', $this->request->getMethod()); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('DELETE', $options[CURLOPT_CUSTOMREQUEST]); - } - - public function testHeadSetsCorrectMethod(): void - { - $this->request->head('http://example.com'); - - $this->assertSame('HEAD', $this->request->getMethod()); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('HEAD', $options[CURLOPT_CUSTOMREQUEST]); - } - - public function testOptionsSetsCorrectMethod(): void - { - $this->request->options('http://example.com'); - - $this->assertSame('OPTIONS', $this->request->getMethod()); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('OPTIONS', $options[CURLOPT_CUSTOMREQUEST]); - } - - public function testOptionsBaseURIOption(): void - { - $options = ['base_uri' => 'http://www.foo.com/api/v1/']; - $request = $this->getRequest($options); - - $this->assertSame('http://www.foo.com/api/v1/', $request->getBaseURI()->__toString()); - } - - public function testOptionsBaseURIOverride(): void - { - $options = [ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'baseURI' => 'http://bogus/com', - ]; - $request = $this->getRequest($options); - - $this->assertSame('http://bogus/com', $request->getBaseURI()->__toString()); - } - - public function testOptionsHeaders(): void - { - $options = [ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'headers' => ['fruit' => 'apple'], - ]; - $request = $this->getRequest(); - $this->assertNull($request->header('fruit')); - - $request = $this->getRequest($options); - $this->assertSame('apple', $request->header('fruit')->getValue()); - } - - /** - * @backupGlobals enabled - */ - public function testOptionsHeadersNotUsingPopulate(): void + public function testHeaderContentLengthNotSharedBetweenRequests(): void { - $_SERVER['HTTP_HOST'] = 'site1.com'; - $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en-US'; - $_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip, deflate, br'; - $options = [ 'base_uri' => 'http://www.foo.com/api/v1/', - 'headers' => [ - 'Host' => 'www.foo.com', - 'Accept-Encoding' => '', - ], ]; $request = $this->getRequest($options); - $request->get('example'); - // if headers for the request are defined we use them - $this->assertNull($request->header('Accept-Language')); - $this->assertSame('www.foo.com', $request->header('Host')->getValue()); - $this->assertSame('', $request->header('Accept-Encoding')->getValue()); - } - public function testDefaultOptionsAreSharedBetweenRequests(): void - { - $options = [ - 'form_params' => ['studio' => 1], - 'user_agent' => 'CodeIgniter Framework v4', - ]; - $request = $this->getRequest($options); - - $request->request('POST', 'https://realestate1.example.com'); - - $this->assertSame('https://realestate1.example.com', $request->curl_options[CURLOPT_URL]); - $this->assertSame('studio=1', $request->curl_options[CURLOPT_POSTFIELDS]); - $this->assertSame('CodeIgniter Framework v4', $request->curl_options[CURLOPT_USERAGENT]); - - $request->request('POST', 'https://realestate2.example.com'); - - $this->assertSame('https://realestate2.example.com', $request->curl_options[CURLOPT_URL]); - $this->assertSame('studio=1', $request->curl_options[CURLOPT_POSTFIELDS]); - $this->assertSame('CodeIgniter Framework v4', $request->curl_options[CURLOPT_USERAGENT]); - } - - /** - * @backupGlobals enabled - */ - public function testHeaderContentLengthNotSharedBetweenClients(): void - { - $_SERVER['HTTP_CONTENT_LENGTH'] = '10'; - - $options = [ - 'base_uri' => 'http://www.foo.com/api/v1/', - ]; - $request = $this->getRequest($options); $request->post('example', [ 'form_params' => [ 'q' => 'keyword', ], ]); - - $request = $this->getRequest($options); $request->get('example'); - $this->assertNull($request->header('Content-Length')); - } - - public function testOptionsDelay(): void - { - $request = $this->getRequest(); - $this->assertEqualsWithDelta(0.0, $request->getDelay(), PHP_FLOAT_EPSILON); - - $options = [ - 'delay' => 2000, - 'headers' => ['fruit' => 'apple'], - ]; - $request = $this->getRequest($options); - $this->assertEqualsWithDelta(2.0, $request->getDelay(), PHP_FLOAT_EPSILON); - } - - public function testPatchSetsCorrectMethod(): void - { - $this->request->patch('http://example.com'); - - $this->assertSame('PATCH', $this->request->getMethod()); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('PATCH', $options[CURLOPT_CUSTOMREQUEST]); - } - - public function testPostSetsCorrectMethod(): void - { - $this->request->post('http://example.com'); - - $this->assertSame('POST', $this->request->getMethod()); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('POST', $options[CURLOPT_CUSTOMREQUEST]); - } - - public function testPutSetsCorrectMethod(): void - { - $this->request->put('http://example.com'); - - $this->assertSame('PUT', $this->request->getMethod()); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('PUT', $options[CURLOPT_CUSTOMREQUEST]); - } - - public function testCustomMethodSetsCorrectMethod(): void - { - $this->request->request('custom', 'http://example.com'); - - $this->assertSame('custom', $this->request->getMethod()); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('custom', $options[CURLOPT_CUSTOMREQUEST]); + // The Content-Length header is shared! + $this->assertSame('9', $request->header('Content-Length')->getValue()); } - public function testRequestMethodGetsSanitized(): void - { - $this->request->request('', 'http://example.com'); - - $this->assertSame('Custom', $this->request->getMethod()); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options); - $this->assertSame('Custom', $options[CURLOPT_CUSTOMREQUEST]); - } - - public function testRequestSetsBasicCurlOptions(): void - { - $this->request->request('get', 'http://example.com'); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_URL, $options); - $this->assertSame('http://example.com', $options[CURLOPT_URL]); - - $this->assertArrayHasKey(CURLOPT_RETURNTRANSFER, $options); - $this->assertTrue($options[CURLOPT_RETURNTRANSFER]); - - $this->assertArrayHasKey(CURLOPT_HEADER, $options); - $this->assertTrue($options[CURLOPT_HEADER]); - - $this->assertArrayHasKey(CURLOPT_FRESH_CONNECT, $options); - $this->assertTrue($options[CURLOPT_FRESH_CONNECT]); - - $this->assertArrayHasKey(CURLOPT_TIMEOUT_MS, $options); - $this->assertEqualsWithDelta(0.0, $options[CURLOPT_TIMEOUT_MS], PHP_FLOAT_EPSILON); - - $this->assertArrayHasKey(CURLOPT_CONNECTTIMEOUT_MS, $options); - $this->assertEqualsWithDelta(150000.0, $options[CURLOPT_CONNECTTIMEOUT_MS], PHP_FLOAT_EPSILON); - } - - public function testAuthBasicOption(): void - { - $this->request->request('get', 'http://example.com', [ - 'auth' => [ - 'username', - 'password', - ], - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_USERPWD, $options); - $this->assertSame('username:password', $options[CURLOPT_USERPWD]); - - $this->assertArrayHasKey(CURLOPT_HTTPAUTH, $options); - $this->assertSame(CURLAUTH_BASIC, $options[CURLOPT_HTTPAUTH]); - } - - public function testAuthBasicOptionExplicit(): void - { - $this->request->request('get', 'http://example.com', [ - 'auth' => [ - 'username', - 'password', - 'basic', - ], - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_USERPWD, $options); - $this->assertSame('username:password', $options[CURLOPT_USERPWD]); - - $this->assertArrayHasKey(CURLOPT_HTTPAUTH, $options); - $this->assertSame(CURLAUTH_BASIC, $options[CURLOPT_HTTPAUTH]); - } - - public function testAuthDigestOption(): void - { - $output = "HTTP/1.1 401 Unauthorized -Server: ddos-guard -Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT -WWW-Authenticate: Digest\x0d\x0a\x0d\x0aHTTP/1.1 200 OK -Server: ddos-guard -Connection: keep-alive -Keep-Alive: timeout=60 -Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT -Date: Tue, 07 Jul 2020 15:13:14 GMT -Expires: Thu, 19 Nov 1981 08:52:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Pragma: no-cache -Set-Cookie: PHPSESSID=80pd3hlg38mvjnelpvokp9lad0; path=/ -Content-Type: application/xml; charset=utf-8 -Transfer-Encoding: chunked\x0d\x0a\x0d\x0aUpdate success! config"; - - $this->request->setOutput($output); - - $response = $this->request->request('get', 'http://example.com', [ - 'auth' => [ - 'username', - 'password', - 'digest', - ], - ]); - - $options = $this->request->curl_options; - - $this->assertSame('Update success! config', $response->getBody()); - $this->assertSame(200, $response->getStatusCode()); - - $this->assertArrayHasKey(CURLOPT_USERPWD, $options); - $this->assertSame('username:password', $options[CURLOPT_USERPWD]); - - $this->assertArrayHasKey(CURLOPT_HTTPAUTH, $options); - $this->assertSame(CURLAUTH_DIGEST, $options[CURLOPT_HTTPAUTH]); - } - - public function testSetAuthBasic(): void - { - $this->request->setAuth('username', 'password')->get('http://example.com'); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_USERPWD, $options); - $this->assertSame('username:password', $options[CURLOPT_USERPWD]); - - $this->assertArrayHasKey(CURLOPT_HTTPAUTH, $options); - $this->assertSame(CURLAUTH_BASIC, $options[CURLOPT_HTTPAUTH]); - } - - public function testSetAuthDigest(): void - { - $output = "HTTP/1.1 401 Unauthorized -Server: ddos-guard -Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT -WWW-Authenticate: Digest\x0d\x0a\x0d\x0aHTTP/1.1 200 OK -Server: ddos-guard -Connection: keep-alive -Keep-Alive: timeout=60 -Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT -Date: Tue, 07 Jul 2020 15:13:14 GMT -Expires: Thu, 19 Nov 1981 08:52:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Pragma: no-cache -Set-Cookie: PHPSESSID=80pd3hlg38mvjnelpvokp9lad0; path=/ -Content-Type: application/xml; charset=utf-8 -Transfer-Encoding: chunked\x0d\x0a\x0d\x0aUpdate success! config"; - - $this->request->setOutput($output); - - $response = $this->request->setAuth('username', 'password', 'digest')->get('http://example.com'); - - $options = $this->request->curl_options; - - $this->assertSame('Update success! config', $response->getBody()); - $this->assertSame(200, $response->getStatusCode()); - - $this->assertArrayHasKey(CURLOPT_USERPWD, $options); - $this->assertSame('username:password', $options[CURLOPT_USERPWD]); - - $this->assertArrayHasKey(CURLOPT_HTTPAUTH, $options); - $this->assertSame(CURLAUTH_DIGEST, $options[CURLOPT_HTTPAUTH]); - } - - public function testCertOption(): void - { - $file = __FILE__; - - $this->request->request('get', 'http://example.com', [ - 'cert' => $file, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_SSLCERT, $options); - $this->assertSame($file, $options[CURLOPT_SSLCERT]); - } - - public function testCertOptionWithPassword(): void - { - $file = __FILE__; - - $this->request->request('get', 'http://example.com', [ - 'cert' => [ - $file, - 'password', - ], - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_SSLCERT, $options); - $this->assertSame($file, $options[CURLOPT_SSLCERT]); - - $this->assertArrayHasKey(CURLOPT_SSLCERTPASSWD, $options); - $this->assertSame('password', $options[CURLOPT_SSLCERTPASSWD]); - } - - public function testMissingCertOption(): void - { - $file = 'something_obviously_bogus'; - $this->expectException(HTTPException::class); - - $this->request->request('get', 'http://example.com', [ - 'cert' => $file, - ]); - } - - public function testSSLVerification(): void - { - $file = __FILE__; - - $this->request->request('get', 'http://example.com', [ - 'verify' => $file, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_CAINFO, $options); - $this->assertSame($file, $options[CURLOPT_CAINFO]); - - $this->assertArrayHasKey(CURLOPT_SSL_VERIFYPEER, $options); - $this->assertTrue($options[CURLOPT_SSL_VERIFYPEER]); - - $this->assertArrayHasKey(CURLOPT_SSL_VERIFYHOST, $options); - $this->assertSame(2, $options[CURLOPT_SSL_VERIFYHOST]); - } - - public function testNoSSL(): void - { - $this->request->request('get', 'http://example.com', [ - 'verify' => false, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_SSL_VERIFYPEER, $options); - $this->assertFalse($options[CURLOPT_SSL_VERIFYPEER]); - - $this->assertArrayHasKey(CURLOPT_SSL_VERIFYHOST, $options); - $this->assertSame(0, $options[CURLOPT_SSL_VERIFYHOST]); - } - - public function testSSLWithBadKey(): void - { - $file = 'something_obviously_bogus'; - $this->expectException(HTTPException::class); - - $this->request->request('get', 'http://example.com', [ - 'verify' => $file, - ]); - } - - public function testProxyuOption(): void - { - $this->request->request('get', 'http://example.com', [ - 'proxy' => 'http://localhost:3128', - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_PROXY, $options); - $this->assertSame('http://localhost:3128', $options[CURLOPT_PROXY]); - $this->assertArrayHasKey(CURLOPT_HTTPPROXYTUNNEL, $options); - $this->assertTrue($options[CURLOPT_HTTPPROXYTUNNEL]); - } - - public function testDebugOptionTrue(): void - { - $this->request->request('get', 'http://example.com', [ - 'debug' => true, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_VERBOSE, $options); - $this->assertSame(1, $options[CURLOPT_VERBOSE]); - - $this->assertArrayHasKey(CURLOPT_STDERR, $options); - $this->assertIsResource($options[CURLOPT_STDERR]); - } - - public function testDebugOptionFalse(): void - { - $this->request->request('get', 'http://example.com', [ - 'debug' => false, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayNotHasKey(CURLOPT_VERBOSE, $options); - $this->assertArrayNotHasKey(CURLOPT_STDERR, $options); - } - - public function testDebugOptionFile(): void - { - $file = SUPPORTPATH . 'Files/baker/banana.php'; - - $this->request->request('get', 'http://example.com', [ - 'debug' => $file, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_VERBOSE, $options); - $this->assertSame(1, $options[CURLOPT_VERBOSE]); - - $this->assertArrayHasKey(CURLOPT_STDERR, $options); - $this->assertIsResource($options[CURLOPT_STDERR]); - } - - public function testDecodeContent(): void - { - $this->request->setHeader('Accept-Encoding', 'cobol'); - $this->request->request('get', 'http://example.com', [ - 'decode_content' => true, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_ENCODING, $options); - $this->assertSame('cobol', $options[CURLOPT_ENCODING]); - } - - public function testDecodeContentWithoutAccept(): void - { - // $this->request->setHeader('Accept-Encoding', 'cobol'); - $this->request->request('get', 'http://example.com', [ - 'decode_content' => true, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_ENCODING, $options); - $this->assertSame('', $options[CURLOPT_ENCODING]); - $this->assertArrayHasKey(CURLOPT_HTTPHEADER, $options); - $this->assertSame('Accept-Encoding', $options[CURLOPT_HTTPHEADER]); - } - - public function testAllowRedirectsOptionFalse(): void - { - $this->request->request('get', 'http://example.com', [ - 'allow_redirects' => false, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_FOLLOWLOCATION, $options); - $this->assertSame(0, $options[CURLOPT_FOLLOWLOCATION]); - - $this->assertArrayNotHasKey(CURLOPT_MAXREDIRS, $options); - $this->assertArrayNotHasKey(CURLOPT_REDIR_PROTOCOLS, $options); - } - - public function testAllowRedirectsOptionTrue(): void - { - $this->request->request('get', 'http://example.com', [ - 'allow_redirects' => true, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_FOLLOWLOCATION, $options); - $this->assertSame(1, $options[CURLOPT_FOLLOWLOCATION]); - - $this->assertArrayHasKey(CURLOPT_MAXREDIRS, $options); - $this->assertSame(5, $options[CURLOPT_MAXREDIRS]); - $this->assertArrayHasKey(CURLOPT_REDIR_PROTOCOLS, $options); - $this->assertSame(CURLPROTO_HTTP | CURLPROTO_HTTPS, $options[CURLOPT_REDIR_PROTOCOLS]); - } - - public function testAllowRedirectsOptionDefaults(): void - { - $this->request->request('get', 'http://example.com', [ - 'allow_redirects' => true, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_FOLLOWLOCATION, $options); - $this->assertSame(1, $options[CURLOPT_FOLLOWLOCATION]); - - $this->assertArrayHasKey(CURLOPT_MAXREDIRS, $options); - $this->assertArrayHasKey(CURLOPT_REDIR_PROTOCOLS, $options); - } - - public function testAllowRedirectsArray(): void - { - $this->request->request('get', 'http://example.com', [ - 'allow_redirects' => ['max' => 2], - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_FOLLOWLOCATION, $options); - $this->assertSame(1, $options[CURLOPT_FOLLOWLOCATION]); - - $this->assertArrayHasKey(CURLOPT_MAXREDIRS, $options); - $this->assertSame(2, $options[CURLOPT_MAXREDIRS]); - } - - public function testSendWithQuery(): void - { - $request = $this->getRequest([ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'query' => [ - 'name' => 'Henry', - 'd.t' => 'value', - ], - ]); - - $request->get('products'); - - $options = $request->curl_options; - - $this->assertSame('http://www.foo.com/api/v1/products?name=Henry&d.t=value', $options[CURLOPT_URL]); - } - - public function testSendWithDelay(): void - { - $request = $this->getRequest([ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'delay' => 100, - ]); - - $request->get('products'); - - // we still need to check the code coverage to make sure this was done - $this->assertEqualsWithDelta(0.1, $request->getDelay(), PHP_FLOAT_EPSILON); - } - - public function testSendContinued(): void - { - $request = $this->getRequest([ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'delay' => 100, - ]); - - $request->setOutput("HTTP/1.1 100 Continue\x0d\x0a\x0d\x0aHi there"); - $response = $request->get('answer'); - $this->assertSame('Hi there', $response->getBody()); - } - - /** - * See: https://github.com/codeigniter4/CodeIgniter4/issues/3261 - */ - public function testSendContinuedWithManyHeaders(): void - { - $request = $this->getRequest([ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'delay' => 100, - ]); - - $output = "HTTP/1.1 100 Continue -Server: ddos-guard -Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT\x0d\x0a\x0d\x0aHTTP/1.1 200 OK -Server: ddos-guard -Connection: keep-alive -Keep-Alive: timeout=60 -Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT -Date: Tue, 07 Jul 2020 15:13:14 GMT -Expires: Thu, 19 Nov 1981 08:52:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Pragma: no-cache -Set-Cookie: PHPSESSID=80pd3hlg38mvjnelpvokp9lad0; path=/ -Content-Type: application/xml; charset=utf-8 -Transfer-Encoding: chunked\x0d\x0a\x0d\x0aUpdate success! config"; - $request->setOutput($output); - - $response = $request->get('answer'); - - $this->assertSame('Update success! config', $response->getBody()); - - $responseHeaderKeys = [ - 'Cache-Control', - 'Server', - 'Connection', - 'Keep-Alive', - 'Set-Cookie', - 'Date', - 'Expires', - 'Pragma', - 'Content-Type', - 'Transfer-Encoding', - ]; - $this->assertSame($responseHeaderKeys, array_keys($response->headers())); - - $this->assertSame(200, $response->getStatusCode()); - } - - public function testSendProxied(): void - { - $request = $this->getRequest([ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'delay' => 100, - ]); - - $output = "HTTP/1.1 200 Connection established -Proxy-Agent: Fortinet-Proxy/1.0\x0d\x0a\x0d\x0aHTTP/1.1 200 OK\x0d\x0a\x0d\x0aHi there"; - $request->setOutput($output); - - $response = $request->get('answer'); - $this->assertSame('Hi there', $response->getBody()); - } - - /** - * See: https://github.com/codeigniter4/CodeIgniter4/issues/7394 - */ - public function testResponseHeadersWithMultipleRequests(): void - { - $request = $this->getRequest([ - 'base_uri' => 'http://www.foo.com/api/v1/', - ]); - - $output = "HTTP/2.0 200 OK -Server: ddos-guard -Expires: Thu, 19 Nov 1981 08:52:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Pragma: no-cache -Content-Type: application/xml; charset=utf-8 -Transfer-Encoding: chunked\x0d\x0a\x0d\x0aHello1"; - $request->setOutput($output); - - $response = $request->get('answer1'); - - $this->assertSame('Hello1', $response->getBody()); - - $responseHeaderKeys = [ - 'Cache-Control', - 'Server', - 'Expires', - 'Pragma', - 'Content-Type', - 'Transfer-Encoding', - ]; - $this->assertSame($responseHeaderKeys, array_keys($response->headers())); - - $this->assertSame(200, $response->getStatusCode()); - - $output = "HTTP/2.0 200 OK -Expires: Thu, 19 Nov 1982 08:52:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Content-Type: application/xml; charset=utf-8 -Transfer-Encoding: chunked\x0d\x0a\x0d\x0aHello2"; - $request->setOutput($output); - - $response = $request->get('answer2'); - - $this->assertSame('Hello2', $response->getBody()); - - $responseHeaderKeys = [ - 'Cache-Control', - 'Expires', - 'Content-Type', - 'Transfer-Encoding', - ]; - $this->assertSame($responseHeaderKeys, array_keys($response->headers())); - - $this->assertSame(200, $response->getStatusCode()); - } - - public function testResponseHeadersWithMultipleSetCookies(): void - { - $request = $this->getRequest([ - 'base_uri' => 'https://github.com/', - ]); - - $output = "HTTP/2 200 -server: GitHub.com -date: Sat, 11 Nov 2023 02:26:55 GMT -content-type: text/html; charset=utf-8 -set-cookie: _gh_sess=PlRlha1YumlLhLuo5MuNbIWJRO9RRuR%2FHfYsWRh5B0mkalFIZstlAbTmSstl8q%2FAC57IsWMVuFHWQc6L4qDHQJrwhuYVO5ZaigPCUjAStnhh%2FieZQVqIf92Al7vusuzx2o8XH%2Fv6nd9qzMTAWc2%2FkRsl8jxPQYGNaWeuUBY2w3%2FDORSikN4c0vHOyedhU7Xcv3Ryz5xD3DNxK9R8xKNZ6OSXLJ6bjX8iIT6LxvroVIf2HjvowW9cQsq0kN08mS6KtTnH0mD3ANWqsVVWeMzFNA%3D%3D--Jx830Q9Nmkfz9OGA--kEcPtNphvjNMopYqFDxUbw%3D%3D; Path=/; HttpOnly; Secure; SameSite=Lax -set-cookie: _octo=GH1.1.599292127.1699669625; Path=/; Domain=github.com; Expires=Mon, 11 Nov 2024 02:27:05 GMT; Secure; SameSite=Lax -set-cookie: logged_in=no; Path=/; Domain=github.com; Expires=Mon, 11 Nov 2024 02:27:05 GMT; HttpOnly; Secure; SameSite=Lax -accept-ranges: bytes\x0d\x0a\x0d\x0a"; - $request->setOutput($output); - - $response = $request->get('/'); - - $setCookieHeaders = $response->header('set-cookie'); - - $this->assertCount(3, $setCookieHeaders); - $this->assertSame( - 'logged_in=no; Path=/; Domain=github.com; Expires=Mon, 11 Nov 2024 02:27:05 GMT; HttpOnly; Secure; SameSite=Lax', - $setCookieHeaders[2]->getValue() - ); - - $this->assertSame( - '_octo=GH1.1.599292127.1699669625; Path=/; Domain=github.com; Expires=Mon, 11 Nov 2024 02:27:05 GMT; Secure; SameSite=Lax', - $setCookieHeaders[1]->getValueLine() - ); - } - - public function testSplitResponse(): void - { - $request = $this->getRequest([ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'delay' => 100, - ]); - - $request->setOutput("Accept: text/html\x0d\x0a\x0d\x0aHi there"); - $response = $request->get('answer'); - $this->assertSame('Hi there', $response->getBody()); - } - - public function testApplyBody(): void + public function testBodyIsResetOnSecondRequest(): void { $request = $this->getRequest([ 'base_uri' => 'http://www.foo.com/api/v1/', 'delay' => 100, ]); - $request->setBody('name=George'); $request->setOutput('Hi there'); - $response = $request->post('answer'); - - $this->assertSame('Hi there', $response->getBody()); - $this->assertSame('name=George', $request->curl_options[CURLOPT_POSTFIELDS]); - } - - public function testApplyBodyByOptions(): void - { - $request = $this->getRequest([ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'delay' => 100, - ]); - - $request->setOutput('Hi there'); - $response = $request->post('answer', [ - 'body' => 'name=George', - ]); - - $this->assertSame('Hi there', $response->getBody()); - $this->assertSame('name=George', $request->curl_options[CURLOPT_POSTFIELDS]); - } - - public function testResponseHeaders(): void - { - $request = $this->getRequest([ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'delay' => 100, - ]); - - $request->setOutput("HTTP/2.0 234 Ohoh\x0d\x0aAccept: text/html\x0d\x0a\x0d\x0aHi there"); - $response = $request->get('bogus'); - - $this->assertSame('2.0', $response->getProtocolVersion()); - $this->assertSame(234, $response->getStatusCode()); - } - - public function testResponseHeadersShortProtocol(): void - { - $request = $this->getRequest([ - 'base_uri' => 'http://www.foo.com/api/v1/', - 'delay' => 100, - ]); - - $request->setOutput("HTTP/2 235 Ohoh\x0d\x0aAccept: text/html\x0d\x0a\x0d\x0aHi there shortie"); - $response = $request->get('bogus'); - - $this->assertSame('2.0', $response->getProtocolVersion()); - $this->assertSame(235, $response->getStatusCode()); - } - - public function testPostFormEncoded(): void - { - $params = [ - 'foo' => 'bar', - 'baz' => [ - 'hi', - 'there', - ], - ]; - $this->request->request('POST', '/post', [ - 'form_params' => $params, - ]); - - $this->assertSame('POST', $this->request->getMethod()); - - $options = $this->request->curl_options; - - $expected = http_build_query($params); - $this->assertArrayHasKey(CURLOPT_POSTFIELDS, $options); - $this->assertSame($expected, $options[CURLOPT_POSTFIELDS]); - } - - public function testPostFormMultipart(): void - { - $params = [ - 'foo' => 'bar', - 'baz' => [ - 'hi', - 'there', - ], - 'afile' => new CURLFile(__FILE__), - ]; - $this->request->request('POST', '/post', [ - 'multipart' => $params, - ]); - - $this->assertSame('POST', $this->request->getMethod()); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_POSTFIELDS, $options); - $this->assertSame($params, $options[CURLOPT_POSTFIELDS]); - } - - public function testSetForm(): void - { - $params = [ - 'foo' => 'bar', - 'baz' => [ - 'hi', - 'there', - ], - ]; - - $this->request->setForm($params)->post('/post'); - - $this->assertSame( - http_build_query($params), - $this->request->curl_options[CURLOPT_POSTFIELDS] - ); - - $params['afile'] = new CURLFile(__FILE__); - - $this->request->setForm($params, true)->post('/post'); - - $this->assertSame( - $params, - $this->request->curl_options[CURLOPT_POSTFIELDS] - ); - } - - public function testJSONData(): void - { - $params = [ - 'foo' => 'bar', - 'baz' => [ - 'hi', - 'there', - ], - ]; - $this->request->request('POST', '/post', [ - 'json' => $params, - ]); - - $this->assertSame('POST', $this->request->getMethod()); - - $expected = json_encode($params); - $this->assertSame( - $expected, - $this->request->curl_options[CURLOPT_POSTFIELDS] - ); - $this->assertSame($expected, $this->request->getBody()); - } - - public function testSetJSON(): void - { - $params = [ - 'foo' => 'bar', - 'baz' => [ - 'hi', - 'there', - ], - ]; - $this->request->setJSON($params)->post('/post'); - - $expected = json_encode($params); - $this->assertSame( - $expected, - $this->request->curl_options[CURLOPT_POSTFIELDS] - ); - $this->assertSame($expected, $this->request->getBody()); - - $this->assertSame( - 'Content-Type: application/json', - $this->request->curl_options[CURLOPT_HTTPHEADER][0] - ); - } - - public function testHTTPv1(): void - { - $this->request->request('POST', '/post', [ - 'version' => 1.0, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_HTTP_VERSION, $options); - $this->assertSame(CURL_HTTP_VERSION_1_0, $options[CURLOPT_HTTP_VERSION]); - } - - public function testHTTPv11(): void - { - $this->request->request('POST', '/post', [ - 'version' => 1.1, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_HTTP_VERSION, $options); - $this->assertSame(CURL_HTTP_VERSION_1_1, $options[CURLOPT_HTTP_VERSION]); - } - - public function testHTTPv2(): void - { - $this->request->request('POST', '/post', [ - 'version' => 2.0, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_HTTP_VERSION, $options); - $this->assertSame(CURL_HTTP_VERSION_2_0, $options[CURLOPT_HTTP_VERSION]); - } - - public function testCookieOption(): void - { - $holder = SUPPORTPATH . 'HTTP/Files/CookiesHolder.txt'; - $this->request->request('POST', '/post', [ - 'cookie' => $holder, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_COOKIEJAR, $options); - $this->assertSame($holder, $options[CURLOPT_COOKIEJAR]); - $this->assertArrayHasKey(CURLOPT_COOKIEFILE, $options); - $this->assertSame($holder, $options[CURLOPT_COOKIEFILE]); - } - - public function testUserAgentOption(): void - { - $agent = 'CodeIgniter Framework'; - - $this->request->request('POST', '/post', [ - 'user_agent' => $agent, - ]); - - $options = $this->request->curl_options; - - $this->assertArrayHasKey(CURLOPT_USERAGENT, $options); - $this->assertSame($agent, $options[CURLOPT_USERAGENT]); - } - - /** - * @see https://github.com/codeigniter4/CodeIgniter4/issues/8347 - */ - public function testMultipleHTTP100(): void - { - $jsonBody = '{"name":"John Doe","age":30}'; - - $output = "HTTP/1.1 100 Continue -Mark bundle as not supporting multiuse -HTTP/1.1 100 Continue -Mark bundle as not supporting multiuse -HTTP/1.1 200 OK -Server: Werkzeug/2.2.2 Python/3.7.17 -Date: Sun, 28 Jan 2024 06:05:36 GMT -Content-Type: application/json -Content-Length: 33\r\n\r\n" . $jsonBody; - - $this->request->setOutput($output); - - $response = $this->request->request('GET', 'http://example.com'); - - $this->assertSame($jsonBody, $response->getBody()); - - $this->assertSame(200, $response->getStatusCode()); - } - - public function testGetHeaderLineContentType(): void - { - $output = 'HTTP/2 200 -date: Thu, 11 Apr 2024 07:26:00 GMT -content-type: text/html; charset=UTF-8 -cache-control: no-store, max-age=0, no-cache -server: cloudflare -content-encoding: br -alt-svc: h3=":443"; ma=86400' . "\x0d\x0a\x0d\x0aResponse Body"; - - $this->request->setOutput($output); - $response = $this->request->request('get', 'http://example.com'); + $request->post('answer'); + $request->post('answer'); - $this->assertSame('text/html; charset=UTF-8', $response->getHeaderLine('Content-Type')); + // The body is not reset! + $this->assertArrayHasKey(CURLOPT_POSTFIELDS, $request->curl_options); } } diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index 32d6a4dd919d..722fe1270c02 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -26,10 +26,12 @@ * @internal * * @group Others + * + * @no-final */ -final class CURLRequestTest extends CIUnitTestCase +class CURLRequestTest extends CIUnitTestCase { - private MockCURLRequest $request; + protected MockCURLRequest $request; protected function setUp(): void { From c6c4f812c84afebe8e8dd2344ba2aabfc10130c4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 11 Apr 2024 18:02:04 +0900 Subject: [PATCH 4/4] docs: add array types --- phpstan-baseline.php | 50 --------------------------- system/HTTP/CURLRequest.php | 2 ++ tests/system/HTTP/CURLRequestTest.php | 3 ++ 3 files changed, 5 insertions(+), 50 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 61841f81795a..3da30e816317 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -5336,11 +5336,6 @@ 'count' => 10, 'path' => __DIR__ . '/system/HTTP/CURLRequest.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Method CodeIgniter\\\\HTTP\\\\CURLRequest\\:\\:__construct\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/HTTP/CURLRequest.php', -]; $ignoreErrors[] = [ 'message' => '#^Method CodeIgniter\\\\HTTP\\\\CURLRequest\\:\\:applyBody\\(\\) has parameter \\$curlOptions with no value type specified in iterable type array\\.$#', 'count' => 1, @@ -12901,36 +12896,6 @@ 'count' => 1, 'path' => __DIR__ . '/tests/system/HTTP/CLIRequestTest.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Assigning \'10\' directly on offset \'HTTP_CONTENT_LENGTH\' of \\$_SERVER is discouraged\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Assigning \'en\\-US\' directly on offset \'HTTP_ACCEPT_LANGUAGE\' of \\$_SERVER is discouraged\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Assigning \'gzip, deflate, br\' directly on offset \'HTTP_ACCEPT_ENCODING\' of \\$_SERVER is discouraged\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Assigning \'site1\\.com\' directly on offset \'HTTP_HOST\' of \\$_SERVER is discouraged\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method CodeIgniter\\\\HTTP\\\\CURLRequestDoNotShareOptionsTest\\:\\:getRequest\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Access to an undefined property CodeIgniter\\\\HTTP\\\\CURLRequest\\:\\:\\$curl_options\\.$#', - 'count' => 39, - 'path' => __DIR__ . '/tests/system/HTTP/CURLRequestTest.php', -]; $ignoreErrors[] = [ 'message' => '#^Assigning \'10\' directly on offset \'HTTP_CONTENT_LENGTH\' of \\$_SERVER is discouraged\\.$#', 'count' => 1, @@ -12951,21 +12916,6 @@ 'count' => 1, 'path' => __DIR__ . '/tests/system/HTTP/CURLRequestTest.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Call to an undefined method CodeIgniter\\\\HTTP\\\\CURLRequest\\:\\:setOutput\\(\\)\\.$#', - 'count' => 4, - 'path' => __DIR__ . '/tests/system/HTTP/CURLRequestTest.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method CodeIgniter\\\\HTTP\\\\CURLRequestTest\\:\\:getRequest\\(\\) has no return type specified\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/HTTP/CURLRequestTest.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Method CodeIgniter\\\\HTTP\\\\CURLRequestTest\\:\\:getRequest\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/tests/system/HTTP/CURLRequestTest.php', -]; $ignoreErrors[] = [ 'message' => '#^Method CodeIgniter\\\\HTTP\\\\ContentSecurityPolicyTest\\:\\:work\\(\\) has no return type specified\\.$#', 'count' => 1, diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 3040f29b9feb..4b1c9c625399 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -107,6 +107,8 @@ class CURLRequest extends OutgoingRequest * - baseURI * - timeout * - any other request options to use as defaults. + * + * @param array $options */ public function __construct(App $config, URI $uri, ?ResponseInterface $response = null, array $options = []) { diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index 722fe1270c02..1f53a57a8465 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -41,6 +41,9 @@ protected function setUp(): void $this->request = $this->getRequest(); } + /** + * @param array $options + */ protected function getRequest(array $options = []): MockCURLRequest { $uri = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI();