RequestTest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. <?php
  2. /**
  3. * Unit tests for request class
  4. *
  5. * @group ko7
  6. * @group ko7.core
  7. * @group ko7.core.request
  8. *
  9. * @package KO7
  10. * @category Tests
  11. *
  12. * @author BRMatt <matthew@sigswitch.com>
  13. * @copyright (c) 2007-2016 Kohana Team
  14. * @copyright (c) since 2016 Koseven Team
  15. * @license https://koseven.dev/LICENSE
  16. */
  17. class KO7_RequestTest extends Unittest_TestCase
  18. {
  19. protected $_inital_request;
  20. // @codingStandardsIgnoreStart
  21. public function setUp(): void
  22. // @codingStandardsIgnoreEnd
  23. {
  24. parent::setUp();
  25. KO7::$config->load('url')->set('trusted_hosts', ['localhost']);
  26. $this->_initial_request = Request::$initial;
  27. Request::$initial = new Request('/');
  28. }
  29. // @codingStandardsIgnoreStart
  30. public function tearDown(): void
  31. // @codingStandardsIgnoreEnd
  32. {
  33. Request::$initial = $this->_initial_request;
  34. parent::tearDown();
  35. }
  36. public function test_initial()
  37. {
  38. $this->setEnvironment([
  39. 'Request::$initial' => NULL,
  40. 'Request::$client_ip' => NULL,
  41. 'Request::$user_agent' => NULL,
  42. '_SERVER' => [
  43. 'HTTPS' => NULL,
  44. 'PATH_INFO' => '/',
  45. 'HTTP_REFERER' => 'http://example.com/',
  46. 'HTTP_USER_AGENT' => 'whatever (Mozilla 5.0/compatible)',
  47. 'REMOTE_ADDR' => '127.0.0.1',
  48. 'REQUEST_METHOD' => 'GET',
  49. 'HTTP_X_REQUESTED_WITH' => 'ajax-or-something',
  50. ],
  51. '_GET' => [],
  52. '_POST' => [],
  53. ]);
  54. $request = Request::factory();
  55. $this->assertEquals(Request::$initial, $request);
  56. $this->assertEquals(Request::$client_ip, '127.0.0.1');
  57. $this->assertEquals(Request::$user_agent, 'whatever (Mozilla 5.0/compatible)');
  58. $this->assertEquals($request->protocol(), 'HTTP/1.1');
  59. $this->assertEquals($request->referrer(), 'http://example.com/');
  60. $this->assertEquals($request->requested_with(), 'ajax-or-something');
  61. $this->assertEquals($request->query(), []);
  62. $this->assertEquals($request->post(), []);
  63. }
  64. /**
  65. * Tests client IP detection
  66. *
  67. * @return null
  68. */
  69. public function test_client_ips()
  70. {
  71. // testing X-Forwarded-For
  72. $server = [
  73. 'HTTPS' => NULL,
  74. 'PATH_INFO' => '/',
  75. 'REMOTE_ADDR' => '255.255.255.1',
  76. 'HTTP_X_FORWARDED_FOR' => '127.0.0.2, 255.255.255.1, 255.255.255.2',
  77. ];
  78. $this->setEnvironment([
  79. 'Request::$initial' => NULL,
  80. 'Request::$client_ip' => NULL,
  81. 'Request::$trusted_proxies' => ['255.255.255.1'],
  82. '_SERVER' => $server,
  83. ]);
  84. $request = Request::factory();
  85. $this->assertEquals(Request::$client_ip, '127.0.0.2', 'Header "HTTP_X_FORWARDED_FOR" handled incorrectly');
  86. // testing Client-IP
  87. $server['HTTP_CLIENT_IP'] = '127.0.0.3';
  88. unset($server['HTTP_X_FORWARDED_FOR']);
  89. $this->setEnvironment([
  90. 'Request::$initial' => NULL,
  91. 'Request::$client_ip' => NULL,
  92. '_SERVER' => $server,
  93. ]);
  94. $request = Request::factory();
  95. $this->assertEquals(Request::$client_ip, '127.0.0.3', 'Header "HTTP_CLIENT_IP" handled incorrectly');
  96. // testing Cloudflare
  97. $server['HTTP_CF_CONNECTING_IP'] = '127.0.0.4';
  98. $this->setEnvironment([
  99. 'Request::$initial' => NULL,
  100. 'Request::$client_ip' => NULL,
  101. '_SERVER' => $server,
  102. ]);
  103. $request = Request::factory();
  104. $this->assertEquals(Request::$client_ip, '127.0.0.4', 'Cloudflare header "HTTP_CF_CONNECTING_IP" handled incorrectly');
  105. }
  106. /**
  107. * Tests that the allow_external flag prevents an external request.
  108. *
  109. * @return null
  110. */
  111. public function test_disable_external_tests()
  112. {
  113. $this->setEnvironment(
  114. [
  115. 'Request::$initial' => NULL,
  116. ]
  117. );
  118. $request = new Request('http://www.google.com/', [], FALSE);
  119. $this->assertEquals(FALSE, $request->is_external());
  120. }
  121. /**
  122. * Provides the data for test_create()
  123. * @return array
  124. */
  125. public function provider_create()
  126. {
  127. return [
  128. ['foo/bar', 'Request_Client_Internal'],
  129. ['http://google.com', 'Request_Client_External'],
  130. ];
  131. }
  132. /**
  133. * Ensures the create class is created with the correct client
  134. *
  135. * @test
  136. * @dataProvider provider_create
  137. */
  138. public function test_create($uri, $client_class)
  139. {
  140. $request = Request::factory($uri);
  141. $this->assertInstanceOf($client_class, $request->client());
  142. }
  143. /**
  144. * Ensure that parameters can be read
  145. *
  146. * @test
  147. */
  148. public function test_param()
  149. {
  150. $route = new Route('(<controller>(/<action>(/<id>)))');
  151. $uri = 'ko7_requesttest_dummy/foobar/some_id';
  152. $request = Request::factory($uri, NULL, TRUE, [$route]);
  153. // We need to execute the request before it has matched a route
  154. $response = $request->execute();
  155. $controller = new Controller_KO7_RequestTest_Dummy($request, $response);
  156. $this->assertSame(200, $response->status());
  157. $this->assertSame($controller->get_expected_response(), $response->body());
  158. $this->assertArrayHasKey('id', $request->param());
  159. $this->assertArrayNotHasKey('foo', $request->param());
  160. $this->assertEquals($request->uri(), $uri);
  161. // Ensure the params do not contain contamination from controller, action, route, uri etc etc
  162. $params = $request->param();
  163. // Test for illegal components
  164. $this->assertArrayNotHasKey('controller', $params);
  165. $this->assertArrayNotHasKey('action', $params);
  166. $this->assertArrayNotHasKey('directory', $params);
  167. $this->assertArrayNotHasKey('uri', $params);
  168. $this->assertArrayNotHasKey('route', $params);
  169. $route = new Route('(<uri>)', ['uri' => '.+']);
  170. $route->defaults(['controller' => 'ko7_requesttest_dummy', 'action' => 'foobar']);
  171. $request = Request::factory('ko7_requesttest_dummy', NULL, TRUE, [$route]);
  172. // We need to execute the request before it has matched a route
  173. $response = $request->execute();
  174. $controller = new Controller_KO7_RequestTest_Dummy($request, $response);
  175. $this->assertSame(200, $response->status());
  176. $this->assertSame($controller->get_expected_response(), $response->body());
  177. $this->assertSame('ko7_requesttest_dummy', $request->param('uri'));
  178. }
  179. /**
  180. * Tests Request::method()
  181. *
  182. * @test
  183. */
  184. public function test_method()
  185. {
  186. $request = Request::factory('foo/bar');
  187. $this->assertEquals($request->method(), 'GET');
  188. $this->assertEquals(($request->method('post') === $request), TRUE);
  189. $this->assertEquals(($request->method() === 'POST'), TRUE);
  190. }
  191. /**
  192. * Tests Request::route()
  193. *
  194. * @test
  195. */
  196. public function test_route()
  197. {
  198. $request = Request::factory(''); // This should always match something, no matter what changes people make
  199. // We need to execute the request before it has matched a route
  200. try
  201. {
  202. $request->execute();
  203. }
  204. catch (Exception $e) {}
  205. $this->assertInstanceOf('Route', $request->route());
  206. }
  207. /**
  208. * Tests Request::route()
  209. *
  210. * @test
  211. */
  212. public function test_route_is_not_set_before_execute()
  213. {
  214. $request = Request::factory(''); // This should always match something, no matter what changes people make
  215. // The route should be NULL since the request has not been executed yet
  216. $this->assertEquals($request->route(), NULL);
  217. }
  218. /**
  219. * Provides test data for Request::url()
  220. * @return array
  221. */
  222. public function provider_url()
  223. {
  224. return [
  225. [
  226. 'foo/bar',
  227. 'http',
  228. 'http://localhost/ko7/foo/bar'
  229. ],
  230. [
  231. 'foo',
  232. 'http',
  233. 'http://localhost/ko7/foo'
  234. ],
  235. [
  236. 'http://www.google.com',
  237. 'http',
  238. 'http://www.google.com'
  239. ],
  240. [
  241. '0',
  242. 'http',
  243. 'http://localhost/ko7/0'
  244. ]
  245. ];
  246. }
  247. /**
  248. * Tests Request::url()
  249. *
  250. * @test
  251. * @dataProvider provider_url
  252. * @covers Request::url
  253. * @param string $uri the uri to use
  254. * @param string $protocol the protocol to use
  255. * @param array $expected The string we expect
  256. */
  257. public function test_url($uri, $protocol, $expected)
  258. {
  259. if ( ! isset($_SERVER['argc']))
  260. {
  261. $_SERVER['argc'] = 1;
  262. }
  263. $this->setEnvironment([
  264. 'KO7::$base_url' => '/ko7/',
  265. '_SERVER' => ['HTTP_HOST' => 'localhost', 'argc' => $_SERVER['argc']],
  266. 'KO7::$index_file' => FALSE,
  267. ]);
  268. // issue #3967: inject the route so that we don't conflict with the application's default route
  269. $route = new Route('(<controller>(/<action>))');
  270. $route->defaults([
  271. 'controller' => 'welcome',
  272. 'action' => 'index',
  273. ]);
  274. $this->assertEquals(Request::factory($uri, [], TRUE, [$route])->url($protocol), $expected);
  275. }
  276. /**
  277. * Data provider for test_set_protocol() test
  278. *
  279. * @return array
  280. */
  281. public function provider_set_protocol()
  282. {
  283. return [
  284. [
  285. 'http/1.1',
  286. 'HTTP/1.1',
  287. ],
  288. [
  289. 'ftp',
  290. 'FTP',
  291. ],
  292. [
  293. 'hTTp/1.0',
  294. 'HTTP/1.0',
  295. ],
  296. ];
  297. }
  298. /**
  299. * Tests the protocol() method
  300. *
  301. * @dataProvider provider_set_protocol
  302. *
  303. * @return null
  304. */
  305. public function test_set_protocol($protocol, $expected)
  306. {
  307. $request = Request::factory();
  308. // Set the supplied protocol
  309. $result = $request->protocol($protocol);
  310. // Test the set value
  311. $this->assertSame($expected, $request->protocol());
  312. // Test the return value
  313. $this->assertTrue($request instanceof $result);
  314. }
  315. /**
  316. * Provides data for test_post_max_size_exceeded()
  317. *
  318. * @return array
  319. */
  320. public function provider_post_max_size_exceeded()
  321. {
  322. // Get the post max size
  323. $post_max_size = Num::bytes(ini_get('post_max_size'));
  324. return [
  325. [
  326. $post_max_size+200000,
  327. TRUE
  328. ],
  329. [
  330. $post_max_size-20,
  331. FALSE
  332. ],
  333. [
  334. $post_max_size,
  335. FALSE
  336. ]
  337. ];
  338. }
  339. /**
  340. * Tests the post_max_size_exceeded() method
  341. *
  342. * @dataProvider provider_post_max_size_exceeded
  343. *
  344. * @param int content_length
  345. * @param bool expected
  346. * @return void
  347. */
  348. public function test_post_max_size_exceeded($content_length, $expected)
  349. {
  350. // Ensure the request method is set to POST
  351. Request::$initial->method(HTTP_Request::POST);
  352. // Set the content length
  353. $_SERVER['CONTENT_LENGTH'] = $content_length;
  354. // Test the post_max_size_exceeded() method
  355. $this->assertSame(Request::post_max_size_exceeded(), $expected);
  356. }
  357. /**
  358. * Provides data for test_uri_only_trimed_on_internal()
  359. *
  360. * @return array
  361. */
  362. public function provider_uri_only_trimed_on_internal()
  363. {
  364. // issue #3967: inject the route so that we don't conflict with the application's default route
  365. $route = new Route('(<controller>(/<action>))');
  366. $route->defaults([
  367. 'controller' => 'welcome',
  368. 'action' => 'index',
  369. ]);
  370. $old_request = Request::$initial;
  371. Request::$initial = new Request(TRUE, [], TRUE, [$route]);
  372. $result = [
  373. [
  374. new Request('http://www.google.com'),
  375. 'http://www.google.com'
  376. ],
  377. [
  378. new Request('http://www.google.com/'),
  379. 'http://www.google.com/'
  380. ],
  381. [
  382. new Request('foo/bar/'),
  383. 'foo/bar'
  384. ],
  385. [
  386. new Request('foo/bar'),
  387. 'foo/bar'
  388. ],
  389. [
  390. new Request('/0'),
  391. '0'
  392. ],
  393. [
  394. new Request('0'),
  395. '0'
  396. ],
  397. [
  398. new Request('/'),
  399. '/'
  400. ],
  401. [
  402. new Request(''),
  403. '/'
  404. ]
  405. ];
  406. Request::$initial = $old_request;
  407. return $result;
  408. }
  409. /**
  410. * Tests that the uri supplied to Request is only trimed
  411. * for internal requests.
  412. *
  413. * @dataProvider provider_uri_only_trimed_on_internal
  414. *
  415. * @return void
  416. */
  417. public function test_uri_only_trimed_on_internal(Request $request, $expected)
  418. {
  419. $this->assertSame($request->uri(), $expected);
  420. }
  421. /**
  422. * Data provider for test_options_set_to_external_client()
  423. *
  424. * @return array
  425. */
  426. public function provider_options_set_to_external_client()
  427. {
  428. $provider = [
  429. [
  430. [
  431. CURLOPT_PROXYPORT => 8080,
  432. CURLOPT_PROXYTYPE => CURLPROXY_HTTP,
  433. CURLOPT_VERBOSE => TRUE
  434. ],
  435. [
  436. CURLOPT_PROXYPORT => 8080,
  437. CURLOPT_PROXYTYPE => CURLPROXY_HTTP,
  438. CURLOPT_VERBOSE => TRUE
  439. ]
  440. ]
  441. ];
  442. return $provider;
  443. }
  444. /**
  445. * Test for Request_Client_External::options() to ensure options
  446. * can be set to the external client (for cURL and PECL_HTTP)
  447. *
  448. * @dataProvider provider_options_set_to_external_client
  449. *
  450. * @param array settings
  451. * @param array expected
  452. * @return void
  453. */
  454. public function test_options_set_to_external_client($settings, $expected)
  455. {
  456. $request_client = Request_Client_External::factory([], 'Request_Client_Curl');
  457. // Test for empty array
  458. $this->assertSame([], $request_client->options());
  459. // Test that set works as expected
  460. $this->assertSame($request_client->options($settings), $request_client);
  461. // Test that each setting is present and returned
  462. foreach ($expected as $key => $value)
  463. {
  464. $this->assertSame($request_client->options($key), $value);
  465. }
  466. }
  467. /**
  468. * Provides data for test_headers_get()
  469. *
  470. * @return array
  471. */
  472. public function provider_headers_get()
  473. {
  474. $x_powered_by = 'KO7 Unit Test';
  475. $content_type = 'application/x-www-form-urlencoded';
  476. $request = new Request('foo/bar', [], TRUE, []);
  477. return [
  478. [
  479. $request->headers([
  480. 'x-powered-by' => $x_powered_by,
  481. 'content-type' => $content_type
  482. ]
  483. ),
  484. [
  485. 'x-powered-by' => $x_powered_by,
  486. 'content-type' => $content_type
  487. ]
  488. ]
  489. ];
  490. }
  491. /**
  492. * Tests getting headers from the Request object
  493. *
  494. * @dataProvider provider_headers_get
  495. *
  496. * @param Request request to test
  497. * @param array headers to test against
  498. * @return void
  499. */
  500. public function test_headers_get($request, $headers)
  501. {
  502. foreach ($headers as $key => $expected_value)
  503. {
  504. $this->assertSame( (string) $request->headers($key), $expected_value);
  505. }
  506. }
  507. /**
  508. * Provides data for test_headers_set
  509. *
  510. * @return array
  511. */
  512. public function provider_headers_set()
  513. {
  514. return [
  515. [
  516. [
  517. 'content-type' => 'application/x-www-form-urlencoded',
  518. 'x-test-header' => 'foo'
  519. ],
  520. "Content-Type: application/x-www-form-urlencoded\r\nX-Test-Header: foo\r\n\r\n"
  521. ],
  522. [
  523. [
  524. 'content-type' => 'application/json',
  525. 'x-powered-by' => 'ko7'
  526. ],
  527. "Content-Type: application/json\r\nX-Powered-By: ko7\r\n\r\n"
  528. ]
  529. ];
  530. }
  531. /**
  532. * Tests the setting of headers to the request object
  533. *
  534. * @dataProvider provider_headers_set
  535. *
  536. * @param array header(s) to set to the request object
  537. * @param string expected http header
  538. * @return void
  539. */
  540. public function test_headers_set($headers, $expected)
  541. {
  542. $request = new Request(TRUE, [], TRUE, []);
  543. $request->headers($headers);
  544. $this->assertSame($expected, (string) $request->headers());
  545. }
  546. /**
  547. * Provides test data for test_query_parameter_parsing()
  548. *
  549. * @return array
  550. */
  551. public function provider_query_parameter_parsing()
  552. {
  553. return [
  554. [
  555. 'foo/bar',
  556. [
  557. 'foo' => 'bar',
  558. 'sna' => 'fu'
  559. ],
  560. [
  561. 'foo' => 'bar',
  562. 'sna' => 'fu'
  563. ],
  564. ],
  565. [
  566. 'foo/bar?john=wayne&peggy=sue',
  567. [
  568. 'foo' => 'bar',
  569. 'sna' => 'fu'
  570. ],
  571. [
  572. 'john' => 'wayne',
  573. 'peggy' => 'sue',
  574. 'foo' => 'bar',
  575. 'sna' => 'fu'
  576. ],
  577. ],
  578. [
  579. 'http://host.tld/foo/bar?john=wayne&peggy=sue',
  580. [
  581. 'foo' => 'bar',
  582. 'sna' => 'fu'
  583. ],
  584. [
  585. 'john' => 'wayne',
  586. 'peggy' => 'sue',
  587. 'foo' => 'bar',
  588. 'sna' => 'fu'
  589. ],
  590. ],
  591. ];
  592. }
  593. /**
  594. * Tests that query parameters are parsed correctly
  595. *
  596. * @dataProvider provider_query_parameter_parsing
  597. *
  598. * @param string url
  599. * @param array query
  600. * @param array expected
  601. * @return void
  602. */
  603. public function test_query_parameter_parsing($url, $query, $expected)
  604. {
  605. Request::$initial = NULL;
  606. $request = new Request($url);
  607. foreach ($query as $key => $value)
  608. {
  609. $request->query($key, $value);
  610. }
  611. $this->assertSame($expected, $request->query());
  612. }
  613. /**
  614. * Tests that query parameters are parsed correctly
  615. *
  616. * @dataProvider provider_query_parameter_parsing
  617. *
  618. * @param string url
  619. * @param array query
  620. * @param array expected
  621. * @return void
  622. */
  623. public function test_query_parameter_parsing_in_subrequest($url, $query, $expected)
  624. {
  625. Request::$initial = new Request(TRUE);
  626. $request = new Request($url);
  627. foreach ($query as $key => $value)
  628. {
  629. $request->query($key, $value);
  630. }
  631. $this->assertSame($expected, $request->query());
  632. }
  633. /**
  634. * Provides data for test_client
  635. *
  636. * @return array
  637. */
  638. public function provider_client()
  639. {
  640. $internal_client = new Request_Client_Internal;
  641. $external_client = new Request_Client_Stream;
  642. return [
  643. [
  644. new Request('http://koseven.dev/'),
  645. $internal_client,
  646. $internal_client
  647. ],
  648. [
  649. new Request('foo/bar'),
  650. $external_client,
  651. $external_client
  652. ]
  653. ];
  654. }
  655. /**
  656. * Tests the getter/setter for request client
  657. *
  658. * @dataProvider provider_client
  659. *
  660. * @param Request $request
  661. * @param Request_Client $client
  662. * @param Request_Client $expected
  663. * @return void
  664. */
  665. public function test_client(Request $request, Request_Client $client, Request_Client $expected)
  666. {
  667. $request->client($client);
  668. $this->assertSame($expected, $request->client());
  669. }
  670. /**
  671. * Tests that the Request constructor passes client params on to the
  672. * Request_Client once created.
  673. */
  674. public function test_passes_client_params()
  675. {
  676. $request = Request::factory('http://example.com/', [
  677. 'follow' => TRUE,
  678. 'strict_redirect' => FALSE
  679. ]);
  680. $client = $request->client();
  681. $this->assertEquals($client->follow(), TRUE);
  682. $this->assertEquals($client->strict_redirect(), FALSE);
  683. }
  684. /**
  685. * Tests correctness request content-length header after calling render
  686. */
  687. public function test_content_length_after_render()
  688. {
  689. $request = Request::factory('https://example.org/post')
  690. ->client(new KO7_RequestTest_Header_Spying_Request_Client_External)
  691. ->method(Request::POST)
  692. ->post(['aaa' => 'bbb']);
  693. $request->render();
  694. $request->execute();
  695. $headers = $request->client()->get_received_request_headers();
  696. $this->assertEquals(strlen($request->body()), $headers['content-length']);
  697. }
  698. /**
  699. * Tests correctness request content-length header after calling render
  700. * and changing post
  701. */
  702. public function test_content_length_after_changing_post()
  703. {
  704. $request = Request::factory('https://example.org/post')
  705. ->client(new KO7_RequestTest_Header_Spying_Request_Client_External)
  706. ->method(Request::POST)
  707. ->post(['aaa' => 'bbb']);
  708. $request->render();
  709. $request->post(['one' => 'one', 'two' => 'two', 'three' => 'three']);
  710. $request->execute();
  711. $headers = $request->client()->get_received_request_headers();
  712. $this->assertEquals(strlen($request->body()), $headers['content-length']);
  713. }
  714. } // End KO7_RequestTest
  715. /**
  716. * A dummy Request_Client_External implementation, that spies on the headers
  717. * of the request
  718. */
  719. class KO7_RequestTest_Header_Spying_Request_Client_External extends Request_Client_External
  720. {
  721. private $headers;
  722. protected function _send_message(Request $request, Response $response) : Response
  723. {
  724. $this->headers = $request->headers();
  725. return $response;
  726. }
  727. public function get_received_request_headers()
  728. {
  729. return $this->headers;
  730. }
  731. }
  732. class Controller_KO7_RequestTest_Dummy extends Controller
  733. {
  734. // hard coded dummy response
  735. protected $dummy_response = "this is a dummy response";
  736. public function action_foobar()
  737. {
  738. $this->response->body($this->dummy_response);
  739. }
  740. public function get_expected_response()
  741. {
  742. return $this->dummy_response;
  743. }
  744. } // End KO7_RequestTest