MessageTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <?php
  2. declare(strict_types=1);
  3. namespace GuzzleHttp\Tests\Psr7;
  4. use GuzzleHttp\Psr7;
  5. use GuzzleHttp\Psr7\FnStream;
  6. use PHPUnit\Framework\TestCase;
  7. class MessageTest extends TestCase
  8. {
  9. public function testConvertsRequestsToStrings(): void
  10. {
  11. $request = new Psr7\Request('PUT', 'http://foo.com/hi?123', [
  12. 'Baz' => 'bar',
  13. 'Qux' => 'ipsum',
  14. ], 'hello', '1.0');
  15. self::assertSame(
  16. "PUT /hi?123 HTTP/1.0\r\nHost: foo.com\r\nBaz: bar\r\nQux: ipsum\r\n\r\nhello",
  17. Psr7\Message::toString($request)
  18. );
  19. }
  20. public function testConvertsResponsesToStrings(): void
  21. {
  22. $response = new Psr7\Response(200, [
  23. 'Baz' => 'bar',
  24. 'Qux' => 'ipsum',
  25. ], 'hello', '1.0', 'FOO');
  26. self::assertSame(
  27. "HTTP/1.0 200 FOO\r\nBaz: bar\r\nQux: ipsum\r\n\r\nhello",
  28. Psr7\Message::toString($response)
  29. );
  30. }
  31. public function testCorrectlyRendersSetCookieHeadersToString(): void
  32. {
  33. $response = new Psr7\Response(200, [
  34. 'Set-Cookie' => ['bar', 'baz', 'qux'],
  35. ], 'hello', '1.0', 'FOO');
  36. self::assertSame(
  37. "HTTP/1.0 200 FOO\r\nSet-Cookie: bar\r\nSet-Cookie: baz\r\nSet-Cookie: qux\r\n\r\nhello",
  38. Psr7\Message::toString($response)
  39. );
  40. }
  41. public function testRewindsBody(): void
  42. {
  43. $body = Psr7\Utils::streamFor('abc');
  44. $res = new Psr7\Response(200, [], $body);
  45. Psr7\Message::rewindBody($res);
  46. self::assertSame(0, $body->tell());
  47. $body->rewind();
  48. Psr7\Message::rewindBody($res);
  49. self::assertSame(0, $body->tell());
  50. }
  51. public function testThrowsWhenBodyCannotBeRewound(): void
  52. {
  53. $body = Psr7\Utils::streamFor('abc');
  54. $body->read(1);
  55. $body = FnStream::decorate($body, [
  56. 'rewind' => function (): void {
  57. throw new \RuntimeException('a');
  58. },
  59. ]);
  60. $res = new Psr7\Response(200, [], $body);
  61. $this->expectException(\RuntimeException::class);
  62. Psr7\Message::rewindBody($res);
  63. }
  64. public function testParsesRequestMessages(): void
  65. {
  66. $req = "GET /abc HTTP/1.0\r\nHost: foo.com\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n\r\nTest";
  67. $request = Psr7\Message::parseRequest($req);
  68. self::assertSame('GET', $request->getMethod());
  69. self::assertSame('/abc', $request->getRequestTarget());
  70. self::assertSame('1.0', $request->getProtocolVersion());
  71. self::assertSame('foo.com', $request->getHeaderLine('Host'));
  72. self::assertSame('Bar', $request->getHeaderLine('Foo'));
  73. self::assertSame('Bam, Qux', $request->getHeaderLine('Baz'));
  74. self::assertSame('Test', (string) $request->getBody());
  75. self::assertSame('http://foo.com/abc', (string) $request->getUri());
  76. }
  77. public function testParsesRequestMessagesWithHttpsScheme(): void
  78. {
  79. $req = "PUT /abc?baz=bar HTTP/1.1\r\nHost: foo.com:443\r\n\r\n";
  80. $request = Psr7\Message::parseRequest($req);
  81. self::assertSame('PUT', $request->getMethod());
  82. self::assertSame('/abc?baz=bar', $request->getRequestTarget());
  83. self::assertSame('1.1', $request->getProtocolVersion());
  84. self::assertSame('foo.com:443', $request->getHeaderLine('Host'));
  85. self::assertSame('', (string) $request->getBody());
  86. self::assertSame('https://foo.com/abc?baz=bar', (string) $request->getUri());
  87. }
  88. public function testParsesRequestMessagesWithUriWhenHostIsNotFirst(): void
  89. {
  90. $req = "PUT / HTTP/1.1\r\nFoo: Bar\r\nHost: foo.com\r\n\r\n";
  91. $request = Psr7\Message::parseRequest($req);
  92. self::assertSame('PUT', $request->getMethod());
  93. self::assertSame('/', $request->getRequestTarget());
  94. self::assertSame('http://foo.com/', (string) $request->getUri());
  95. }
  96. public function testParsesRequestMessagesWithFullUri(): void
  97. {
  98. $req = "GET https://www.google.com:443/search?q=foobar HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
  99. $request = Psr7\Message::parseRequest($req);
  100. self::assertSame('GET', $request->getMethod());
  101. self::assertSame('https://www.google.com:443/search?q=foobar', $request->getRequestTarget());
  102. self::assertSame('1.1', $request->getProtocolVersion());
  103. self::assertSame('www.google.com', $request->getHeaderLine('Host'));
  104. self::assertSame('', (string) $request->getBody());
  105. self::assertSame('https://www.google.com/search?q=foobar', (string) $request->getUri());
  106. }
  107. public function testParsesRequestMessagesWithCustomMethod(): void
  108. {
  109. $req = "GET_DATA / HTTP/1.1\r\nFoo: Bar\r\nHost: foo.com\r\n\r\n";
  110. $request = Psr7\Message::parseRequest($req);
  111. self::assertSame('GET_DATA', $request->getMethod());
  112. }
  113. public function testParsesRequestMessagesWithNumericHeader(): void
  114. {
  115. $req = "GET /abc HTTP/1.0\r\nHost: foo.com\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n123: 456\r\n\r\nTest";
  116. $request = Psr7\Message::parseRequest($req);
  117. self::assertSame('GET', $request->getMethod());
  118. self::assertSame('/abc', $request->getRequestTarget());
  119. self::assertSame('1.0', $request->getProtocolVersion());
  120. self::assertSame('foo.com', $request->getHeaderLine('Host'));
  121. self::assertSame('Bar', $request->getHeaderLine('Foo'));
  122. self::assertSame('Bam, Qux', $request->getHeaderLine('Baz'));
  123. self::assertSame('456', $request->getHeaderLine('123'));
  124. self::assertSame('Test', (string) $request->getBody());
  125. self::assertSame('http://foo.com/abc', (string) $request->getUri());
  126. }
  127. public function testParsesRequestMessagesWithFoldedHeadersOnHttp10(): void
  128. {
  129. $req = "PUT / HTTP/1.0\r\nFoo: Bar\r\n Bam\r\n\r\n";
  130. $request = Psr7\Message::parseRequest($req);
  131. self::assertSame('PUT', $request->getMethod());
  132. self::assertSame('/', $request->getRequestTarget());
  133. self::assertSame('Bar Bam', $request->getHeaderLine('Foo'));
  134. }
  135. public function testRequestParsingFailsWithFoldedHeadersOnHttp11(): void
  136. {
  137. $this->expectException(\InvalidArgumentException::class);
  138. $this->expectExceptionMessage('Invalid header syntax: Obsolete line folding');
  139. Psr7\Message::parseResponse("GET_DATA / HTTP/1.1\r\nFoo: Bar\r\n Biz: Bam\r\n\r\n");
  140. }
  141. public function testParsesRequestMessagesWhenHeaderDelimiterIsOnlyALineFeed(): void
  142. {
  143. $req = "PUT / HTTP/1.0\nFoo: Bar\nBaz: Bam\n\n";
  144. $request = Psr7\Message::parseRequest($req);
  145. self::assertSame('PUT', $request->getMethod());
  146. self::assertSame('/', $request->getRequestTarget());
  147. self::assertSame('Bar', $request->getHeaderLine('Foo'));
  148. self::assertSame('Bam', $request->getHeaderLine('Baz'));
  149. }
  150. public function testValidatesRequestMessages(): void
  151. {
  152. $this->expectException(\InvalidArgumentException::class);
  153. Psr7\Message::parseRequest("HTTP/1.1 200 OK\r\n\r\n");
  154. }
  155. public function testParsesResponseMessages(): void
  156. {
  157. $res = "HTTP/1.0 200 OK\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n\r\nTest";
  158. $response = Psr7\Message::parseResponse($res);
  159. self::assertSame(200, $response->getStatusCode());
  160. self::assertSame('OK', $response->getReasonPhrase());
  161. self::assertSame('1.0', $response->getProtocolVersion());
  162. self::assertSame('Bar', $response->getHeaderLine('Foo'));
  163. self::assertSame('Bam, Qux', $response->getHeaderLine('Baz'));
  164. self::assertSame('Test', (string) $response->getBody());
  165. }
  166. public function testParsesResponseWithoutReason(): void
  167. {
  168. $res = "HTTP/1.0 200\r\nFoo: Bar\r\nBaz: Bam\r\nBaz: Qux\r\n\r\nTest";
  169. $response = Psr7\Message::parseResponse($res);
  170. self::assertSame(200, $response->getStatusCode());
  171. self::assertSame('OK', $response->getReasonPhrase());
  172. self::assertSame('1.0', $response->getProtocolVersion());
  173. self::assertSame('Bar', $response->getHeaderLine('Foo'));
  174. self::assertSame('Bam, Qux', $response->getHeaderLine('Baz'));
  175. self::assertSame('Test', (string) $response->getBody());
  176. }
  177. public function testParsesResponseWithLeadingDelimiter(): void
  178. {
  179. $res = "\r\nHTTP/1.0 200\r\nFoo: Bar\r\n\r\nTest";
  180. $response = Psr7\Message::parseResponse($res);
  181. self::assertSame(200, $response->getStatusCode());
  182. self::assertSame('OK', $response->getReasonPhrase());
  183. self::assertSame('1.0', $response->getProtocolVersion());
  184. self::assertSame('Bar', $response->getHeaderLine('Foo'));
  185. self::assertSame('Test', (string) $response->getBody());
  186. }
  187. public function testParsesResponseWithFoldedHeadersOnHttp10(): void
  188. {
  189. $res = "HTTP/1.0 200\r\nFoo: Bar\r\n Bam\r\n\r\nTest";
  190. $response = Psr7\Message::parseResponse($res);
  191. self::assertSame(200, $response->getStatusCode());
  192. self::assertSame('OK', $response->getReasonPhrase());
  193. self::assertSame('1.0', $response->getProtocolVersion());
  194. self::assertSame('Bar Bam', $response->getHeaderLine('Foo'));
  195. self::assertSame('Test', (string) $response->getBody());
  196. }
  197. public function testResponseParsingFailsWithFoldedHeadersOnHttp11(): void
  198. {
  199. $this->expectException(\InvalidArgumentException::class);
  200. $this->expectExceptionMessage('Invalid header syntax: Obsolete line folding');
  201. Psr7\Message::parseResponse("HTTP/1.1 200\r\nFoo: Bar\r\n Biz: Bam\r\nBaz: Qux\r\n\r\nTest");
  202. }
  203. public function testParsesResponseWhenHeaderDelimiterIsOnlyALineFeed(): void
  204. {
  205. $res = "HTTP/1.0 200\nFoo: Bar\nBaz: Bam\n\nTest\n\nOtherTest";
  206. $response = Psr7\Message::parseResponse($res);
  207. self::assertSame(200, $response->getStatusCode());
  208. self::assertSame('OK', $response->getReasonPhrase());
  209. self::assertSame('1.0', $response->getProtocolVersion());
  210. self::assertSame('Bar', $response->getHeaderLine('Foo'));
  211. self::assertSame('Bam', $response->getHeaderLine('Baz'));
  212. self::assertSame("Test\n\nOtherTest", (string) $response->getBody());
  213. }
  214. public function testResponseParsingFailsWithoutHeaderDelimiter(): void
  215. {
  216. $this->expectException(\InvalidArgumentException::class);
  217. $this->expectExceptionMessage('Invalid message: Missing header delimiter');
  218. Psr7\Message::parseResponse("HTTP/1.0 200\r\nFoo: Bar\r\n Baz: Bam\r\nBaz: Qux\r\n");
  219. }
  220. public function testValidatesResponseMessages(): void
  221. {
  222. $this->expectException(\InvalidArgumentException::class);
  223. Psr7\Message::parseResponse("GET / HTTP/1.1\r\n\r\n");
  224. }
  225. public function testMessageBodySummaryWithSmallBody(): void
  226. {
  227. $message = new Psr7\Response(200, [], 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
  228. self::assertSame('Lorem ipsum dolor sit amet, consectetur adipiscing elit.', Psr7\Message::bodySummary($message));
  229. }
  230. public function testMessageBodySummaryWithLargeBody(): void
  231. {
  232. $message = new Psr7\Response(200, [], 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
  233. self::assertSame('Lorem ipsu (truncated...)', Psr7\Message::bodySummary($message, 10));
  234. }
  235. public function testMessageBodySummaryWithSpecialUTF8Characters(): void
  236. {
  237. $message = new Psr7\Response(200, [], '’é€௵ဪ‱');
  238. self::assertSame('’é€௵ဪ‱', Psr7\Message::bodySummary($message));
  239. }
  240. public function testMessageBodySummaryWithSpecialUTF8CharactersAndLargeBody(): void
  241. {
  242. $message = new Psr7\Response(200, [], '🤦🏾‍♀️');
  243. // The first Unicode codepoint of the body has four bytes.
  244. self::assertNull(Psr7\Message::bodySummary($message, 3));
  245. }
  246. public function testMessageBodySummaryWithEmptyBody(): void
  247. {
  248. $message = new Psr7\Response(200, [], '');
  249. self::assertNull(Psr7\Message::bodySummary($message));
  250. }
  251. public function testMessageBodySummaryNotInitiallyRewound(): void
  252. {
  253. $message = new Psr7\Response(200, [], 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.');
  254. $message->getBody()->read(10);
  255. self::assertSame('Lorem ipsu (truncated...)', Psr7\Message::bodySummary($message, 10));
  256. }
  257. public function testGetResponseBodySummaryOfNonReadableStream(): void
  258. {
  259. $message = new Psr7\Response(500, [], new ReadSeekOnlyStream());
  260. self::assertNull(Psr7\Message::bodySummary($message));
  261. }
  262. }