uri_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "chromeos/printing/uri_unittest.h"
  5. #include "base/strings/string_number_conversions.h"
  6. #include "chromeos/printing/uri.h"
  7. #include "testing/gmock/include/gmock/gmock.h"
  8. #include "testing/gtest/include/gtest/gtest.h"
  9. namespace chromeos {
  10. namespace uri_unittest {
  11. UriComponents::UriComponents() = default;
  12. UriComponents::UriComponents(const UriComponents&) = default;
  13. UriComponents::UriComponents(
  14. const std::string& scheme,
  15. const std::string& userinfo,
  16. const std::string& host,
  17. int port,
  18. const std::vector<std::string>& path,
  19. const std::vector<std::pair<std::string, std::string>>& query,
  20. const std::string& fragment)
  21. : scheme(scheme),
  22. userinfo(userinfo),
  23. host(host),
  24. port(port),
  25. path(path),
  26. query(query),
  27. fragment(fragment) {}
  28. UriComponents::~UriComponents() = default;
  29. } // namespace uri_unittest
  30. namespace {
  31. using UriComponents = uri_unittest::UriComponents;
  32. // Verifies that |components| set by Set*() methods produces given
  33. // |normalized_uri|. Runs also consistency test on the created Uri object.
  34. void TestBuilder(const UriComponents& components,
  35. const std::string& normalized_uri) {
  36. Uri uri;
  37. uri.SetFragment(components.fragment);
  38. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  39. uri.SetHost(components.host);
  40. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  41. uri.SetPath(components.path);
  42. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  43. uri.SetPort(components.port);
  44. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  45. uri.SetQuery(components.query);
  46. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  47. uri.SetScheme(components.scheme);
  48. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  49. uri.SetUserinfo(components.userinfo);
  50. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  51. // Check URI.
  52. EXPECT_EQ(uri.GetNormalized(false), normalized_uri);
  53. }
  54. // Verifies that |input_uri| set as parameter in Uri constructor is parsed
  55. // as |components|. Runs also consistency test on the created Uri object.
  56. void TestParser(const std::string& input_uri, const UriComponents& components) {
  57. Uri uri(input_uri);
  58. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  59. // Check components values.
  60. EXPECT_EQ(uri.GetScheme(), components.scheme);
  61. EXPECT_EQ(uri.GetUserinfo(), components.userinfo);
  62. EXPECT_EQ(uri.GetHost(), components.host);
  63. EXPECT_EQ(uri.GetPort(), components.port);
  64. EXPECT_EQ(uri.GetPath(), components.path);
  65. EXPECT_EQ(uri.GetQuery(), components.query);
  66. EXPECT_EQ(uri.GetFragment(), components.fragment);
  67. }
  68. // Verifies that |input_uri| set as parameter in Uri constructor is normalized
  69. // to |normalized_uri|. Runs also consistency test on the created Uri object.
  70. void TestNormalization(const std::string& input_uri,
  71. const std::string& normalized_uri) {
  72. Uri uri(input_uri);
  73. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  74. EXPECT_EQ(uri.GetNormalized(false), normalized_uri);
  75. }
  76. TEST(UriTest, DefaultConstructor) {
  77. Uri uri;
  78. EXPECT_EQ(uri.GetNormalized(), "");
  79. EXPECT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  80. EXPECT_EQ(uri.GetScheme(), "");
  81. EXPECT_EQ(uri.GetUserinfo(), "");
  82. EXPECT_EQ(uri.GetUserinfoEncoded(), "");
  83. EXPECT_EQ(uri.GetHost(), "");
  84. EXPECT_EQ(uri.GetHostEncoded(), "");
  85. EXPECT_EQ(uri.GetPort(), -1);
  86. EXPECT_TRUE(uri.GetPath().empty());
  87. EXPECT_TRUE(uri.GetPathEncoded().empty());
  88. EXPECT_TRUE(uri.GetQuery().empty());
  89. EXPECT_TRUE(uri.GetQueryEncoded().empty());
  90. EXPECT_EQ(uri.GetFragment(), "");
  91. EXPECT_EQ(uri.GetFragmentEncoded(), "");
  92. }
  93. TEST(UriTest, SchemeIsCaseInsensitive) {
  94. Uri uri;
  95. uri.SetScheme("ExAmplE+SchemA-X");
  96. EXPECT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  97. EXPECT_EQ(uri.GetScheme(), "example+schema-x");
  98. }
  99. TEST(UriTest, HostIsCaseInsensitive) {
  100. Uri uri;
  101. uri.SetHost("ExAmplE.COM");
  102. EXPECT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  103. EXPECT_EQ(uri.GetHost(), "example.com");
  104. EXPECT_EQ(uri.GetHostEncoded(), "example.com");
  105. }
  106. TEST(UriTest, EncodingInHostComponent) {
  107. Uri uri;
  108. uri.SetHost("new.EX%41MPLE.COM");
  109. EXPECT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  110. EXPECT_EQ(uri.GetHost(), "new.ex%41mple.com");
  111. EXPECT_EQ(uri.GetHostEncoded(),
  112. "new.ex%2541mple.com"); // %-character was escaped
  113. uri.SetHostEncoded("new.EX%41MPLE.COM");
  114. EXPECT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  115. EXPECT_EQ(uri.GetHost(), "new.example.com");
  116. EXPECT_EQ(uri.GetHostEncoded(), "new.example.com");
  117. uri.SetHost("ExAmPlE._!_@_#_$_%_^_");
  118. EXPECT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  119. EXPECT_EQ(uri.GetHost(), "example._!_@_#_$_%_^_");
  120. EXPECT_EQ(uri.GetHostEncoded(), "example._!_%40_%23_$_%25_%5E_");
  121. uri.SetHostEncoded("ExAmPlE._!_@_#_$_%25_^_._%21_%40_%23_%24_%25_%5E_");
  122. EXPECT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  123. EXPECT_EQ(uri.GetHost(), "example._!_@_#_$_%_^_._!_@_#_$_%_^_");
  124. EXPECT_EQ(uri.GetHostEncoded(),
  125. "example._!_%40_%23_$_%25_%5E_._!_%40_%23_$_%25_%5E_");
  126. }
  127. TEST(UriTest, SetPortFromString) {
  128. Uri uri1;
  129. Uri uri2;
  130. EXPECT_TRUE(uri1.SetPort(1234));
  131. EXPECT_TRUE(uri2.SetPort("1234"));
  132. EXPECT_EQ(uri1, uri2);
  133. // -1 and empty string mean "unspecified port".
  134. EXPECT_TRUE(uri1.SetPort(-1));
  135. EXPECT_TRUE(uri2.SetPort(""));
  136. EXPECT_EQ(uri1, uri2);
  137. EXPECT_FALSE(uri2.SetPort("65536"));
  138. EXPECT_FALSE(uri2.SetPort("-2"));
  139. EXPECT_FALSE(uri2.SetPort("+2"));
  140. EXPECT_FALSE(uri2.SetPort(" 2133"));
  141. EXPECT_FALSE(uri2.SetPort("0x123"));
  142. }
  143. TEST(UriTest, UriWithAllPrintableASCII) {
  144. Uri uri;
  145. std::string host = kPrintableASCII;
  146. const std::vector<std::string> path = {kPrintableASCII};
  147. std::vector<std::pair<std::string, std::string>> query = {
  148. {kPrintableASCII, kPrintableASCII}};
  149. uri.SetUserinfo(kPrintableASCII);
  150. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  151. uri.SetHost(host);
  152. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  153. uri.SetPath(path);
  154. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  155. uri.SetQuery(query);
  156. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  157. uri.SetFragment(kPrintableASCII);
  158. ASSERT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  159. // Host is case-insensitive, uppercase letters are normalized to lowercase.
  160. std::for_each(host.begin(), host.end(), [](char& c) {
  161. if (c >= 'A' && c <= 'Z')
  162. c += 'a' - 'A';
  163. });
  164. EXPECT_EQ(uri.GetUserinfo(), kPrintableASCII);
  165. EXPECT_EQ(uri.GetHost(), host);
  166. EXPECT_EQ(uri.GetPath(), path);
  167. EXPECT_EQ(uri.GetQuery(), query);
  168. EXPECT_EQ(uri.GetFragment(), kPrintableASCII);
  169. }
  170. TEST(UriTest, BuildingHttpUriWithQuery) {
  171. UriComponents components("http", "", "example.com", 1234);
  172. components.query = {{"par1", "val1"}, {"par2", ""}, {"par3", "val3"}};
  173. TestBuilder(components, "http://example.com:1234?par1=val1&par2&par3=val3");
  174. }
  175. TEST(UriTest, BuildingUriWithAllComponents) {
  176. UriComponents components("A", "B", "C", 1);
  177. components.path = {"D", "E"};
  178. components.query = {{"F", "G"}, {"H", "I"}};
  179. components.fragment = "J";
  180. TestBuilder(components, "a://B@c:1/D/E?F=G&H=I#J");
  181. }
  182. TEST(UriTest, BuildingUriWithoutAuthority) {
  183. UriComponents components("A+1-b.C", "", "", -1);
  184. components.path = {"//", " "};
  185. components.fragment = "?#@/";
  186. TestBuilder(components, "a+1-b.c:/%2F%2F/%20#?%23@/");
  187. }
  188. // Special path segments "." and ".." are reduced when possible.
  189. TEST(UriTest, ParsingOfUriWithReduciblePath) {
  190. const std::string input_uri =
  191. "hTTp://exAmple.c%4Fm:234"
  192. "/very/../../long/.././pAth?parAm=vAlue#?%3f?";
  193. UriComponents components("http", "", "example.com", 234);
  194. components.path = {"..", "pAth"};
  195. components.query = {{"parAm", "vAlue"}};
  196. components.fragment = "???";
  197. TestParser(input_uri, components);
  198. }
  199. TEST(UriTest, ParsingOfUriWithoutPort) {
  200. // When a Port is not specified and the Scheme has a default port number,
  201. // the default port number is set.
  202. TestParser("hTTp://exAmple.com",
  203. UriComponents("http", "", "example.com", 80));
  204. // When the Scheme does not have a default port number, the value of Port
  205. // remains "unspecified".
  206. TestParser("X-x://exAmple.com", UriComponents("x-x", "", "example.com"));
  207. }
  208. TEST(UriTest, ParsingOfUriWithUTF8Characters) {
  209. // On the input, bytes defining UTF-8 characters can be %-escaped or
  210. // specified directly.
  211. const std::string uri =
  212. "http://utf8.test?"
  213. "zażółć=za%c5%bc%c3%b3%c5%82%c4%87&"
  214. "gęślą=\x67\xC4\x99\xC5%9B%6C%C4\x85&"
  215. "jaźń=ja%c5%ba%c5%84";
  216. UriComponents components("http", "", "utf8.test", 80);
  217. components.query = {
  218. {"zażółć", "zażółć"}, {"gęślą", "gęślą"}, {"jaźń", "jaźń"}};
  219. TestParser(uri, components);
  220. }
  221. // Leading and trailing whitespaces are ignored.
  222. TEST(UriTest, ParsingOfUriWithLeadingAndTrailingWhitespaces) {
  223. const std::string uri = " \t\n\r\f\vSC://WITH.whitespaces# END \t\n\r\f\v";
  224. UriComponents components("sc", "", "with.whitespaces");
  225. components.fragment = " END";
  226. TestParser(uri, components);
  227. }
  228. // Empty components are accepted.
  229. TEST(UriTest, NormalizationOfEmptyUri) {
  230. TestNormalization("://@:/?#", "");
  231. }
  232. TEST(UriTest, NormalizationOfUriWithoutAuthority) {
  233. // When Userinfo, Host and Port are not specified, the "//" prefix is
  234. // skipped.
  235. TestNormalization("xx://@:/my/path?#fragment", "xx:/my/path#fragment");
  236. TestNormalization("xx:///my/path?#fragment", "xx:/my/path#fragment");
  237. // The same happens when the Port number is equal to the default port number
  238. // of the Scheme.
  239. TestNormalization("http://:80/my/path?#fragment", "http:/my/path#fragment");
  240. }
  241. // In the normalized URI, all bytes being part of UTF-8 characters must be
  242. // %-escaped.
  243. TEST(UriTest, NormalizationOfUriWithUTF8Characters) {
  244. const std::string uri =
  245. "http://utf8.test?"
  246. "zażółć=za%c5%bc%c3%b3%c5%82%c4%87&"
  247. "gęślą=\x67\xC4\x99\xC5%9B%6C%C4\x85&"
  248. "jaźń=ja%c5%ba%c5%84";
  249. const std::string uri_normalized =
  250. "http://utf8.test?"
  251. "za%C5%BC%C3%B3%C5%82%C4%87=za%C5%BC%C3%B3%C5%82%C4%87&"
  252. "g%C4%99%C5%9Bl%C4%85=g%C4%99%C5%9Bl%C4%85&"
  253. "ja%C5%BA%C5%84=ja%C5%BA%C5%84";
  254. TestNormalization(uri, uri_normalized);
  255. }
  256. TEST(UriTest, ParserErrorDisallowedASCIICharacter) {
  257. // Non-printable character (0xFF) inside the Host component.
  258. Uri uri(" \t\n\r\f\vHTTP://BAD.\xff.CHaracter# \t\n\r\f\v");
  259. const Uri::ParserError pe = uri.GetLastParsingError();
  260. EXPECT_EQ(pe.status, Uri::ParserStatus::kDisallowedASCIICharacter);
  261. EXPECT_EQ(pe.parsed_chars, 17u);
  262. EXPECT_EQ(pe.parsed_strings, 0u);
  263. }
  264. TEST(UriTest, ParserErrorInvalidPercentEncoding) {
  265. Uri uri;
  266. // The first percent character has no following ASCII code.
  267. uri.SetHostEncoded("ExAmPlE._!_@_#_$_%_^_._%21_%40_%23_%24_%25_%5E_");
  268. EXPECT_EQ(uri.GetLastParsingError().status,
  269. Uri::ParserStatus::kInvalidPercentEncoding);
  270. EXPECT_EQ(uri.GetLastParsingError().parsed_chars, 17u);
  271. }
  272. TEST(UriTest, ParserErrorInvalidUTF8Character) {
  273. // Broken UTF-8 character in the Path (the byte after 0xC5 is wrong).
  274. Uri uri("http://host/utf8_\xC5\x3C_is_broken");
  275. const Uri::ParserError pe = uri.GetLastParsingError();
  276. EXPECT_EQ(pe.status, Uri::ParserStatus::kInvalidUTF8Character);
  277. EXPECT_EQ(pe.parsed_chars, 18u);
  278. EXPECT_EQ(pe.parsed_strings, 0u);
  279. }
  280. // Parameters in Query cannot have empty names.
  281. TEST(UriTest, ParserErrorEmptyParameterNameInQuery) {
  282. Uri uri;
  283. std::vector<std::pair<std::string, std::string>> query;
  284. query = {{"name1", "value1"}, {"", "value2"}};
  285. EXPECT_FALSE(uri.SetQuery(query));
  286. const Uri::ParserError pe1 = uri.GetLastParsingError();
  287. EXPECT_EQ(pe1.status, Uri::ParserStatus::kEmptyParameterNameInQuery);
  288. EXPECT_EQ(pe1.parsed_chars, 0u);
  289. EXPECT_EQ(pe1.parsed_strings, 2u);
  290. }
  291. // Port number cannot have non-digit characters.
  292. TEST(UriTest, ParserErrorInvalidPortNumber) {
  293. Uri uri("http://my.weird.port.number:+123");
  294. const Uri::ParserError pe = uri.GetLastParsingError();
  295. EXPECT_EQ(pe.status, Uri::ParserStatus::kInvalidPortNumber);
  296. EXPECT_EQ(pe.parsed_chars, 28u);
  297. EXPECT_EQ(pe.parsed_strings, 0u);
  298. }
  299. // Path cannot have empty segments.
  300. TEST(UriTest, ParserErrorEmptySegmentInPath) {
  301. Uri uri;
  302. EXPECT_FALSE(uri.SetPathEncoded("/segment1//segment3"));
  303. const Uri::ParserError pe2 = uri.GetLastParsingError();
  304. EXPECT_EQ(pe2.status, Uri::ParserStatus::kEmptySegmentInPath);
  305. EXPECT_EQ(pe2.parsed_chars, 10u);
  306. EXPECT_EQ(pe2.parsed_strings, 0u);
  307. }
  308. TEST(UriTest, ParserErrorInPath) {
  309. // Non-printable character (0xBA) inside the path.
  310. Uri uri(
  311. " HTTP://example.org/aa/\xba_d/cc"
  312. "?name1&name2=param2&\xba_d=character#here\xba ");
  313. const Uri::ParserError pe = uri.GetLastParsingError();
  314. EXPECT_EQ(pe.status, Uri::ParserStatus::kDisallowedASCIICharacter);
  315. EXPECT_EQ(pe.parsed_chars, 24u);
  316. EXPECT_EQ(pe.parsed_strings, 0u);
  317. }
  318. TEST(UriTest, ParserErrorInQuery) {
  319. // Non-printable character (0xBA) inside the query.
  320. Uri uri(
  321. " HTTP://example.org/aa/bb/cc"
  322. "?name1&name2=param2&\xba_d=character#here\xba ");
  323. const Uri::ParserError pe = uri.GetLastParsingError();
  324. EXPECT_EQ(pe.status, Uri::ParserStatus::kDisallowedASCIICharacter);
  325. EXPECT_EQ(pe.parsed_chars, 49u);
  326. EXPECT_EQ(pe.parsed_strings, 0u);
  327. }
  328. TEST(UriTest, ParserErrorInFragment) {
  329. // Non-printable character (0xBA) inside the fragment.
  330. Uri uri(
  331. " HTTP://example.org/aa/bb/cc"
  332. "?name1&name2=param2&good=character#here\xba ");
  333. const Uri::ParserError pe = uri.GetLastParsingError();
  334. EXPECT_EQ(pe.status, Uri::ParserStatus::kDisallowedASCIICharacter);
  335. EXPECT_EQ(pe.parsed_chars, 68u);
  336. EXPECT_EQ(pe.parsed_strings, 0u);
  337. }
  338. TEST(UriTest, GetQueryAsMap) {
  339. Uri uri("ipp://example.org?p1&p2=val&p1=123&p3=aa&p1=&p2=val&other=x&end");
  340. EXPECT_EQ(uri.GetLastParsingError().status, Uri::ParserStatus::kNoErrors);
  341. using KeyValue = std::pair<std::string, std::vector<std::string>>;
  342. // Parameters from the query sorted by keys.
  343. const KeyValue e1("end", {""});
  344. const KeyValue e2("other", {"x"});
  345. const KeyValue e3("p1", {"", "123", ""});
  346. const KeyValue e4("p2", {"val", "val"});
  347. const KeyValue e5("p3", {"aa"});
  348. EXPECT_THAT(uri.GetQueryAsMap(), testing::ElementsAre(e1, e2, e3, e4, e5));
  349. }
  350. } // namespace
  351. } // namespace chromeos