123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859 |
- <?php
- /**
- * Unit tests for request class
- *
- * @group ko7
- * @group ko7.core
- * @group ko7.core.request
- *
- * @package KO7
- * @category Tests
- *
- * @author BRMatt <matthew@sigswitch.com>
- * @copyright (c) 2007-2016 Kohana Team
- * @copyright (c) since 2016 Koseven Team
- * @license https://koseven.dev/LICENSE
- */
- class KO7_RequestTest extends Unittest_TestCase
- {
- protected $_inital_request;
- // @codingStandardsIgnoreStart
- public function setUp(): void
- // @codingStandardsIgnoreEnd
- {
- parent::setUp();
- KO7::$config->load('url')->set('trusted_hosts', ['localhost']);
- $this->_initial_request = Request::$initial;
- Request::$initial = new Request('/');
- }
- // @codingStandardsIgnoreStart
- public function tearDown(): void
- // @codingStandardsIgnoreEnd
- {
- Request::$initial = $this->_initial_request;
- parent::tearDown();
- }
- public function test_initial()
- {
- $this->setEnvironment([
- 'Request::$initial' => NULL,
- 'Request::$client_ip' => NULL,
- 'Request::$user_agent' => NULL,
- '_SERVER' => [
- 'HTTPS' => NULL,
- 'PATH_INFO' => '/',
- 'HTTP_REFERER' => 'http://example.com/',
- 'HTTP_USER_AGENT' => 'whatever (Mozilla 5.0/compatible)',
- 'REMOTE_ADDR' => '127.0.0.1',
- 'REQUEST_METHOD' => 'GET',
- 'HTTP_X_REQUESTED_WITH' => 'ajax-or-something',
- ],
- '_GET' => [],
- '_POST' => [],
- ]);
- $request = Request::factory();
- $this->assertEquals(Request::$initial, $request);
- $this->assertEquals(Request::$client_ip, '127.0.0.1');
- $this->assertEquals(Request::$user_agent, 'whatever (Mozilla 5.0/compatible)');
- $this->assertEquals($request->protocol(), 'HTTP/1.1');
- $this->assertEquals($request->referrer(), 'http://example.com/');
- $this->assertEquals($request->requested_with(), 'ajax-or-something');
- $this->assertEquals($request->query(), []);
- $this->assertEquals($request->post(), []);
- }
- /**
- * Tests client IP detection
- *
- * @return null
- */
- public function test_client_ips()
- {
- // testing X-Forwarded-For
- $server = [
- 'HTTPS' => NULL,
- 'PATH_INFO' => '/',
- 'REMOTE_ADDR' => '255.255.255.1',
- 'HTTP_X_FORWARDED_FOR' => '127.0.0.2, 255.255.255.1, 255.255.255.2',
- ];
- $this->setEnvironment([
- 'Request::$initial' => NULL,
- 'Request::$client_ip' => NULL,
- 'Request::$trusted_proxies' => ['255.255.255.1'],
- '_SERVER' => $server,
- ]);
- $request = Request::factory();
- $this->assertEquals(Request::$client_ip, '127.0.0.2', 'Header "HTTP_X_FORWARDED_FOR" handled incorrectly');
- // testing Client-IP
- $server['HTTP_CLIENT_IP'] = '127.0.0.3';
- unset($server['HTTP_X_FORWARDED_FOR']);
- $this->setEnvironment([
- 'Request::$initial' => NULL,
- 'Request::$client_ip' => NULL,
- '_SERVER' => $server,
- ]);
- $request = Request::factory();
- $this->assertEquals(Request::$client_ip, '127.0.0.3', 'Header "HTTP_CLIENT_IP" handled incorrectly');
- // testing Cloudflare
- $server['HTTP_CF_CONNECTING_IP'] = '127.0.0.4';
- $this->setEnvironment([
- 'Request::$initial' => NULL,
- 'Request::$client_ip' => NULL,
- '_SERVER' => $server,
- ]);
- $request = Request::factory();
- $this->assertEquals(Request::$client_ip, '127.0.0.4', 'Cloudflare header "HTTP_CF_CONNECTING_IP" handled incorrectly');
- }
- /**
- * Tests that the allow_external flag prevents an external request.
- *
- * @return null
- */
- public function test_disable_external_tests()
- {
- $this->setEnvironment(
- [
- 'Request::$initial' => NULL,
- ]
- );
- $request = new Request('http://www.google.com/', [], FALSE);
- $this->assertEquals(FALSE, $request->is_external());
- }
- /**
- * Provides the data for test_create()
- * @return array
- */
- public function provider_create()
- {
- return [
- ['foo/bar', 'Request_Client_Internal'],
- ['http://google.com', 'Request_Client_External'],
- ];
- }
- /**
- * Ensures the create class is created with the correct client
- *
- * @test
- * @dataProvider provider_create
- */
- public function test_create($uri, $client_class)
- {
- $request = Request::factory($uri);
- $this->assertInstanceOf($client_class, $request->client());
- }
- /**
- * Ensure that parameters can be read
- *
- * @test
- */
- public function test_param()
- {
- $route = new Route('(<controller>(/<action>(/<id>)))');
- $uri = 'ko7_requesttest_dummy/foobar/some_id';
- $request = Request::factory($uri, NULL, TRUE, [$route]);
- // We need to execute the request before it has matched a route
- $response = $request->execute();
- $controller = new Controller_KO7_RequestTest_Dummy($request, $response);
- $this->assertSame(200, $response->status());
- $this->assertSame($controller->get_expected_response(), $response->body());
- $this->assertArrayHasKey('id', $request->param());
- $this->assertArrayNotHasKey('foo', $request->param());
- $this->assertEquals($request->uri(), $uri);
- // Ensure the params do not contain contamination from controller, action, route, uri etc etc
- $params = $request->param();
- // Test for illegal components
- $this->assertArrayNotHasKey('controller', $params);
- $this->assertArrayNotHasKey('action', $params);
- $this->assertArrayNotHasKey('directory', $params);
- $this->assertArrayNotHasKey('uri', $params);
- $this->assertArrayNotHasKey('route', $params);
- $route = new Route('(<uri>)', ['uri' => '.+']);
- $route->defaults(['controller' => 'ko7_requesttest_dummy', 'action' => 'foobar']);
- $request = Request::factory('ko7_requesttest_dummy', NULL, TRUE, [$route]);
- // We need to execute the request before it has matched a route
- $response = $request->execute();
- $controller = new Controller_KO7_RequestTest_Dummy($request, $response);
- $this->assertSame(200, $response->status());
- $this->assertSame($controller->get_expected_response(), $response->body());
- $this->assertSame('ko7_requesttest_dummy', $request->param('uri'));
- }
- /**
- * Tests Request::method()
- *
- * @test
- */
- public function test_method()
- {
- $request = Request::factory('foo/bar');
- $this->assertEquals($request->method(), 'GET');
- $this->assertEquals(($request->method('post') === $request), TRUE);
- $this->assertEquals(($request->method() === 'POST'), TRUE);
- }
- /**
- * Tests Request::route()
- *
- * @test
- */
- public function test_route()
- {
- $request = Request::factory(''); // This should always match something, no matter what changes people make
- // We need to execute the request before it has matched a route
- try
- {
- $request->execute();
- }
- catch (Exception $e) {}
- $this->assertInstanceOf('Route', $request->route());
- }
- /**
- * Tests Request::route()
- *
- * @test
- */
- public function test_route_is_not_set_before_execute()
- {
- $request = Request::factory(''); // This should always match something, no matter what changes people make
- // The route should be NULL since the request has not been executed yet
- $this->assertEquals($request->route(), NULL);
- }
- /**
- * Provides test data for Request::url()
- * @return array
- */
- public function provider_url()
- {
- return [
- [
- 'foo/bar',
- 'http',
- 'http://localhost/ko7/foo/bar'
- ],
- [
- 'foo',
- 'http',
- 'http://localhost/ko7/foo'
- ],
- [
- 'http://www.google.com',
- 'http',
- 'http://www.google.com'
- ],
- [
- '0',
- 'http',
- 'http://localhost/ko7/0'
- ]
- ];
- }
- /**
- * Tests Request::url()
- *
- * @test
- * @dataProvider provider_url
- * @covers Request::url
- * @param string $uri the uri to use
- * @param string $protocol the protocol to use
- * @param array $expected The string we expect
- */
- public function test_url($uri, $protocol, $expected)
- {
- if ( ! isset($_SERVER['argc']))
- {
- $_SERVER['argc'] = 1;
- }
- $this->setEnvironment([
- 'KO7::$base_url' => '/ko7/',
- '_SERVER' => ['HTTP_HOST' => 'localhost', 'argc' => $_SERVER['argc']],
- 'KO7::$index_file' => FALSE,
- ]);
- // issue #3967: inject the route so that we don't conflict with the application's default route
- $route = new Route('(<controller>(/<action>))');
- $route->defaults([
- 'controller' => 'welcome',
- 'action' => 'index',
- ]);
- $this->assertEquals(Request::factory($uri, [], TRUE, [$route])->url($protocol), $expected);
- }
- /**
- * Data provider for test_set_protocol() test
- *
- * @return array
- */
- public function provider_set_protocol()
- {
- return [
- [
- 'http/1.1',
- 'HTTP/1.1',
- ],
- [
- 'ftp',
- 'FTP',
- ],
- [
- 'hTTp/1.0',
- 'HTTP/1.0',
- ],
- ];
- }
- /**
- * Tests the protocol() method
- *
- * @dataProvider provider_set_protocol
- *
- * @return null
- */
- public function test_set_protocol($protocol, $expected)
- {
- $request = Request::factory();
- // Set the supplied protocol
- $result = $request->protocol($protocol);
- // Test the set value
- $this->assertSame($expected, $request->protocol());
- // Test the return value
- $this->assertTrue($request instanceof $result);
- }
- /**
- * Provides data for test_post_max_size_exceeded()
- *
- * @return array
- */
- public function provider_post_max_size_exceeded()
- {
- // Get the post max size
- $post_max_size = Num::bytes(ini_get('post_max_size'));
- return [
- [
- $post_max_size+200000,
- TRUE
- ],
- [
- $post_max_size-20,
- FALSE
- ],
- [
- $post_max_size,
- FALSE
- ]
- ];
- }
- /**
- * Tests the post_max_size_exceeded() method
- *
- * @dataProvider provider_post_max_size_exceeded
- *
- * @param int content_length
- * @param bool expected
- * @return void
- */
- public function test_post_max_size_exceeded($content_length, $expected)
- {
- // Ensure the request method is set to POST
- Request::$initial->method(HTTP_Request::POST);
- // Set the content length
- $_SERVER['CONTENT_LENGTH'] = $content_length;
- // Test the post_max_size_exceeded() method
- $this->assertSame(Request::post_max_size_exceeded(), $expected);
- }
- /**
- * Provides data for test_uri_only_trimed_on_internal()
- *
- * @return array
- */
- public function provider_uri_only_trimed_on_internal()
- {
- // issue #3967: inject the route so that we don't conflict with the application's default route
- $route = new Route('(<controller>(/<action>))');
- $route->defaults([
- 'controller' => 'welcome',
- 'action' => 'index',
- ]);
- $old_request = Request::$initial;
- Request::$initial = new Request(TRUE, [], TRUE, [$route]);
- $result = [
- [
- new Request('http://www.google.com'),
- 'http://www.google.com'
- ],
- [
- new Request('http://www.google.com/'),
- 'http://www.google.com/'
- ],
- [
- new Request('foo/bar/'),
- 'foo/bar'
- ],
- [
- new Request('foo/bar'),
- 'foo/bar'
- ],
- [
- new Request('/0'),
- '0'
- ],
- [
- new Request('0'),
- '0'
- ],
- [
- new Request('/'),
- '/'
- ],
- [
- new Request(''),
- '/'
- ]
- ];
- Request::$initial = $old_request;
- return $result;
- }
- /**
- * Tests that the uri supplied to Request is only trimed
- * for internal requests.
- *
- * @dataProvider provider_uri_only_trimed_on_internal
- *
- * @return void
- */
- public function test_uri_only_trimed_on_internal(Request $request, $expected)
- {
- $this->assertSame($request->uri(), $expected);
- }
- /**
- * Data provider for test_options_set_to_external_client()
- *
- * @return array
- */
- public function provider_options_set_to_external_client()
- {
- $provider = [
- [
- [
- CURLOPT_PROXYPORT => 8080,
- CURLOPT_PROXYTYPE => CURLPROXY_HTTP,
- CURLOPT_VERBOSE => TRUE
- ],
- [
- CURLOPT_PROXYPORT => 8080,
- CURLOPT_PROXYTYPE => CURLPROXY_HTTP,
- CURLOPT_VERBOSE => TRUE
- ]
- ]
- ];
- return $provider;
- }
- /**
- * Test for Request_Client_External::options() to ensure options
- * can be set to the external client (for cURL and PECL_HTTP)
- *
- * @dataProvider provider_options_set_to_external_client
- *
- * @param array settings
- * @param array expected
- * @return void
- */
- public function test_options_set_to_external_client($settings, $expected)
- {
- $request_client = Request_Client_External::factory([], 'Request_Client_Curl');
- // Test for empty array
- $this->assertSame([], $request_client->options());
- // Test that set works as expected
- $this->assertSame($request_client->options($settings), $request_client);
- // Test that each setting is present and returned
- foreach ($expected as $key => $value)
- {
- $this->assertSame($request_client->options($key), $value);
- }
- }
- /**
- * Provides data for test_headers_get()
- *
- * @return array
- */
- public function provider_headers_get()
- {
- $x_powered_by = 'KO7 Unit Test';
- $content_type = 'application/x-www-form-urlencoded';
- $request = new Request('foo/bar', [], TRUE, []);
- return [
- [
- $request->headers([
- 'x-powered-by' => $x_powered_by,
- 'content-type' => $content_type
- ]
- ),
- [
- 'x-powered-by' => $x_powered_by,
- 'content-type' => $content_type
- ]
- ]
- ];
- }
- /**
- * Tests getting headers from the Request object
- *
- * @dataProvider provider_headers_get
- *
- * @param Request request to test
- * @param array headers to test against
- * @return void
- */
- public function test_headers_get($request, $headers)
- {
- foreach ($headers as $key => $expected_value)
- {
- $this->assertSame( (string) $request->headers($key), $expected_value);
- }
- }
- /**
- * Provides data for test_headers_set
- *
- * @return array
- */
- public function provider_headers_set()
- {
- return [
- [
- [
- 'content-type' => 'application/x-www-form-urlencoded',
- 'x-test-header' => 'foo'
- ],
- "Content-Type: application/x-www-form-urlencoded\r\nX-Test-Header: foo\r\n\r\n"
- ],
- [
- [
- 'content-type' => 'application/json',
- 'x-powered-by' => 'ko7'
- ],
- "Content-Type: application/json\r\nX-Powered-By: ko7\r\n\r\n"
- ]
- ];
- }
- /**
- * Tests the setting of headers to the request object
- *
- * @dataProvider provider_headers_set
- *
- * @param array header(s) to set to the request object
- * @param string expected http header
- * @return void
- */
- public function test_headers_set($headers, $expected)
- {
- $request = new Request(TRUE, [], TRUE, []);
- $request->headers($headers);
- $this->assertSame($expected, (string) $request->headers());
- }
- /**
- * Provides test data for test_query_parameter_parsing()
- *
- * @return array
- */
- public function provider_query_parameter_parsing()
- {
- return [
- [
- 'foo/bar',
- [
- 'foo' => 'bar',
- 'sna' => 'fu'
- ],
- [
- 'foo' => 'bar',
- 'sna' => 'fu'
- ],
- ],
- [
- 'foo/bar?john=wayne&peggy=sue',
- [
- 'foo' => 'bar',
- 'sna' => 'fu'
- ],
- [
- 'john' => 'wayne',
- 'peggy' => 'sue',
- 'foo' => 'bar',
- 'sna' => 'fu'
- ],
- ],
- [
- 'http://host.tld/foo/bar?john=wayne&peggy=sue',
- [
- 'foo' => 'bar',
- 'sna' => 'fu'
- ],
- [
- 'john' => 'wayne',
- 'peggy' => 'sue',
- 'foo' => 'bar',
- 'sna' => 'fu'
- ],
- ],
- ];
- }
- /**
- * Tests that query parameters are parsed correctly
- *
- * @dataProvider provider_query_parameter_parsing
- *
- * @param string url
- * @param array query
- * @param array expected
- * @return void
- */
- public function test_query_parameter_parsing($url, $query, $expected)
- {
- Request::$initial = NULL;
- $request = new Request($url);
- foreach ($query as $key => $value)
- {
- $request->query($key, $value);
- }
- $this->assertSame($expected, $request->query());
- }
- /**
- * Tests that query parameters are parsed correctly
- *
- * @dataProvider provider_query_parameter_parsing
- *
- * @param string url
- * @param array query
- * @param array expected
- * @return void
- */
- public function test_query_parameter_parsing_in_subrequest($url, $query, $expected)
- {
- Request::$initial = new Request(TRUE);
- $request = new Request($url);
- foreach ($query as $key => $value)
- {
- $request->query($key, $value);
- }
- $this->assertSame($expected, $request->query());
- }
- /**
- * Provides data for test_client
- *
- * @return array
- */
- public function provider_client()
- {
- $internal_client = new Request_Client_Internal;
- $external_client = new Request_Client_Stream;
- return [
- [
- new Request('http://koseven.dev/'),
- $internal_client,
- $internal_client
- ],
- [
- new Request('foo/bar'),
- $external_client,
- $external_client
- ]
- ];
- }
- /**
- * Tests the getter/setter for request client
- *
- * @dataProvider provider_client
- *
- * @param Request $request
- * @param Request_Client $client
- * @param Request_Client $expected
- * @return void
- */
- public function test_client(Request $request, Request_Client $client, Request_Client $expected)
- {
- $request->client($client);
- $this->assertSame($expected, $request->client());
- }
- /**
- * Tests that the Request constructor passes client params on to the
- * Request_Client once created.
- */
- public function test_passes_client_params()
- {
- $request = Request::factory('http://example.com/', [
- 'follow' => TRUE,
- 'strict_redirect' => FALSE
- ]);
- $client = $request->client();
- $this->assertEquals($client->follow(), TRUE);
- $this->assertEquals($client->strict_redirect(), FALSE);
- }
- /**
- * Tests correctness request content-length header after calling render
- */
- public function test_content_length_after_render()
- {
- $request = Request::factory('https://example.org/post')
- ->client(new KO7_RequestTest_Header_Spying_Request_Client_External)
- ->method(Request::POST)
- ->post(['aaa' => 'bbb']);
- $request->render();
- $request->execute();
- $headers = $request->client()->get_received_request_headers();
- $this->assertEquals(strlen($request->body()), $headers['content-length']);
- }
- /**
- * Tests correctness request content-length header after calling render
- * and changing post
- */
- public function test_content_length_after_changing_post()
- {
- $request = Request::factory('https://example.org/post')
- ->client(new KO7_RequestTest_Header_Spying_Request_Client_External)
- ->method(Request::POST)
- ->post(['aaa' => 'bbb']);
- $request->render();
- $request->post(['one' => 'one', 'two' => 'two', 'three' => 'three']);
- $request->execute();
- $headers = $request->client()->get_received_request_headers();
- $this->assertEquals(strlen($request->body()), $headers['content-length']);
- }
- } // End KO7_RequestTest
- /**
- * A dummy Request_Client_External implementation, that spies on the headers
- * of the request
- */
- class KO7_RequestTest_Header_Spying_Request_Client_External extends Request_Client_External
- {
- private $headers;
- protected function _send_message(Request $request, Response $response) : Response
- {
- $this->headers = $request->headers();
- return $response;
- }
- public function get_received_request_headers()
- {
- return $this->headers;
- }
- }
- class Controller_KO7_RequestTest_Dummy extends Controller
- {
- // hard coded dummy response
- protected $dummy_response = "this is a dummy response";
- public function action_foobar()
- {
- $this->response->body($this->dummy_response);
- }
- public function get_expected_response()
- {
- return $this->dummy_response;
- }
- } // End KO7_RequestTest
|