ClientTest.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  10. * @link https://cakephp.org CakePHP(tm) Project
  11. * @since 3.0.0
  12. * @license https://opensource.org/licenses/mit-license.php MIT License
  13. */
  14. namespace Cake\Test\TestCase\Http;
  15. use Cake\Http\Client;
  16. use Cake\Http\Client\Request;
  17. use Cake\Http\Client\Response;
  18. use Cake\Http\Cookie\Cookie;
  19. use Cake\Http\Cookie\CookieCollection;
  20. use Cake\TestSuite\TestCase;
  21. /**
  22. * HTTP client test.
  23. */
  24. class ClientTest extends TestCase
  25. {
  26. /**
  27. * Test storing config options and modifying them.
  28. *
  29. * @return void
  30. */
  31. public function testConstructConfig()
  32. {
  33. $config = [
  34. 'scheme' => 'http',
  35. 'host' => 'example.org',
  36. ];
  37. $http = new Client($config);
  38. $result = $http->getConfig();
  39. foreach ($config as $key => $val) {
  40. $this->assertEquals($val, $result[$key]);
  41. }
  42. $result = $http->setConfig([
  43. 'auth' => ['username' => 'mark', 'password' => 'secret']
  44. ]);
  45. $this->assertSame($result, $http);
  46. $result = $http->getConfig();
  47. $expected = [
  48. 'scheme' => 'http',
  49. 'host' => 'example.org',
  50. 'auth' => ['username' => 'mark', 'password' => 'secret']
  51. ];
  52. foreach ($expected as $key => $val) {
  53. $this->assertEquals($val, $result[$key]);
  54. }
  55. }
  56. /**
  57. * Data provider for buildUrl() tests
  58. *
  59. * @return array
  60. */
  61. public static function urlProvider()
  62. {
  63. return [
  64. [
  65. 'http://example.com/test.html',
  66. 'http://example.com/test.html',
  67. [],
  68. null,
  69. 'Null options'
  70. ],
  71. [
  72. 'http://example.com/test.html',
  73. 'http://example.com/test.html',
  74. [],
  75. [],
  76. 'Simple string'
  77. ],
  78. [
  79. 'http://example.com/test.html',
  80. '/test.html',
  81. [],
  82. ['host' => 'example.com'],
  83. 'host name option',
  84. ],
  85. [
  86. 'https://example.com/test.html',
  87. '/test.html',
  88. [],
  89. ['host' => 'example.com', 'scheme' => 'https'],
  90. 'HTTPS',
  91. ],
  92. [
  93. 'http://example.com:8080/test.html',
  94. '/test.html',
  95. [],
  96. ['host' => 'example.com', 'port' => '8080'],
  97. 'Non standard port',
  98. ],
  99. [
  100. 'http://example.com/test.html',
  101. '/test.html',
  102. [],
  103. ['host' => 'example.com', 'port' => '80'],
  104. 'standard port, does not display'
  105. ],
  106. [
  107. 'https://example.com/test.html',
  108. '/test.html',
  109. [],
  110. ['host' => 'example.com', 'scheme' => 'https', 'port' => '443'],
  111. 'standard port, does not display'
  112. ],
  113. [
  114. 'http://example.com/test.html',
  115. 'http://example.com/test.html',
  116. [],
  117. ['host' => 'example.com', 'scheme' => 'https'],
  118. 'options do not duplicate'
  119. ],
  120. [
  121. 'http://example.com/search?q=hi+there&cat%5Bid%5D%5B0%5D=2&cat%5Bid%5D%5B1%5D=3',
  122. 'http://example.com/search',
  123. ['q' => 'hi there', 'cat' => ['id' => [2, 3]]],
  124. [],
  125. 'query string data.'
  126. ],
  127. [
  128. 'http://example.com/search?q=hi+there&id=12',
  129. 'http://example.com/search?q=hi+there',
  130. ['id' => '12'],
  131. [],
  132. 'query string data with some already on the url.'
  133. ],
  134. [
  135. 'http://example.com/test.html',
  136. '//test.html',
  137. [],
  138. [
  139. 'scheme' => 'http',
  140. 'host' => 'example.com',
  141. 'protocolRelative' => false
  142. ],
  143. 'url with a double slash',
  144. ],
  145. [
  146. 'http://example.com/test.html',
  147. '//example.com/test.html',
  148. [],
  149. [
  150. 'scheme' => 'http',
  151. 'protocolRelative' => true
  152. ],
  153. 'protocol relative url',
  154. ],
  155. ];
  156. }
  157. /**
  158. * @dataProvider urlProvider
  159. */
  160. public function testBuildUrl($expected, $url, $query, $opts)
  161. {
  162. $http = new Client();
  163. $result = $http->buildUrl($url, $query, $opts);
  164. $this->assertEquals($expected, $result);
  165. }
  166. /**
  167. * test simple get request with headers & cookies.
  168. *
  169. * @return void
  170. */
  171. public function testGetSimpleWithHeadersAndCookies()
  172. {
  173. $response = new Response();
  174. $headers = [
  175. 'User-Agent' => 'Cake',
  176. 'Connection' => 'close',
  177. 'Content-Type' => 'application/x-www-form-urlencoded',
  178. ];
  179. $cookies = [
  180. 'split' => 'value'
  181. ];
  182. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  183. ->setMethods(['send'])
  184. ->getMock();
  185. $mock->expects($this->once())
  186. ->method('send')
  187. ->with($this->callback(function ($request) use ($cookies, $headers) {
  188. $this->assertInstanceOf('Cake\Http\Client\Request', $request);
  189. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  190. $this->assertEquals('http://cakephp.org/test.html', $request->getUri() . '');
  191. $this->assertEquals('split=value', $request->getHeaderLine('Cookie'));
  192. $this->assertEquals($headers['Content-Type'], $request->getHeaderLine('content-type'));
  193. $this->assertEquals($headers['Connection'], $request->getHeaderLine('connection'));
  194. return true;
  195. }))
  196. ->will($this->returnValue([$response]));
  197. $http = new Client(['adapter' => $mock]);
  198. $result = $http->get('http://cakephp.org/test.html', [], [
  199. 'headers' => $headers,
  200. 'cookies' => $cookies,
  201. ]);
  202. $this->assertSame($result, $response);
  203. }
  204. /**
  205. * test get request with no data
  206. *
  207. * @return void
  208. */
  209. public function testGetNoData()
  210. {
  211. $response = new Response();
  212. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  213. ->setMethods(['send'])
  214. ->getMock();
  215. $mock->expects($this->once())
  216. ->method('send')
  217. ->with($this->callback(function ($request) {
  218. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  219. $this->assertEmpty($request->getHeaderLine('Content-Type'), 'Should have no content-type set');
  220. $this->assertEquals(
  221. 'http://cakephp.org/search',
  222. $request->getUri() . ''
  223. );
  224. return true;
  225. }))
  226. ->will($this->returnValue([$response]));
  227. $http = new Client([
  228. 'host' => 'cakephp.org',
  229. 'adapter' => $mock
  230. ]);
  231. $result = $http->get('/search');
  232. $this->assertSame($result, $response);
  233. }
  234. /**
  235. * test get request with querystring data
  236. *
  237. * @return void
  238. */
  239. public function testGetQuerystring()
  240. {
  241. $response = new Response();
  242. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  243. ->setMethods(['send'])
  244. ->getMock();
  245. $mock->expects($this->once())
  246. ->method('send')
  247. ->with($this->callback(function ($request) {
  248. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  249. $this->assertEquals(
  250. 'http://cakephp.org/search?q=hi+there&Category%5Bid%5D%5B0%5D=2&Category%5Bid%5D%5B1%5D=3',
  251. $request->getUri() . ''
  252. );
  253. return true;
  254. }))
  255. ->will($this->returnValue([$response]));
  256. $http = new Client([
  257. 'host' => 'cakephp.org',
  258. 'adapter' => $mock
  259. ]);
  260. $result = $http->get('/search', [
  261. 'q' => 'hi there',
  262. 'Category' => ['id' => [2, 3]]
  263. ]);
  264. $this->assertSame($result, $response);
  265. }
  266. /**
  267. * test get request with string of query data.
  268. *
  269. * @return void
  270. */
  271. public function testGetQuerystringString()
  272. {
  273. $response = new Response();
  274. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  275. ->setMethods(['send'])
  276. ->getMock();
  277. $mock->expects($this->once())
  278. ->method('send')
  279. ->with($this->callback(function ($request) {
  280. $this->assertEquals(
  281. 'http://cakephp.org/search?q=hi+there&Category%5Bid%5D%5B0%5D=2&Category%5Bid%5D%5B1%5D=3',
  282. $request->getUri() . ''
  283. );
  284. return true;
  285. }))
  286. ->will($this->returnValue([$response]));
  287. $http = new Client([
  288. 'host' => 'cakephp.org',
  289. 'adapter' => $mock
  290. ]);
  291. $data = [
  292. 'q' => 'hi there',
  293. 'Category' => ['id' => [2, 3]]
  294. ];
  295. $result = $http->get('/search', http_build_query($data));
  296. $this->assertSame($response, $result);
  297. }
  298. /**
  299. * Test a GET with a request body. Services like
  300. * elasticsearch use this feature.
  301. *
  302. * @return void
  303. */
  304. public function testGetWithContent()
  305. {
  306. $response = new Response();
  307. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  308. ->setMethods(['send'])
  309. ->getMock();
  310. $mock->expects($this->once())
  311. ->method('send')
  312. ->with($this->callback(function ($request) {
  313. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  314. $this->assertEquals('http://cakephp.org/search', '' . $request->getUri());
  315. $this->assertEquals('some data', '' . $request->getBody());
  316. return true;
  317. }))
  318. ->will($this->returnValue([$response]));
  319. $http = new Client([
  320. 'host' => 'cakephp.org',
  321. 'adapter' => $mock
  322. ]);
  323. $result = $http->get('/search', [
  324. '_content' => 'some data'
  325. ]);
  326. $this->assertSame($result, $response);
  327. }
  328. /**
  329. * Test invalid authentication types throw exceptions.
  330. *
  331. * @return void
  332. */
  333. public function testInvalidAuthenticationType()
  334. {
  335. $this->expectException(\Cake\Core\Exception\Exception::class);
  336. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  337. ->setMethods(['send'])
  338. ->getMock();
  339. $mock->expects($this->never())
  340. ->method('send');
  341. $http = new Client([
  342. 'host' => 'cakephp.org',
  343. 'adapter' => $mock
  344. ]);
  345. $result = $http->get('/', [], [
  346. 'auth' => ['type' => 'horribly broken']
  347. ]);
  348. }
  349. /**
  350. * Test setting basic authentication with get
  351. *
  352. * @return void
  353. */
  354. public function testGetWithAuthenticationAndProxy()
  355. {
  356. $response = new Response();
  357. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  358. ->setMethods(['send'])
  359. ->getMock();
  360. $headers = [
  361. 'Authorization' => 'Basic ' . base64_encode('mark:secret'),
  362. 'Proxy-Authorization' => 'Basic ' . base64_encode('mark:pass'),
  363. ];
  364. $mock->expects($this->once())
  365. ->method('send')
  366. ->with($this->callback(function ($request) use ($headers) {
  367. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  368. $this->assertEquals('http://cakephp.org/', '' . $request->getUri());
  369. $this->assertEquals($headers['Authorization'], $request->getHeaderLine('Authorization'));
  370. $this->assertEquals($headers['Proxy-Authorization'], $request->getHeaderLine('Proxy-Authorization'));
  371. return true;
  372. }))
  373. ->will($this->returnValue([$response]));
  374. $http = new Client([
  375. 'host' => 'cakephp.org',
  376. 'adapter' => $mock
  377. ]);
  378. $result = $http->get('/', [], [
  379. 'auth' => ['username' => 'mark', 'password' => 'secret'],
  380. 'proxy' => ['username' => 'mark', 'password' => 'pass'],
  381. ]);
  382. $this->assertSame($result, $response);
  383. }
  384. /**
  385. * Test authentication adapter that mutates request.
  386. *
  387. * @group deprecated
  388. * @return void
  389. */
  390. public function testAuthenticationWithMutation()
  391. {
  392. $this->deprecated(function () {
  393. static::setAppNamespace();
  394. $response = new Response();
  395. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  396. ->setMethods(['send'])
  397. ->getMock();
  398. $headers = [
  399. 'Authorization' => 'Bearer abc123',
  400. 'Proxy-Authorization' => 'Bearer abc123',
  401. ];
  402. $mock->expects($this->once())
  403. ->method('send')
  404. ->with($this->callback(function ($request) use ($headers) {
  405. $this->assertEquals(Request::METHOD_GET, $request->getMethod());
  406. $this->assertEquals('http://cakephp.org/', '' . $request->getUri());
  407. $this->assertEquals($headers['Authorization'], $request->getHeaderLine('Authorization'));
  408. $this->assertEquals($headers['Proxy-Authorization'], $request->getHeaderLine('Proxy-Authorization'));
  409. return true;
  410. }))
  411. ->will($this->returnValue([$response]));
  412. $http = new Client([
  413. 'host' => 'cakephp.org',
  414. 'adapter' => $mock
  415. ]);
  416. $result = $http->get('/', [], [
  417. 'auth' => ['type' => 'TestApp\Http\CompatAuth'],
  418. 'proxy' => ['type' => 'TestApp\Http\CompatAuth'],
  419. ]);
  420. $this->assertSame($result, $response);
  421. });
  422. }
  423. /**
  424. * Return a list of HTTP methods.
  425. *
  426. * @return array
  427. */
  428. public static function methodProvider()
  429. {
  430. return [
  431. [Request::METHOD_GET],
  432. [Request::METHOD_POST],
  433. [Request::METHOD_PUT],
  434. [Request::METHOD_DELETE],
  435. [Request::METHOD_PATCH],
  436. [Request::METHOD_OPTIONS],
  437. [Request::METHOD_TRACE],
  438. ];
  439. }
  440. /**
  441. * test simple POST request.
  442. *
  443. * @dataProvider methodProvider
  444. * @return void
  445. */
  446. public function testMethodsSimple($method)
  447. {
  448. $response = new Response();
  449. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  450. ->setMethods(['send'])
  451. ->getMock();
  452. $mock->expects($this->once())
  453. ->method('send')
  454. ->with($this->callback(function ($request) use ($method) {
  455. $this->assertInstanceOf('Cake\Http\Client\Request', $request);
  456. $this->assertEquals($method, $request->getMethod());
  457. $this->assertEquals('http://cakephp.org/projects/add', '' . $request->getUri());
  458. return true;
  459. }))
  460. ->will($this->returnValue([$response]));
  461. $http = new Client([
  462. 'host' => 'cakephp.org',
  463. 'adapter' => $mock
  464. ]);
  465. $result = $http->{$method}('/projects/add');
  466. $this->assertSame($result, $response);
  467. }
  468. /**
  469. * Provider for testing the type option.
  470. *
  471. * @return array
  472. */
  473. public static function typeProvider()
  474. {
  475. return [
  476. ['application/json', 'application/json'],
  477. ['json', 'application/json'],
  478. ['xml', 'application/xml'],
  479. ['application/xml', 'application/xml'],
  480. ];
  481. }
  482. /**
  483. * Test that using the 'type' option sets the correct headers
  484. *
  485. * @dataProvider typeProvider
  486. * @return void
  487. */
  488. public function testPostWithTypeKey($type, $mime)
  489. {
  490. $response = new Response();
  491. $data = 'some data';
  492. $headers = [
  493. 'Content-Type' => $mime,
  494. 'Accept' => $mime,
  495. ];
  496. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  497. ->setMethods(['send'])
  498. ->getMock();
  499. $mock->expects($this->once())
  500. ->method('send')
  501. ->with($this->callback(function ($request) use ($headers) {
  502. $this->assertEquals(Request::METHOD_POST, $request->getMethod());
  503. $this->assertEquals($headers['Content-Type'], $request->getHeaderLine('Content-Type'));
  504. $this->assertEquals($headers['Accept'], $request->getHeaderLine('Accept'));
  505. return true;
  506. }))
  507. ->will($this->returnValue([$response]));
  508. $http = new Client([
  509. 'host' => 'cakephp.org',
  510. 'adapter' => $mock
  511. ]);
  512. $http->post('/projects/add', $data, ['type' => $type]);
  513. }
  514. /**
  515. * Test that string payloads with no content type have a default content-type set.
  516. *
  517. * @return void
  518. */
  519. public function testPostWithStringDataDefaultsToFormEncoding()
  520. {
  521. $response = new Response();
  522. $data = 'some=value&more=data';
  523. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  524. ->setMethods(['send'])
  525. ->getMock();
  526. $mock->expects($this->any())
  527. ->method('send')
  528. ->with($this->callback(function ($request) use ($data) {
  529. $this->assertEquals($data, '' . $request->getBody());
  530. $this->assertEquals('application/x-www-form-urlencoded', $request->getHeaderLine('content-type'));
  531. return true;
  532. }))
  533. ->will($this->returnValue([$response]));
  534. $http = new Client([
  535. 'host' => 'cakephp.org',
  536. 'adapter' => $mock
  537. ]);
  538. $http->post('/projects/add', $data);
  539. $http->put('/projects/add', $data);
  540. $http->delete('/projects/add', $data);
  541. }
  542. /**
  543. * Test that exceptions are raised on invalid types.
  544. *
  545. * @return void
  546. */
  547. public function testExceptionOnUnknownType()
  548. {
  549. $this->expectException(\Cake\Core\Exception\Exception::class);
  550. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  551. ->setMethods(['send'])
  552. ->getMock();
  553. $mock->expects($this->never())
  554. ->method('send');
  555. $http = new Client([
  556. 'host' => 'cakephp.org',
  557. 'adapter' => $mock
  558. ]);
  559. $http->post('/projects/add', 'it works', ['type' => 'invalid']);
  560. }
  561. /**
  562. * Test that Client stores cookies
  563. *
  564. * @return void
  565. */
  566. public function testCookieStorage()
  567. {
  568. $adapter = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  569. ->setMethods(['send'])
  570. ->getMock();
  571. $headers = [
  572. 'HTTP/1.0 200 Ok',
  573. 'Set-Cookie: first=1',
  574. 'Set-Cookie: expiring=now; Expires=Wed, 09-Jun-1999 10:18:14 GMT'
  575. ];
  576. $response = new Response($headers, '');
  577. $adapter->expects($this->at(0))
  578. ->method('send')
  579. ->will($this->returnValue([$response]));
  580. $http = new Client([
  581. 'host' => 'cakephp.org',
  582. 'adapter' => $adapter,
  583. ]);
  584. $http->get('/projects');
  585. $cookies = $http->cookies();
  586. $this->assertCount(1, $cookies);
  587. $this->assertTrue($cookies->has('first'));
  588. $this->assertFalse($cookies->has('expiring'));
  589. }
  590. /**
  591. * Test cookieJar config option.
  592. *
  593. * @return void
  594. */
  595. public function testCookieJar()
  596. {
  597. $jar = new CookieCollection();
  598. $http = new Client([
  599. 'cookieJar' => $jar
  600. ]);
  601. $this->assertSame($jar, $http->cookies());
  602. }
  603. /**
  604. * Test addCookie() method.
  605. *
  606. * @return void
  607. */
  608. public function testAddCookie()
  609. {
  610. $client = new Client();
  611. $cookie = new Cookie('foo', '', null, '/', 'example.com');
  612. $this->assertFalse($client->cookies()->has('foo'));
  613. $client->addCookie($cookie);
  614. $this->assertTrue($client->cookies()->has('foo'));
  615. }
  616. /**
  617. * Test addCookie() method without a domain.
  618. *
  619. * @return void
  620. */
  621. public function testAddCookieWithoutDomain()
  622. {
  623. $this->expectException(\InvalidArgumentException::class);
  624. $this->expectExceptionMessage('Cookie must have a domain and a path set.');
  625. $client = new Client();
  626. $cookie = new Cookie('foo', '', null, '/', '');
  627. $this->assertFalse($client->cookies()->has('foo'));
  628. $client->addCookie($cookie);
  629. $this->assertTrue($client->cookies()->has('foo'));
  630. }
  631. /**
  632. * Test addCookie() method without a path.
  633. *
  634. * @return void
  635. */
  636. public function testAddCookieWithoutPath()
  637. {
  638. $this->expectException(\InvalidArgumentException::class);
  639. $this->expectExceptionMessage('Cookie must have a domain and a path set.');
  640. $client = new Client();
  641. $cookie = new Cookie('foo', '', null, '', 'example.com');
  642. $this->assertFalse($client->cookies()->has('foo'));
  643. $client->addCookie($cookie);
  644. $this->assertTrue($client->cookies()->has('foo'));
  645. }
  646. /**
  647. * test head request with querystring data
  648. *
  649. * @return void
  650. */
  651. public function testHeadQuerystring()
  652. {
  653. $response = new Response();
  654. $mock = $this->getMockBuilder('Cake\Http\Client\Adapter\Stream')
  655. ->setMethods(['send'])
  656. ->getMock();
  657. $mock->expects($this->once())
  658. ->method('send')
  659. ->with($this->callback(function ($request) {
  660. $this->assertInstanceOf('Cake\Http\Client\Request', $request);
  661. $this->assertEquals(Request::METHOD_HEAD, $request->getMethod());
  662. $this->assertEquals('http://cakephp.org/search?q=hi+there', '' . $request->getUri());
  663. return true;
  664. }))
  665. ->will($this->returnValue([$response]));
  666. $http = new Client([
  667. 'host' => 'cakephp.org',
  668. 'adapter' => $mock
  669. ]);
  670. $result = $http->head('/search', [
  671. 'q' => 'hi there',
  672. ]);
  673. $this->assertSame($result, $response);
  674. }
  675. /**
  676. * test redirects
  677. *
  678. * @return void
  679. */
  680. public function testRedirects()
  681. {
  682. $url = 'http://cakephp.org';
  683. $adapter = $this->getMockBuilder(Client\Adapter\Stream::class)
  684. ->setMethods(['send'])
  685. ->getMock();
  686. $redirect = new Response([
  687. 'HTTP/1.0 301',
  688. 'Location: http://cakephp.org/redirect1?foo=bar',
  689. 'Set-Cookie: redirect1=true;path=/',
  690. ]);
  691. $adapter->expects($this->at(0))
  692. ->method('send')
  693. ->with(
  694. $this->callback(function ($request) use ($url) {
  695. $this->assertInstanceOf(Request::class, $request);
  696. $this->assertEquals($url, $request->getUri());
  697. return true;
  698. }),
  699. $this->callback(function ($options) {
  700. $this->assertArrayNotHasKey('redirect', $options);
  701. return true;
  702. })
  703. )
  704. ->willReturn([$redirect]);
  705. $redirect2 = new Response([
  706. 'HTTP/1.0 301',
  707. 'Location: /redirect2#foo',
  708. 'Set-Cookie: redirect2=true;path=/',
  709. ]);
  710. $adapter->expects($this->at(1))
  711. ->method('send')
  712. ->with(
  713. $this->callback(function ($request) use ($url) {
  714. $this->assertInstanceOf(Request::class, $request);
  715. $this->assertEquals($url . '/redirect1?foo=bar', $request->getUri());
  716. return true;
  717. }),
  718. $this->callback(function ($options) {
  719. $this->assertArrayNotHasKey('redirect', $options);
  720. return true;
  721. })
  722. )
  723. ->willReturn([$redirect2]);
  724. $response = new Response([
  725. 'HTTP/1.0 200'
  726. ]);
  727. $adapter->expects($this->at(2))
  728. ->method('send')
  729. ->with($this->callback(function ($request) use ($url) {
  730. $this->assertInstanceOf(Request::class, $request);
  731. $this->assertEquals($url . '/redirect2#foo', $request->getUri());
  732. return true;
  733. }))
  734. ->willReturn([$response]);
  735. $client = new Client([
  736. 'adapter' => $adapter
  737. ]);
  738. $result = $client->send(new Request($url), [
  739. 'redirect' => 10
  740. ]);
  741. $this->assertInstanceOf(Response::class, $result);
  742. $this->assertTrue($result->isOk());
  743. $cookies = $client->cookies();
  744. $this->assertTrue($cookies->has('redirect1'));
  745. $this->assertTrue($cookies->has('redirect2'));
  746. }
  747. }