UriNormalizerTest.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. <?php
  2. declare(strict_types=1);
  3. namespace GuzzleHttp\Tests\Psr7;
  4. use GuzzleHttp\Psr7\Uri;
  5. use GuzzleHttp\Psr7\UriNormalizer;
  6. use PHPUnit\Framework\TestCase;
  7. use Psr\Http\Message\UriInterface;
  8. /**
  9. * @covers \GuzzleHttp\Psr7\UriNormalizer
  10. */
  11. class UriNormalizerTest extends TestCase
  12. {
  13. public function testCapitalizePercentEncoding(): void
  14. {
  15. $actualEncoding = 'a%c2%7A%5eb%25%fa%fA%Fa';
  16. $expectEncoding = 'a%C2%7A%5Eb%25%FA%FA%FA';
  17. $uri = (new Uri())->withPath("/$actualEncoding")->withQuery($actualEncoding);
  18. self::assertSame("/$actualEncoding?$actualEncoding", (string) $uri, 'Not normalized automatically beforehand');
  19. $normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::CAPITALIZE_PERCENT_ENCODING);
  20. self::assertInstanceOf(UriInterface::class, $normalizedUri);
  21. self::assertSame("/$expectEncoding?$expectEncoding", (string) $normalizedUri);
  22. }
  23. /**
  24. * @dataProvider getUnreservedCharacters
  25. */
  26. public function testDecodeUnreservedCharacters(string $char): void
  27. {
  28. $percentEncoded = '%'.bin2hex($char);
  29. // Add encoded reserved characters to test that those are not decoded and include the percent-encoded
  30. // unreserved character both in lower and upper case to test the decoding is case-insensitive.
  31. $encodedChars = $percentEncoded.'%2F%5B'.strtoupper($percentEncoded);
  32. $uri = (new Uri())->withPath("/$encodedChars")->withQuery($encodedChars);
  33. self::assertSame("/$encodedChars?$encodedChars", (string) $uri, 'Not normalized automatically beforehand');
  34. $normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::DECODE_UNRESERVED_CHARACTERS);
  35. self::assertInstanceOf(UriInterface::class, $normalizedUri);
  36. self::assertSame("/$char%2F%5B$char?$char%2F%5B$char", (string) $normalizedUri);
  37. }
  38. public function getUnreservedCharacters(): iterable
  39. {
  40. $unreservedChars = array_merge(range('a', 'z'), range('A', 'Z'), range(0, 9), ['-', '.', '_', '~']);
  41. return array_map(function ($char) {
  42. return [(string) $char];
  43. }, $unreservedChars);
  44. }
  45. /**
  46. * @dataProvider getEmptyPathTestCases
  47. */
  48. public function testConvertEmptyPath($uri, $expected): void
  49. {
  50. $normalizedUri = UriNormalizer::normalize(new Uri($uri), UriNormalizer::CONVERT_EMPTY_PATH);
  51. self::assertInstanceOf(UriInterface::class, $normalizedUri);
  52. self::assertSame($expected, (string) $normalizedUri);
  53. }
  54. public function getEmptyPathTestCases(): iterable
  55. {
  56. return [
  57. ['http://example.org', 'http://example.org/'],
  58. ['https://example.org', 'https://example.org/'],
  59. ['urn://example.org', 'urn://example.org'],
  60. ];
  61. }
  62. public function testRemoveDefaultHost(): void
  63. {
  64. $uri = new Uri('file://localhost/myfile');
  65. $normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DEFAULT_HOST);
  66. self::assertInstanceOf(UriInterface::class, $normalizedUri);
  67. self::assertSame('file:///myfile', (string) $normalizedUri);
  68. }
  69. public function testRemoveDefaultPort(): void
  70. {
  71. $uri = $this->createMock(UriInterface::class);
  72. $uri->expects(self::any())->method('getScheme')->willReturn('http');
  73. $uri->expects(self::any())->method('getPort')->willReturn(80);
  74. $uri->expects(self::once())->method('withPort')->with(null)->willReturn(new Uri('http://example.org'));
  75. $normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DEFAULT_PORT);
  76. self::assertInstanceOf(UriInterface::class, $normalizedUri);
  77. self::assertNull($normalizedUri->getPort());
  78. }
  79. public function testRemoveDotSegments(): void
  80. {
  81. $uri = new Uri('http://example.org/../a/b/../c/./d.html');
  82. $normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DOT_SEGMENTS);
  83. self::assertInstanceOf(UriInterface::class, $normalizedUri);
  84. self::assertSame('http://example.org/a/c/d.html', (string) $normalizedUri);
  85. }
  86. public function testRemoveDotSegmentsOfAbsolutePathReference(): void
  87. {
  88. $uri = new Uri('/../a/b/../c/./d.html');
  89. $normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DOT_SEGMENTS);
  90. self::assertInstanceOf(UriInterface::class, $normalizedUri);
  91. self::assertSame('/a/c/d.html', (string) $normalizedUri);
  92. }
  93. public function testRemoveDotSegmentsOfRelativePathReference(): void
  94. {
  95. $uri = new Uri('../c/./d.html');
  96. $normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DOT_SEGMENTS);
  97. self::assertInstanceOf(UriInterface::class, $normalizedUri);
  98. self::assertSame('../c/./d.html', (string) $normalizedUri);
  99. }
  100. public function testRemoveDuplicateSlashes(): void
  101. {
  102. $uri = new Uri('http://example.org//foo///bar/bam.html');
  103. $normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::REMOVE_DUPLICATE_SLASHES);
  104. self::assertInstanceOf(UriInterface::class, $normalizedUri);
  105. self::assertSame('http://example.org/foo/bar/bam.html', (string) $normalizedUri);
  106. }
  107. public function testSortQueryParameters(): void
  108. {
  109. $uri = new Uri('?lang=en&article=fred');
  110. $normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::SORT_QUERY_PARAMETERS);
  111. self::assertInstanceOf(UriInterface::class, $normalizedUri);
  112. self::assertSame('?article=fred&lang=en', (string) $normalizedUri);
  113. }
  114. public function testSortQueryParametersWithSameKeys(): void
  115. {
  116. $uri = new Uri('?a=b&b=c&a=a&a&b=a&b=b&a=d&a=c');
  117. $normalizedUri = UriNormalizer::normalize($uri, UriNormalizer::SORT_QUERY_PARAMETERS);
  118. self::assertInstanceOf(UriInterface::class, $normalizedUri);
  119. self::assertSame('?a&a=a&a=b&a=c&a=d&b=a&b=b&b=c', (string) $normalizedUri);
  120. }
  121. /**
  122. * @dataProvider getEquivalentTestCases
  123. */
  124. public function testIsEquivalent(string $uri1, string $uri2, bool $expected): void
  125. {
  126. $equivalent = UriNormalizer::isEquivalent(new Uri($uri1), new Uri($uri2));
  127. self::assertSame($expected, $equivalent);
  128. }
  129. public function getEquivalentTestCases(): iterable
  130. {
  131. return [
  132. ['http://example.org', 'http://example.org', true],
  133. ['hTTp://eXaMpLe.org', 'http://example.org', true],
  134. ['http://example.org/path?#', 'http://example.org/path', true],
  135. ['http://example.org:80', 'http://example.org/', true],
  136. ['http://example.org/../a/.././p%61th?%7a=%5e', 'http://example.org/path?z=%5E', true],
  137. ['https://example.org/', 'http://example.org/', false],
  138. ['https://example.org/', '//example.org/', false],
  139. ['//example.org/', '//example.org/', true],
  140. ['file:/myfile', 'file:///myfile', true],
  141. ['file:///myfile', 'file://localhost/myfile', true],
  142. ];
  143. }
  144. }