HttpClientTestCase.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Contracts\HttpClient\Test;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
  13. use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
  14. use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
  15. use Symfony\Contracts\HttpClient\HttpClientInterface;
  16. /**
  17. * A reference test suite for HttpClientInterface implementations.
  18. *
  19. * @experimental in 1.1
  20. */
  21. abstract class HttpClientTestCase extends TestCase
  22. {
  23. private static $server;
  24. public static function setUpBeforeClass()
  25. {
  26. TestHttpServer::start();
  27. }
  28. abstract protected function getHttpClient(string $testCase): HttpClientInterface;
  29. public function testGetRequest()
  30. {
  31. $client = $this->getHttpClient(__FUNCTION__);
  32. $response = $client->request('GET', 'http://localhost:8057', [
  33. 'headers' => ['Foo' => 'baR'],
  34. 'user_data' => $data = new \stdClass(),
  35. ]);
  36. $this->assertSame([], $response->getInfo('response_headers'));
  37. $this->assertSame($data, $response->getInfo()['user_data']);
  38. $this->assertSame(200, $response->getStatusCode());
  39. $info = $response->getInfo();
  40. $this->assertNull($info['error']);
  41. $this->assertSame(0, $info['redirect_count']);
  42. $this->assertSame('HTTP/1.1 200 OK', $info['response_headers'][0]);
  43. $this->assertSame('Host: localhost:8057', $info['response_headers'][1]);
  44. $this->assertSame('http://localhost:8057/', $info['url']);
  45. $headers = $response->getHeaders();
  46. $this->assertSame('localhost:8057', $headers['host'][0]);
  47. $this->assertSame(['application/json'], $headers['content-type']);
  48. $body = json_decode($response->getContent(), true);
  49. $this->assertSame($body, $response->toArray());
  50. $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']);
  51. $this->assertSame('/', $body['REQUEST_URI']);
  52. $this->assertSame('GET', $body['REQUEST_METHOD']);
  53. $this->assertSame('localhost:8057', $body['HTTP_HOST']);
  54. $this->assertSame('baR', $body['HTTP_FOO']);
  55. $response = $client->request('GET', 'http://localhost:8057/length-broken');
  56. $this->expectException(TransportExceptionInterface::class);
  57. $response->getContent();
  58. }
  59. public function testNonBufferedGetRequest()
  60. {
  61. $client = $this->getHttpClient(__FUNCTION__);
  62. $response = $client->request('GET', 'http://localhost:8057', [
  63. 'buffer' => false,
  64. 'headers' => ['Foo' => 'baR'],
  65. ]);
  66. $body = $response->toArray();
  67. $this->assertSame('baR', $body['HTTP_FOO']);
  68. $this->expectException(TransportExceptionInterface::class);
  69. $response->getContent();
  70. }
  71. public function testUnsupportedOption()
  72. {
  73. $client = $this->getHttpClient(__FUNCTION__);
  74. $this->expectException(\InvalidArgumentException::class);
  75. $client->request('GET', 'http://localhost:8057', [
  76. 'capture_peer_cert' => 1.0,
  77. ]);
  78. }
  79. public function testHttpVersion()
  80. {
  81. $client = $this->getHttpClient(__FUNCTION__);
  82. $response = $client->request('GET', 'http://localhost:8057', [
  83. 'http_version' => 1.0,
  84. ]);
  85. $this->assertSame(200, $response->getStatusCode());
  86. $this->assertSame('HTTP/1.0 200 OK', $response->getInfo('response_headers')[0]);
  87. $body = $response->toArray();
  88. $this->assertSame('HTTP/1.0', $body['SERVER_PROTOCOL']);
  89. $this->assertSame('GET', $body['REQUEST_METHOD']);
  90. $this->assertSame('/', $body['REQUEST_URI']);
  91. }
  92. public function testChunkedEncoding()
  93. {
  94. $client = $this->getHttpClient(__FUNCTION__);
  95. $response = $client->request('GET', 'http://localhost:8057/chunked');
  96. $this->assertSame(['chunked'], $response->getHeaders()['transfer-encoding']);
  97. $this->assertSame('Symfony is awesome!', $response->getContent());
  98. $response = $client->request('GET', 'http://localhost:8057/chunked-broken');
  99. $this->expectException(TransportExceptionInterface::class);
  100. $response->getContent();
  101. }
  102. public function testClientError()
  103. {
  104. $client = $this->getHttpClient(__FUNCTION__);
  105. $response = $client->request('GET', 'http://localhost:8057/404');
  106. $client->stream($response)->valid();
  107. $this->assertSame(404, $response->getInfo('http_code'));
  108. try {
  109. $response->getHeaders();
  110. $this->fail(ClientExceptionInterface::class.' expected');
  111. } catch (ClientExceptionInterface $e) {
  112. }
  113. try {
  114. $response->getContent();
  115. $this->fail(ClientExceptionInterface::class.' expected');
  116. } catch (ClientExceptionInterface $e) {
  117. }
  118. $this->assertSame(404, $response->getStatusCode());
  119. $this->assertSame(['application/json'], $response->getHeaders(false)['content-type']);
  120. $this->assertNotEmpty($response->getContent(false));
  121. }
  122. public function testIgnoreErrors()
  123. {
  124. $client = $this->getHttpClient(__FUNCTION__);
  125. $response = $client->request('GET', 'http://localhost:8057/404');
  126. $this->assertSame(404, $response->getStatusCode());
  127. }
  128. public function testDnsError()
  129. {
  130. $client = $this->getHttpClient(__FUNCTION__);
  131. $response = $client->request('GET', 'http://localhost:8057/301/bad-tld');
  132. try {
  133. $response->getStatusCode();
  134. $this->fail(TransportExceptionInterface::class.' expected');
  135. } catch (TransportExceptionInterface $e) {
  136. $this->addToAssertionCount(1);
  137. }
  138. try {
  139. $response->getStatusCode();
  140. $this->fail(TransportExceptionInterface::class.' still expected');
  141. } catch (TransportExceptionInterface $e) {
  142. $this->addToAssertionCount(1);
  143. }
  144. $response = $client->request('GET', 'http://localhost:8057/301/bad-tld');
  145. try {
  146. foreach ($client->stream($response) as $r => $chunk) {
  147. }
  148. $this->fail(TransportExceptionInterface::class.' expected');
  149. } catch (TransportExceptionInterface $e) {
  150. $this->addToAssertionCount(1);
  151. }
  152. $this->assertSame($response, $r);
  153. $this->assertNotNull($chunk->getError());
  154. $this->expectException(TransportExceptionInterface::class);
  155. foreach ($client->stream($response) as $chunk) {
  156. }
  157. }
  158. public function testInlineAuth()
  159. {
  160. $client = $this->getHttpClient(__FUNCTION__);
  161. $response = $client->request('GET', 'http://foo:bar%3Dbar@localhost:8057');
  162. $body = $response->toArray();
  163. $this->assertSame('foo', $body['PHP_AUTH_USER']);
  164. $this->assertSame('bar=bar', $body['PHP_AUTH_PW']);
  165. }
  166. public function testBadRequestBody()
  167. {
  168. $client = $this->getHttpClient(__FUNCTION__);
  169. $this->expectException(TransportExceptionInterface::class);
  170. $response = $client->request('POST', 'http://localhost:8057/', [
  171. 'body' => function () { yield []; },
  172. ]);
  173. $response->getStatusCode();
  174. }
  175. public function testRedirects()
  176. {
  177. $client = $this->getHttpClient(__FUNCTION__);
  178. $response = $client->request('POST', 'http://localhost:8057/301', [
  179. 'auth_basic' => 'foo:bar',
  180. 'body' => function () {
  181. yield 'foo=bar';
  182. },
  183. ]);
  184. $body = $response->toArray();
  185. $this->assertSame('GET', $body['REQUEST_METHOD']);
  186. $this->assertSame('Basic Zm9vOmJhcg==', $body['HTTP_AUTHORIZATION']);
  187. $this->assertSame('http://localhost:8057/', $response->getInfo('url'));
  188. $this->assertSame(2, $response->getInfo('redirect_count'));
  189. $this->assertNull($response->getInfo('redirect_url'));
  190. $expected = [
  191. 'HTTP/1.1 301 Moved Permanently',
  192. 'Location: http://127.0.0.1:8057/302',
  193. 'Content-Type: application/json',
  194. 'HTTP/1.1 302 Found',
  195. 'Location: http://localhost:8057/',
  196. 'Content-Type: application/json',
  197. 'HTTP/1.1 200 OK',
  198. 'Content-Type: application/json',
  199. ];
  200. $filteredHeaders = array_values(array_filter($response->getInfo('response_headers'), function ($h) {
  201. return \in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true) && 'Content-Encoding: gzip' !== $h;
  202. }));
  203. $this->assertSame($expected, $filteredHeaders);
  204. }
  205. public function testRelativeRedirects()
  206. {
  207. $client = $this->getHttpClient(__FUNCTION__);
  208. $response = $client->request('GET', 'http://localhost:8057/302/relative');
  209. $body = $response->toArray();
  210. $this->assertSame('/', $body['REQUEST_URI']);
  211. $this->assertNull($response->getInfo('redirect_url'));
  212. $response = $client->request('GET', 'http://localhost:8057/302/relative', [
  213. 'max_redirects' => 0,
  214. ]);
  215. $this->assertSame(302, $response->getStatusCode());
  216. $this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url'));
  217. }
  218. public function testRedirect307()
  219. {
  220. $client = $this->getHttpClient(__FUNCTION__);
  221. $response = $client->request('POST', 'http://localhost:8057/307', [
  222. 'body' => function () {
  223. yield 'foo=bar';
  224. },
  225. 'max_redirects' => 0,
  226. ]);
  227. $this->assertSame(307, $response->getStatusCode());
  228. $response = $client->request('POST', 'http://localhost:8057/307', [
  229. 'body' => 'foo=bar',
  230. ]);
  231. $body = $response->toArray();
  232. $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $body);
  233. }
  234. public function testMaxRedirects()
  235. {
  236. $client = $this->getHttpClient(__FUNCTION__);
  237. $response = $client->request('GET', 'http://localhost:8057/301', [
  238. 'max_redirects' => 1,
  239. 'auth_basic' => 'foo:bar',
  240. ]);
  241. try {
  242. $response->getHeaders();
  243. $this->fail(RedirectionExceptionInterface::class.' expected');
  244. } catch (RedirectionExceptionInterface $e) {
  245. }
  246. $this->assertSame(302, $response->getStatusCode());
  247. $this->assertSame(1, $response->getInfo('redirect_count'));
  248. $this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url'));
  249. $expected = [
  250. 'HTTP/1.1 301 Moved Permanently',
  251. 'Location: http://127.0.0.1:8057/302',
  252. 'Content-Type: application/json',
  253. 'HTTP/1.1 302 Found',
  254. 'Location: http://localhost:8057/',
  255. 'Content-Type: application/json',
  256. ];
  257. $filteredHeaders = array_values(array_filter($response->getInfo('response_headers'), function ($h) {
  258. return \in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true);
  259. }));
  260. $this->assertSame($expected, $filteredHeaders);
  261. }
  262. public function testStream()
  263. {
  264. $client = $this->getHttpClient(__FUNCTION__);
  265. $response = $client->request('GET', 'http://localhost:8057');
  266. $chunks = $client->stream($response);
  267. $result = [];
  268. foreach ($chunks as $r => $chunk) {
  269. if ($chunk->isTimeout()) {
  270. $result[] = 't';
  271. } elseif ($chunk->isLast()) {
  272. $result[] = 'l';
  273. } elseif ($chunk->isFirst()) {
  274. $result[] = 'f';
  275. }
  276. }
  277. $this->assertSame($response, $r);
  278. $this->assertSame(['f', 'l'], $result);
  279. $chunk = null;
  280. $i = 0;
  281. foreach ($client->stream($response) as $chunk) {
  282. ++$i;
  283. }
  284. $this->assertSame(1, $i);
  285. $this->assertTrue($chunk->isLast());
  286. }
  287. public function testAddToStream()
  288. {
  289. $client = $this->getHttpClient(__FUNCTION__);
  290. $r1 = $client->request('GET', 'http://localhost:8057');
  291. $completed = [];
  292. $pool = [$r1];
  293. while ($pool) {
  294. $chunks = $client->stream($pool);
  295. $pool = [];
  296. foreach ($chunks as $r => $chunk) {
  297. if (!$chunk->isLast()) {
  298. continue;
  299. }
  300. if ($r1 === $r) {
  301. $r2 = $client->request('GET', 'http://localhost:8057');
  302. $pool[] = $r2;
  303. }
  304. $completed[] = $r;
  305. }
  306. }
  307. $this->assertSame([$r1, $r2], $completed);
  308. }
  309. public function testCompleteTypeError()
  310. {
  311. $client = $this->getHttpClient(__FUNCTION__);
  312. $this->expectException(\TypeError::class);
  313. $client->stream(123);
  314. }
  315. public function testOnProgress()
  316. {
  317. $client = $this->getHttpClient(__FUNCTION__);
  318. $response = $client->request('POST', 'http://localhost:8057/post', [
  319. 'headers' => ['Content-Length' => 14],
  320. 'body' => 'foo=0123456789',
  321. 'on_progress' => function (...$state) use (&$steps) { $steps[] = $state; },
  322. ]);
  323. $body = $response->toArray();
  324. $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body);
  325. $this->assertSame([0, 0], \array_slice($steps[0], 0, 2));
  326. $lastStep = \array_slice($steps, -1)[0];
  327. $this->assertSame([57, 57], \array_slice($lastStep, 0, 2));
  328. $this->assertSame('http://localhost:8057/post', $steps[0][2]['url']);
  329. }
  330. public function testPostJson()
  331. {
  332. $client = $this->getHttpClient(__FUNCTION__);
  333. $response = $client->request('POST', 'http://localhost:8057/post', [
  334. 'json' => ['foo' => 'bar'],
  335. ]);
  336. $body = $response->toArray();
  337. $this->assertContains('json', $body['content-type']);
  338. unset($body['content-type']);
  339. $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $body);
  340. }
  341. public function testPostArray()
  342. {
  343. $client = $this->getHttpClient(__FUNCTION__);
  344. $response = $client->request('POST', 'http://localhost:8057/post', [
  345. 'body' => ['foo' => 'bar'],
  346. ]);
  347. $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $response->toArray());
  348. }
  349. public function testPostResource()
  350. {
  351. $client = $this->getHttpClient(__FUNCTION__);
  352. $h = fopen('php://temp', 'w+');
  353. fwrite($h, 'foo=0123456789');
  354. rewind($h);
  355. $response = $client->request('POST', 'http://localhost:8057/post', [
  356. 'body' => $h,
  357. ]);
  358. $body = $response->toArray();
  359. $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body);
  360. }
  361. public function testPostCallback()
  362. {
  363. $client = $this->getHttpClient(__FUNCTION__);
  364. $response = $client->request('POST', 'http://localhost:8057/post', [
  365. 'body' => function () {
  366. yield 'foo';
  367. yield '';
  368. yield '=';
  369. yield '0123456789';
  370. },
  371. ]);
  372. $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $response->toArray());
  373. }
  374. public function testOnProgressCancel()
  375. {
  376. $client = $this->getHttpClient(__FUNCTION__);
  377. $response = $client->request('GET', 'http://localhost:8057/timeout-body', [
  378. 'on_progress' => function ($dlNow) {
  379. if (0 < $dlNow) {
  380. throw new \Exception('Aborting the request');
  381. }
  382. },
  383. ]);
  384. try {
  385. foreach ($client->stream([$response]) as $chunk) {
  386. }
  387. $this->fail(ClientExceptionInterface::class.' expected');
  388. } catch (TransportExceptionInterface $e) {
  389. $this->assertSame('Aborting the request', $e->getPrevious()->getMessage());
  390. }
  391. $this->assertNotNull($response->getInfo('error'));
  392. $this->expectException(TransportExceptionInterface::class);
  393. $response->getContent();
  394. }
  395. public function testOnProgressError()
  396. {
  397. $client = $this->getHttpClient(__FUNCTION__);
  398. $response = $client->request('GET', 'http://localhost:8057/timeout-body', [
  399. 'on_progress' => function ($dlNow) {
  400. if (0 < $dlNow) {
  401. throw new \Error('BUG');
  402. }
  403. },
  404. ]);
  405. try {
  406. foreach ($client->stream([$response]) as $chunk) {
  407. }
  408. $this->fail('Error expected');
  409. } catch (\Error $e) {
  410. $this->assertSame('BUG', $e->getMessage());
  411. }
  412. $this->assertNotNull($response->getInfo('error'));
  413. $this->expectException(TransportExceptionInterface::class);
  414. $response->getContent();
  415. }
  416. public function testResolve()
  417. {
  418. $client = $this->getHttpClient(__FUNCTION__);
  419. $response = $client->request('GET', 'http://symfony.com:8057/', [
  420. 'resolve' => ['symfony.com' => '127.0.0.1'],
  421. ]);
  422. $this->assertSame(200, $response->getStatusCode());
  423. $this->assertSame(200, $client->request('GET', 'http://symfony.com:8057/')->getStatusCode());
  424. $response = null;
  425. $this->expectException(TransportExceptionInterface::class);
  426. $client->request('GET', 'http://symfony.com:8057/', ['timeout' => 3]);
  427. }
  428. public function testTimeoutOnAccess()
  429. {
  430. $client = $this->getHttpClient(__FUNCTION__);
  431. $response = $client->request('GET', 'http://localhost:8057/timeout-header', [
  432. 'timeout' => 0.1,
  433. ]);
  434. $this->expectException(TransportExceptionInterface::class);
  435. $response->getHeaders();
  436. }
  437. public function testTimeoutOnStream()
  438. {
  439. usleep(300000); // wait for the previous test to release the server
  440. $client = $this->getHttpClient(__FUNCTION__);
  441. $response = $client->request('GET', 'http://localhost:8057/timeout-body');
  442. $this->assertSame(200, $response->getStatusCode());
  443. $chunks = $client->stream([$response], 0.2);
  444. $result = [];
  445. foreach ($chunks as $r => $chunk) {
  446. if ($chunk->isTimeout()) {
  447. $result[] = 't';
  448. } else {
  449. $result[] = $chunk->getContent();
  450. }
  451. }
  452. $this->assertSame(['<1>', 't'], $result);
  453. $chunks = $client->stream([$response]);
  454. foreach ($chunks as $r => $chunk) {
  455. $this->assertSame('<2>', $chunk->getContent());
  456. $this->assertSame('<1><2>', $r->getContent());
  457. return;
  458. }
  459. $this->fail('The response should have completed');
  460. }
  461. public function testUncheckedTimeoutThrows()
  462. {
  463. $client = $this->getHttpClient(__FUNCTION__);
  464. $response = $client->request('GET', 'http://localhost:8057/timeout-body');
  465. $chunks = $client->stream([$response], 0.1);
  466. $this->expectException(TransportExceptionInterface::class);
  467. foreach ($chunks as $r => $chunk) {
  468. }
  469. }
  470. public function testDestruct()
  471. {
  472. $client = $this->getHttpClient(__FUNCTION__);
  473. $downloaded = 0;
  474. $start = microtime(true);
  475. $client->request('GET', 'http://localhost:8057/timeout-long');
  476. $client = null;
  477. $duration = microtime(true) - $start;
  478. $this->assertGreaterThan(1, $duration);
  479. $this->assertLessThan(3, $duration);
  480. }
  481. public function testProxy()
  482. {
  483. $client = $this->getHttpClient(__FUNCTION__);
  484. $response = $client->request('GET', 'http://localhost:8057/', [
  485. 'proxy' => 'http://localhost:8057',
  486. ]);
  487. $body = $response->toArray();
  488. $this->assertSame('localhost:8057', $body['HTTP_HOST']);
  489. $this->assertRegexp('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']);
  490. $response = $client->request('GET', 'http://localhost:8057/', [
  491. 'proxy' => 'http://foo:b%3Dar@localhost:8057',
  492. ]);
  493. $body = $response->toArray();
  494. $this->assertSame('Basic Zm9vOmI9YXI=', $body['HTTP_PROXY_AUTHORIZATION']);
  495. }
  496. public function testNoProxy()
  497. {
  498. putenv('no_proxy='.$_SERVER['no_proxy'] = 'example.com, localhost');
  499. try {
  500. $client = $this->getHttpClient(__FUNCTION__);
  501. $response = $client->request('GET', 'http://localhost:8057/', [
  502. 'proxy' => 'http://localhost:8057',
  503. ]);
  504. $body = $response->toArray();
  505. $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']);
  506. $this->assertSame('/', $body['REQUEST_URI']);
  507. $this->assertSame('GET', $body['REQUEST_METHOD']);
  508. } finally {
  509. putenv('no_proxy');
  510. unset($_SERVER['no_proxy']);
  511. }
  512. }
  513. /**
  514. * @requires extension zlib
  515. */
  516. public function testAutoEncodingRequest()
  517. {
  518. $client = $this->getHttpClient(__FUNCTION__);
  519. $response = $client->request('GET', 'http://localhost:8057');
  520. $this->assertSame(200, $response->getStatusCode());
  521. $headers = $response->getHeaders();
  522. $this->assertSame(['Accept-Encoding'], $headers['vary']);
  523. $this->assertContains('gzip', $headers['content-encoding'][0]);
  524. $body = $response->toArray();
  525. $this->assertContains('gzip', $body['HTTP_ACCEPT_ENCODING']);
  526. }
  527. public function testBaseUri()
  528. {
  529. $client = $this->getHttpClient(__FUNCTION__);
  530. $response = $client->request('GET', '../404', [
  531. 'base_uri' => 'http://localhost:8057/abc/',
  532. ]);
  533. $this->assertSame(404, $response->getStatusCode());
  534. $this->assertSame(['application/json'], $response->getHeaders(false)['content-type']);
  535. }
  536. public function testQuery()
  537. {
  538. $client = $this->getHttpClient(__FUNCTION__);
  539. $response = $client->request('GET', 'http://localhost:8057/?a=a', [
  540. 'query' => ['b' => 'b'],
  541. ]);
  542. $body = $response->toArray();
  543. $this->assertSame('GET', $body['REQUEST_METHOD']);
  544. $this->assertSame('/?a=a&b=b', $body['REQUEST_URI']);
  545. }
  546. /**
  547. * @requires extension zlib
  548. */
  549. public function testUserlandEncodingRequest()
  550. {
  551. $client = $this->getHttpClient(__FUNCTION__);
  552. $response = $client->request('GET', 'http://localhost:8057', [
  553. 'headers' => ['Accept-Encoding' => 'gzip'],
  554. ]);
  555. $headers = $response->getHeaders();
  556. $this->assertSame(['Accept-Encoding'], $headers['vary']);
  557. $this->assertContains('gzip', $headers['content-encoding'][0]);
  558. $body = $response->getContent();
  559. $this->assertSame("\x1F", $body[0]);
  560. $body = json_decode(gzdecode($body), true);
  561. $this->assertSame('gzip', $body['HTTP_ACCEPT_ENCODING']);
  562. }
  563. /**
  564. * @requires extension zlib
  565. */
  566. public function testGzipBroken()
  567. {
  568. $client = $this->getHttpClient(__FUNCTION__);
  569. $response = $client->request('GET', 'http://localhost:8057/gzip-broken');
  570. $this->expectException(TransportExceptionInterface::class);
  571. $response->getContent();
  572. }
  573. }