1 // Copyright 2013 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 
5 #include <stddef.h>
6 
7 #include "base/stl_util.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "url/gurl.h"
12 #include "url/origin.h"
13 #include "url/url_canon.h"
14 #include "url/url_test_utils.h"
15 
16 namespace url {
17 
18 namespace {
19 
20 template<typename CHAR>
SetupReplacement(void (Replacements<CHAR>::* func)(const CHAR *,const Component &),Replacements<CHAR> * replacements,const CHAR * str)21 void SetupReplacement(
22     void (Replacements<CHAR>::*func)(const CHAR*, const Component&),
23     Replacements<CHAR>* replacements,
24     const CHAR* str) {
25   if (str) {
26     Component comp;
27     if (str[0])
28       comp.len = static_cast<int>(strlen(str));
29     (replacements->*func)(str, comp);
30   }
31 }
32 
33 // Returns the canonicalized string for the given URL string for the
34 // GURLTest.Types test.
TypesTestCase(const char * src)35 std::string TypesTestCase(const char* src) {
36   GURL gurl(src);
37   return gurl.possibly_invalid_spec();
38 }
39 
40 }  // namespace
41 
42 // Different types of URLs should be handled differently, and handed off to
43 // different canonicalizers.
TEST(GURLTest,Types)44 TEST(GURLTest, Types) {
45   // URLs with unknown schemes should be treated as path URLs, even when they
46   // have things like "://".
47   EXPECT_EQ("something:///HOSTNAME.com/",
48             TypesTestCase("something:///HOSTNAME.com/"));
49 
50   // Conversely, URLs with known schemes should always trigger standard URL
51   // handling.
52   EXPECT_EQ("http://hostname.com/", TypesTestCase("http:HOSTNAME.com"));
53   EXPECT_EQ("http://hostname.com/", TypesTestCase("http:/HOSTNAME.com"));
54   EXPECT_EQ("http://hostname.com/", TypesTestCase("http://HOSTNAME.com"));
55   EXPECT_EQ("http://hostname.com/", TypesTestCase("http:///HOSTNAME.com"));
56 
57 #ifdef WIN32
58   // URLs that look like Windows absolute path specs.
59   EXPECT_EQ("file:///C:/foo.txt", TypesTestCase("c:\\foo.txt"));
60   EXPECT_EQ("file:///Z:/foo.txt", TypesTestCase("Z|foo.txt"));
61   EXPECT_EQ("file://server/foo.txt", TypesTestCase("\\\\server\\foo.txt"));
62   EXPECT_EQ("file://server/foo.txt", TypesTestCase("//server/foo.txt"));
63 #endif
64 }
65 
66 // Test the basic creation and querying of components in a GURL. We assume that
67 // the parser is already tested and works, so we are mostly interested if the
68 // object does the right thing with the results.
TEST(GURLTest,Components)69 TEST(GURLTest, Components) {
70   GURL empty_url(base::UTF8ToUTF16(""));
71   EXPECT_TRUE(empty_url.is_empty());
72   EXPECT_FALSE(empty_url.is_valid());
73 
74   GURL url(base::UTF8ToUTF16("http://user:pass@google.com:99/foo;bar?q=a#ref"));
75   EXPECT_FALSE(url.is_empty());
76   EXPECT_TRUE(url.is_valid());
77   EXPECT_TRUE(url.SchemeIs("http"));
78   EXPECT_FALSE(url.SchemeIsFile());
79 
80   // This is the narrow version of the URL, which should match the wide input.
81   EXPECT_EQ("http://user:pass@google.com:99/foo;bar?q=a#ref", url.spec());
82 
83   EXPECT_EQ("http", url.scheme());
84   EXPECT_EQ("user", url.username());
85   EXPECT_EQ("pass", url.password());
86   EXPECT_EQ("google.com", url.host());
87   EXPECT_EQ("99", url.port());
88   EXPECT_EQ(99, url.IntPort());
89   EXPECT_EQ("/foo;bar", url.path());
90   EXPECT_EQ("q=a", url.query());
91   EXPECT_EQ("ref", url.ref());
92 
93   // Test parsing userinfo with special characters.
94   GURL url_special_pass("http://user:%40!$&'()*+,;=:@google.com:12345");
95   EXPECT_TRUE(url_special_pass.is_valid());
96   // GURL canonicalizes some delimiters.
97   EXPECT_EQ("%40!$&%27()*+,%3B%3D%3A", url_special_pass.password());
98   EXPECT_EQ("google.com", url_special_pass.host());
99   EXPECT_EQ("12345", url_special_pass.port());
100 }
101 
TEST(GURLTest,Empty)102 TEST(GURLTest, Empty) {
103   GURL url;
104   EXPECT_FALSE(url.is_valid());
105   EXPECT_EQ("", url.spec());
106 
107   EXPECT_EQ("", url.scheme());
108   EXPECT_EQ("", url.username());
109   EXPECT_EQ("", url.password());
110   EXPECT_EQ("", url.host());
111   EXPECT_EQ("", url.port());
112   EXPECT_EQ(PORT_UNSPECIFIED, url.IntPort());
113   EXPECT_EQ("", url.path());
114   EXPECT_EQ("", url.query());
115   EXPECT_EQ("", url.ref());
116 }
117 
TEST(GURLTest,Copy)118 TEST(GURLTest, Copy) {
119   GURL url(base::UTF8ToUTF16(
120       "http://user:pass@google.com:99/foo;bar?q=a#ref"));
121 
122   GURL url2(url);
123   EXPECT_TRUE(url2.is_valid());
124 
125   EXPECT_EQ("http://user:pass@google.com:99/foo;bar?q=a#ref", url2.spec());
126   EXPECT_EQ("http", url2.scheme());
127   EXPECT_EQ("user", url2.username());
128   EXPECT_EQ("pass", url2.password());
129   EXPECT_EQ("google.com", url2.host());
130   EXPECT_EQ("99", url2.port());
131   EXPECT_EQ(99, url2.IntPort());
132   EXPECT_EQ("/foo;bar", url2.path());
133   EXPECT_EQ("q=a", url2.query());
134   EXPECT_EQ("ref", url2.ref());
135 
136   // Copying of invalid URL should be invalid
137   GURL invalid;
138   GURL invalid2(invalid);
139   EXPECT_FALSE(invalid2.is_valid());
140   EXPECT_EQ("", invalid2.spec());
141   EXPECT_EQ("", invalid2.scheme());
142   EXPECT_EQ("", invalid2.username());
143   EXPECT_EQ("", invalid2.password());
144   EXPECT_EQ("", invalid2.host());
145   EXPECT_EQ("", invalid2.port());
146   EXPECT_EQ(PORT_UNSPECIFIED, invalid2.IntPort());
147   EXPECT_EQ("", invalid2.path());
148   EXPECT_EQ("", invalid2.query());
149   EXPECT_EQ("", invalid2.ref());
150 }
151 
TEST(GURLTest,Assign)152 TEST(GURLTest, Assign) {
153   GURL url(base::UTF8ToUTF16(
154       "http://user:pass@google.com:99/foo;bar?q=a#ref"));
155 
156   GURL url2;
157   url2 = url;
158   EXPECT_TRUE(url2.is_valid());
159 
160   EXPECT_EQ("http://user:pass@google.com:99/foo;bar?q=a#ref", url2.spec());
161   EXPECT_EQ("http", url2.scheme());
162   EXPECT_EQ("user", url2.username());
163   EXPECT_EQ("pass", url2.password());
164   EXPECT_EQ("google.com", url2.host());
165   EXPECT_EQ("99", url2.port());
166   EXPECT_EQ(99, url2.IntPort());
167   EXPECT_EQ("/foo;bar", url2.path());
168   EXPECT_EQ("q=a", url2.query());
169   EXPECT_EQ("ref", url2.ref());
170 
171   // Assignment of invalid URL should be invalid
172   GURL invalid;
173   GURL invalid2;
174   invalid2 = invalid;
175   EXPECT_FALSE(invalid2.is_valid());
176   EXPECT_EQ("", invalid2.spec());
177   EXPECT_EQ("", invalid2.scheme());
178   EXPECT_EQ("", invalid2.username());
179   EXPECT_EQ("", invalid2.password());
180   EXPECT_EQ("", invalid2.host());
181   EXPECT_EQ("", invalid2.port());
182   EXPECT_EQ(PORT_UNSPECIFIED, invalid2.IntPort());
183   EXPECT_EQ("", invalid2.path());
184   EXPECT_EQ("", invalid2.query());
185   EXPECT_EQ("", invalid2.ref());
186 }
187 
188 // This is a regression test for http://crbug.com/309975.
TEST(GURLTest,SelfAssign)189 TEST(GURLTest, SelfAssign) {
190   GURL a("filesystem:http://example.com/temporary/");
191   // This should not crash.
192   a = *&a;  // The *& defeats Clang's -Wself-assign warning.
193 }
194 
TEST(GURLTest,CopyFileSystem)195 TEST(GURLTest, CopyFileSystem) {
196   GURL url(base::UTF8ToUTF16(
197       "filesystem:https://user:pass@google.com:99/t/foo;bar?q=a#ref"));
198 
199   GURL url2(url);
200   EXPECT_TRUE(url2.is_valid());
201 
202   EXPECT_EQ("filesystem:https://google.com:99/t/foo;bar?q=a#ref", url2.spec());
203   EXPECT_EQ("filesystem", url2.scheme());
204   EXPECT_EQ("", url2.username());
205   EXPECT_EQ("", url2.password());
206   EXPECT_EQ("", url2.host());
207   EXPECT_EQ("", url2.port());
208   EXPECT_EQ(PORT_UNSPECIFIED, url2.IntPort());
209   EXPECT_EQ("/foo;bar", url2.path());
210   EXPECT_EQ("q=a", url2.query());
211   EXPECT_EQ("ref", url2.ref());
212 
213   const GURL* inner = url2.inner_url();
214   ASSERT_TRUE(inner);
215   EXPECT_EQ("https", inner->scheme());
216   EXPECT_EQ("", inner->username());
217   EXPECT_EQ("", inner->password());
218   EXPECT_EQ("google.com", inner->host());
219   EXPECT_EQ("99", inner->port());
220   EXPECT_EQ(99, inner->IntPort());
221   EXPECT_EQ("/t", inner->path());
222   EXPECT_EQ("", inner->query());
223   EXPECT_EQ("", inner->ref());
224 }
225 
TEST(GURLTest,IsValid)226 TEST(GURLTest, IsValid) {
227   const char* valid_cases[] = {
228       "http://google.com",
229       "unknown://google.com",
230       "http://user:pass@google.com",
231       "http://google.com:12345",
232       "http://google.com:0",  // 0 is a valid port
233       "http://google.com/path",
234       "http://google.com//path",
235       "http://google.com?k=v#fragment",
236       "http://user:pass@google.com:12345/path?k=v#fragment",
237       "http:/path",
238       "http:path",
239   };
240   for (size_t i = 0; i < base::size(valid_cases); i++) {
241     EXPECT_TRUE(GURL(valid_cases[i]).is_valid())
242         << "Case: " << valid_cases[i];
243   }
244 
245   const char* invalid_cases[] = {
246       "http://?k=v",
247       "http:://google.com",
248       "http//google.com",
249       "http://google.com:12three45",
250       "file://server:123",  // file: URLs cannot have a port
251       "file://server:0",
252       "://google.com",
253       "path",
254   };
255   for (size_t i = 0; i < base::size(invalid_cases); i++) {
256     EXPECT_FALSE(GURL(invalid_cases[i]).is_valid())
257         << "Case: " << invalid_cases[i];
258   }
259 }
260 
TEST(GURLTest,ExtraSlashesBeforeAuthority)261 TEST(GURLTest, ExtraSlashesBeforeAuthority) {
262   // According to RFC3986, the hierarchical part for URI with an authority
263   // must use only two slashes; GURL intentionally just ignores extra slashes
264   // if there are more than 2, and parses the following part as an authority.
265   GURL url("http:///host");
266   EXPECT_EQ("host", url.host());
267   EXPECT_EQ("/", url.path());
268 }
269 
270 // Given an invalid URL, we should still get most of the components.
TEST(GURLTest,ComponentGettersWorkEvenForInvalidURL)271 TEST(GURLTest, ComponentGettersWorkEvenForInvalidURL) {
272   GURL url("http:google.com:foo");
273   EXPECT_FALSE(url.is_valid());
274   EXPECT_EQ("http://google.com:foo/", url.possibly_invalid_spec());
275 
276   EXPECT_EQ("http", url.scheme());
277   EXPECT_EQ("", url.username());
278   EXPECT_EQ("", url.password());
279   EXPECT_EQ("google.com", url.host());
280   EXPECT_EQ("foo", url.port());
281   EXPECT_EQ(PORT_INVALID, url.IntPort());
282   EXPECT_EQ("/", url.path());
283   EXPECT_EQ("", url.query());
284   EXPECT_EQ("", url.ref());
285 }
286 
TEST(GURLTest,Resolve)287 TEST(GURLTest, Resolve) {
288   // The tricky cases for relative URL resolving are tested in the
289   // canonicalizer unit test. Here, we just test that the GURL integration
290   // works properly.
291   struct ResolveCase {
292     const char* base;
293     const char* relative;
294     bool expected_valid;
295     const char* expected;
296   } resolve_cases[] = {
297       {"http://www.google.com/", "foo.html", true,
298        "http://www.google.com/foo.html"},
299       {"http://www.google.com/foo/", "bar", true,
300        "http://www.google.com/foo/bar"},
301       {"http://www.google.com/foo/", "/bar", true, "http://www.google.com/bar"},
302       {"http://www.google.com/foo", "bar", true, "http://www.google.com/bar"},
303       {"http://www.google.com/", "http://images.google.com/foo.html", true,
304        "http://images.google.com/foo.html"},
305       {"http://www.google.com/", "http://images.\tgoogle.\ncom/\rfoo.html",
306        true, "http://images.google.com/foo.html"},
307       {"http://www.google.com/blah/bloo?c#d", "../../../hello/./world.html?a#b",
308        true, "http://www.google.com/hello/world.html?a#b"},
309       {"http://www.google.com/foo#bar", "#com", true,
310        "http://www.google.com/foo#com"},
311       {"http://www.google.com/", "Https:images.google.com", true,
312        "https://images.google.com/"},
313       // A non-standard base can be replaced with a standard absolute URL.
314       {"data:blahblah", "http://google.com/", true, "http://google.com/"},
315       {"data:blahblah", "http:google.com", true, "http://google.com/"},
316       // Filesystem URLs have different paths to test.
317       {"filesystem:http://www.google.com/type/", "foo.html", true,
318        "filesystem:http://www.google.com/type/foo.html"},
319       {"filesystem:http://www.google.com/type/", "../foo.html", true,
320        "filesystem:http://www.google.com/type/foo.html"},
321       // https://crbug.com/530123 - scheme validation (e.g. are "10.0.0.7:"
322       // or "x1:" valid schemes) when deciding if |relative| is an absolute url.
323       {"file:///some/dir/ip-relative.html", "10.0.0.7:8080/foo.html", true,
324        "file:///some/dir/10.0.0.7:8080/foo.html"},
325       {"file:///some/dir/", "1://host", true, "file:///some/dir/1://host"},
326       {"file:///some/dir/", "x1://host", true, "x1://host"},
327       {"file:///some/dir/", "X1://host", true, "x1://host"},
328       {"file:///some/dir/", "x.://host", true, "x.://host"},
329       {"file:///some/dir/", "x+://host", true, "x+://host"},
330       {"file:///some/dir/", "x-://host", true, "x-://host"},
331       {"file:///some/dir/", "x!://host", true, "file:///some/dir/x!://host"},
332       {"file:///some/dir/", "://host", true, "file:///some/dir/://host"},
333   };
334 
335   for (size_t i = 0; i < base::size(resolve_cases); i++) {
336     // 8-bit code path.
337     GURL input(resolve_cases[i].base);
338     GURL output = input.Resolve(resolve_cases[i].relative);
339     EXPECT_EQ(resolve_cases[i].expected_valid, output.is_valid()) << i;
340     EXPECT_EQ(resolve_cases[i].expected, output.spec()) << i;
341     EXPECT_EQ(output.SchemeIsFileSystem(), output.inner_url() != NULL);
342 
343     // Wide code path.
344     GURL inputw(base::UTF8ToUTF16(resolve_cases[i].base));
345     GURL outputw =
346         input.Resolve(base::UTF8ToUTF16(resolve_cases[i].relative));
347     EXPECT_EQ(resolve_cases[i].expected_valid, outputw.is_valid()) << i;
348     EXPECT_EQ(resolve_cases[i].expected, outputw.spec()) << i;
349     EXPECT_EQ(outputw.SchemeIsFileSystem(), outputw.inner_url() != NULL);
350   }
351 }
352 
TEST(GURLTest,GetOrigin)353 TEST(GURLTest, GetOrigin) {
354   struct TestCase {
355     const char* input;
356     const char* expected;
357   } cases[] = {
358       {"http://www.google.com", "http://www.google.com/"},
359       {"javascript:window.alert(\"hello,world\");", ""},
360       {"http://user:pass@www.google.com:21/blah#baz",
361        "http://www.google.com:21/"},
362       {"http://user@www.google.com", "http://www.google.com/"},
363       {"http://:pass@www.google.com", "http://www.google.com/"},
364       {"http://:@www.google.com", "http://www.google.com/"},
365       {"filesystem:http://www.google.com/temp/foo?q#b",
366        "http://www.google.com/"},
367       {"filesystem:http://user:pass@google.com:21/blah#baz",
368        "http://google.com:21/"},
369       {"blob:null/guid-goes-here", ""},
370       {"blob:http://origin/guid-goes-here", "" /* should be http://origin/ */},
371   };
372   for (size_t i = 0; i < base::size(cases); i++) {
373     GURL url(cases[i].input);
374     GURL origin = url.GetOrigin();
375     EXPECT_EQ(cases[i].expected, origin.spec());
376   }
377 }
378 
TEST(GURLTest,GetAsReferrer)379 TEST(GURLTest, GetAsReferrer) {
380   struct TestCase {
381     const char* input;
382     const char* expected;
383   } cases[] = {
384     {"http://www.google.com", "http://www.google.com/"},
385     {"http://user:pass@www.google.com:21/blah#baz", "http://www.google.com:21/blah"},
386     {"http://user@www.google.com", "http://www.google.com/"},
387     {"http://:pass@www.google.com", "http://www.google.com/"},
388     {"http://:@www.google.com", "http://www.google.com/"},
389     {"http://www.google.com/temp/foo?q#b", "http://www.google.com/temp/foo?q"},
390     {"not a url", ""},
391     {"unknown-scheme://foo.html", ""},
392     {"file:///tmp/test.html", ""},
393     {"https://www.google.com", "https://www.google.com/"},
394   };
395   for (size_t i = 0; i < base::size(cases); i++) {
396     GURL url(cases[i].input);
397     GURL origin = url.GetAsReferrer();
398     EXPECT_EQ(cases[i].expected, origin.spec());
399   }
400 }
401 
TEST(GURLTest,GetWithEmptyPath)402 TEST(GURLTest, GetWithEmptyPath) {
403   struct TestCase {
404     const char* input;
405     const char* expected;
406   } cases[] = {
407     {"http://www.google.com", "http://www.google.com/"},
408     {"javascript:window.alert(\"hello, world\");", ""},
409     {"http://www.google.com/foo/bar.html?baz=22", "http://www.google.com/"},
410     {"filesystem:http://www.google.com/temporary/bar.html?baz=22", "filesystem:http://www.google.com/temporary/"},
411     {"filesystem:file:///temporary/bar.html?baz=22", "filesystem:file:///temporary/"},
412   };
413 
414   for (size_t i = 0; i < base::size(cases); i++) {
415     GURL url(cases[i].input);
416     GURL empty_path = url.GetWithEmptyPath();
417     EXPECT_EQ(cases[i].expected, empty_path.spec());
418   }
419 }
420 
TEST(GURLTest,GetWithoutFilename)421 TEST(GURLTest, GetWithoutFilename) {
422   struct TestCase {
423     const char* input;
424     const char* expected;
425   } cases[] = {
426     // Common Standard URLs.
427     {"https://www.google.com",                    "https://www.google.com/"},
428     {"https://www.google.com/",                   "https://www.google.com/"},
429     {"https://www.google.com/maps.htm",           "https://www.google.com/"},
430     {"https://www.google.com/maps/",              "https://www.google.com/maps/"},
431     {"https://www.google.com/index.html",         "https://www.google.com/"},
432     {"https://www.google.com/index.html?q=maps",  "https://www.google.com/"},
433     {"https://www.google.com/index.html#maps/",   "https://www.google.com/"},
434     {"https://foo:bar@www.google.com/maps.htm",   "https://foo:bar@www.google.com/"},
435     {"https://www.google.com/maps/au/index.html", "https://www.google.com/maps/au/"},
436     {"https://www.google.com/maps/au/north",      "https://www.google.com/maps/au/"},
437     {"https://www.google.com/maps/au/north/",     "https://www.google.com/maps/au/north/"},
438     {"https://www.google.com/maps/au/index.html?q=maps#fragment/",     "https://www.google.com/maps/au/"},
439     {"http://www.google.com:8000/maps/au/index.html?q=maps#fragment/", "http://www.google.com:8000/maps/au/"},
440     {"https://www.google.com/maps/au/north/?q=maps#fragment",          "https://www.google.com/maps/au/north/"},
441     {"https://www.google.com/maps/au/north?q=maps#fragment",           "https://www.google.com/maps/au/"},
442     // Less common standard URLs.
443     {"filesystem:http://www.google.com/temporary/bar.html?baz=22", "filesystem:http://www.google.com/temporary/"},
444     {"file:///temporary/bar.html?baz=22","file:///temporary/"},
445     {"ftp://foo/test/index.html",        "ftp://foo/test/"},
446     {"gopher://foo/test/index.html",     "gopher://foo/test/"},
447     {"ws://foo/test/index.html",         "ws://foo/test/"},
448     // Non-standard, hierarchical URLs.
449     {"chrome://foo/bar.html", "chrome://foo/"},
450     {"httpa://foo/test/index.html", "httpa://foo/test/"},
451     // Non-standard, non-hierarchical URLs.
452     {"blob:https://foo.bar/test/index.html", ""},
453     {"about:blank", ""},
454     {"data:foobar", ""},
455     {"scheme:opaque_data", ""},
456     // Invalid URLs.
457     {"foobar", ""},
458   };
459 
460   for (size_t i = 0; i < base::size(cases); i++) {
461     GURL url(cases[i].input);
462     GURL without_filename = url.GetWithoutFilename();
463     EXPECT_EQ(cases[i].expected, without_filename.spec()) << i;
464   }
465 }
466 
TEST(GURLTest,Replacements)467 TEST(GURLTest, Replacements) {
468   // The URL canonicalizer replacement test will handle most of these case.
469   // The most important thing to do here is to check that the proper
470   // canonicalizer gets called based on the scheme of the input.
471   struct ReplaceCase {
472     const char* base;
473     const char* scheme;
474     const char* username;
475     const char* password;
476     const char* host;
477     const char* port;
478     const char* path;
479     const char* query;
480     const char* ref;
481     const char* expected;
482   } replace_cases[] = {
483       {"http://www.google.com/foo/bar.html?foo#bar", NULL, NULL, NULL, NULL,
484        NULL, "/", "", "", "http://www.google.com/"},
485       {"http://www.google.com/foo/bar.html?foo#bar", "javascript", "", "", "",
486        "", "window.open('foo');", "", "", "javascript:window.open('foo');"},
487       {"file:///C:/foo/bar.txt", "http", NULL, NULL, "www.google.com", "99",
488        "/foo", "search", "ref", "http://www.google.com:99/foo?search#ref"},
489 #ifdef WIN32
490       {"http://www.google.com/foo/bar.html?foo#bar", "file", "", "", "", "",
491        "c:\\", "", "", "file:///C:/"},
492 #endif
493       {"filesystem:http://www.google.com/foo/bar.html?foo#bar", NULL, NULL,
494        NULL, NULL, NULL, "/", "", "", "filesystem:http://www.google.com/foo/"},
495       // Lengthen the URL instead of shortening it, to test creation of
496       // inner_url.
497       {"filesystem:http://www.google.com/foo/", NULL, NULL, NULL, NULL, NULL,
498        "bar.html", "foo", "bar",
499        "filesystem:http://www.google.com/foo/bar.html?foo#bar"},
500   };
501 
502   for (size_t i = 0; i < base::size(replace_cases); i++) {
503     const ReplaceCase& cur = replace_cases[i];
504     GURL url(cur.base);
505     GURL::Replacements repl;
506     SetupReplacement(&GURL::Replacements::SetScheme, &repl, cur.scheme);
507     SetupReplacement(&GURL::Replacements::SetUsername, &repl, cur.username);
508     SetupReplacement(&GURL::Replacements::SetPassword, &repl, cur.password);
509     SetupReplacement(&GURL::Replacements::SetHost, &repl, cur.host);
510     SetupReplacement(&GURL::Replacements::SetPort, &repl, cur.port);
511     SetupReplacement(&GURL::Replacements::SetPath, &repl, cur.path);
512     SetupReplacement(&GURL::Replacements::SetQuery, &repl, cur.query);
513     SetupReplacement(&GURL::Replacements::SetRef, &repl, cur.ref);
514     GURL output = url.ReplaceComponents(repl);
515 
516     EXPECT_EQ(replace_cases[i].expected, output.spec());
517 
518     EXPECT_EQ(output.SchemeIsFileSystem(), output.inner_url() != NULL);
519     if (output.SchemeIsFileSystem()) {
520       // TODO(mmenke): inner_url()->spec() is currently the same as the spec()
521       // for the GURL itself.  This should be fixed.
522       // See https://crbug.com/619596
523       EXPECT_EQ(replace_cases[i].expected, output.inner_url()->spec());
524     }
525   }
526 }
527 
TEST(GURLTest,ClearFragmentOnDataUrl)528 TEST(GURLTest, ClearFragmentOnDataUrl) {
529   // http://crbug.com/291747 - a data URL may legitimately have trailing
530   // whitespace in the spec after the ref is cleared. Test this does not trigger
531   // the Parsed importing validation DCHECK in GURL.
532   GURL url(" data: one ? two # three ");
533 
534   // By default the trailing whitespace will have been stripped.
535   EXPECT_EQ("data: one ? two # three", url.spec());
536   GURL::Replacements repl;
537   repl.ClearRef();
538   GURL url_no_ref = url.ReplaceComponents(repl);
539 
540   EXPECT_EQ("data: one ? two ", url_no_ref.spec());
541 
542   // Importing a parsed URL via this constructor overload will retain trailing
543   // whitespace.
544   GURL import_url(url_no_ref.spec(),
545                   url_no_ref.parsed_for_possibly_invalid_spec(),
546                   url_no_ref.is_valid());
547   EXPECT_EQ(url_no_ref, import_url);
548   EXPECT_EQ(import_url.query(), " two ");
549 }
550 
TEST(GURLTest,PathForRequest)551 TEST(GURLTest, PathForRequest) {
552   struct TestCase {
553     const char* input;
554     const char* expected;
555     const char* inner_expected;
556   } cases[] = {
557     {"http://www.google.com", "/", NULL},
558     {"http://www.google.com/", "/", NULL},
559     {"http://www.google.com/foo/bar.html?baz=22", "/foo/bar.html?baz=22", NULL},
560     {"http://www.google.com/foo/bar.html#ref", "/foo/bar.html", NULL},
561     {"http://www.google.com/foo/bar.html?query#ref", "/foo/bar.html?query", NULL},
562     {"filesystem:http://www.google.com/temporary/foo/bar.html?query#ref", "/foo/bar.html?query", "/temporary"},
563     {"filesystem:http://www.google.com/temporary/foo/bar.html?query", "/foo/bar.html?query", "/temporary"},
564   };
565 
566   for (size_t i = 0; i < base::size(cases); i++) {
567     GURL url(cases[i].input);
568     EXPECT_EQ(cases[i].expected, url.PathForRequest());
569     EXPECT_EQ(cases[i].expected, url.PathForRequestPiece());
570     EXPECT_EQ(cases[i].inner_expected == NULL, url.inner_url() == NULL);
571     if (url.inner_url() && cases[i].inner_expected) {
572       EXPECT_EQ(cases[i].inner_expected, url.inner_url()->PathForRequest());
573       EXPECT_EQ(cases[i].inner_expected,
574                 url.inner_url()->PathForRequestPiece());
575     }
576   }
577 }
578 
TEST(GURLTest,EffectiveIntPort)579 TEST(GURLTest, EffectiveIntPort) {
580   struct PortTest {
581     const char* spec;
582     int expected_int_port;
583   } port_tests[] = {
584     // http
585     {"http://www.google.com/", 80},
586     {"http://www.google.com:80/", 80},
587     {"http://www.google.com:443/", 443},
588 
589     // https
590     {"https://www.google.com/", 443},
591     {"https://www.google.com:443/", 443},
592     {"https://www.google.com:80/", 80},
593 
594     // ftp
595     {"ftp://www.google.com/", 21},
596     {"ftp://www.google.com:21/", 21},
597     {"ftp://www.google.com:80/", 80},
598 
599     // file - no port
600     {"file://www.google.com/", PORT_UNSPECIFIED},
601     {"file://www.google.com:443/", PORT_UNSPECIFIED},
602 
603     // data - no port
604     {"data:www.google.com:90", PORT_UNSPECIFIED},
605     {"data:www.google.com", PORT_UNSPECIFIED},
606 
607     // filesystem - no port
608     {"filesystem:http://www.google.com:90/t/foo", PORT_UNSPECIFIED},
609     {"filesystem:file:///t/foo", PORT_UNSPECIFIED},
610   };
611 
612   for (size_t i = 0; i < base::size(port_tests); i++) {
613     GURL url(port_tests[i].spec);
614     EXPECT_EQ(port_tests[i].expected_int_port, url.EffectiveIntPort());
615   }
616 }
617 
TEST(GURLTest,IPAddress)618 TEST(GURLTest, IPAddress) {
619   struct IPTest {
620     const char* spec;
621     bool expected_ip;
622   } ip_tests[] = {
623     {"http://www.google.com/", false},
624     {"http://192.168.9.1/", true},
625     {"http://192.168.9.1.2/", false},
626     {"http://192.168.m.1/", false},
627     {"http://2001:db8::1/", false},
628     {"http://[2001:db8::1]/", true},
629     {"", false},
630     {"some random input!", false},
631   };
632 
633   for (size_t i = 0; i < base::size(ip_tests); i++) {
634     GURL url(ip_tests[i].spec);
635     EXPECT_EQ(ip_tests[i].expected_ip, url.HostIsIPAddress());
636   }
637 }
638 
TEST(GURLTest,HostNoBrackets)639 TEST(GURLTest, HostNoBrackets) {
640   struct TestCase {
641     const char* input;
642     const char* expected_host;
643     const char* expected_plainhost;
644   } cases[] = {
645     {"http://www.google.com", "www.google.com", "www.google.com"},
646     {"http://[2001:db8::1]/", "[2001:db8::1]", "2001:db8::1"},
647     {"http://[::]/", "[::]", "::"},
648 
649     // Don't require a valid URL, but don't crash either.
650     {"http://[]/", "[]", ""},
651     {"http://[x]/", "[x]", "x"},
652     {"http://[x/", "[x", "[x"},
653     {"http://x]/", "x]", "x]"},
654     {"http://[/", "[", "["},
655     {"http://]/", "]", "]"},
656     {"", "", ""},
657   };
658   for (size_t i = 0; i < base::size(cases); i++) {
659     GURL url(cases[i].input);
660     EXPECT_EQ(cases[i].expected_host, url.host());
661     EXPECT_EQ(cases[i].expected_plainhost, url.HostNoBrackets());
662     EXPECT_EQ(cases[i].expected_plainhost, url.HostNoBracketsPiece());
663   }
664 }
665 
TEST(GURLTest,DomainIs)666 TEST(GURLTest, DomainIs) {
667   GURL url_1("http://google.com/foo");
668   EXPECT_TRUE(url_1.DomainIs("google.com"));
669 
670   // Subdomain and port are ignored.
671   GURL url_2("http://www.google.com:99/foo");
672   EXPECT_TRUE(url_2.DomainIs("google.com"));
673 
674   // Different top-level domain.
675   GURL url_3("http://www.google.com.cn/foo");
676   EXPECT_FALSE(url_3.DomainIs("google.com"));
677 
678   // Different host name.
679   GURL url_4("http://www.iamnotgoogle.com/foo");
680   EXPECT_FALSE(url_4.DomainIs("google.com"));
681 
682   // The input must be lower-cased otherwise DomainIs returns false.
683   GURL url_5("http://www.google.com/foo");
684   EXPECT_FALSE(url_5.DomainIs("Google.com"));
685 
686   // If the URL is invalid, DomainIs returns false.
687   GURL invalid_url("google.com");
688   EXPECT_FALSE(invalid_url.is_valid());
689   EXPECT_FALSE(invalid_url.DomainIs("google.com"));
690 
691   GURL url_with_escape_chars("https://www.,.test");
692   EXPECT_TRUE(url_with_escape_chars.is_valid());
693   EXPECT_EQ(url_with_escape_chars.host(), "www.%2C.test");
694   EXPECT_TRUE(url_with_escape_chars.DomainIs("%2C.test"));
695 }
696 
TEST(GURLTest,DomainIsTerminatingDotBehavior)697 TEST(GURLTest, DomainIsTerminatingDotBehavior) {
698   // If the host part ends with a dot, it matches input domains
699   // with or without a dot.
700   GURL url_with_dot("http://www.google.com./foo");
701   EXPECT_TRUE(url_with_dot.DomainIs("google.com"));
702   EXPECT_TRUE(url_with_dot.DomainIs("google.com."));
703   EXPECT_TRUE(url_with_dot.DomainIs(".com"));
704   EXPECT_TRUE(url_with_dot.DomainIs(".com."));
705 
706   // But, if the host name doesn't end with a dot and the input
707   // domain does, then it's considered to not match.
708   GURL url_without_dot("http://google.com/foo");
709   EXPECT_FALSE(url_without_dot.DomainIs("google.com."));
710 
711   // If the URL ends with two dots, it doesn't match.
712   GURL url_with_two_dots("http://www.google.com../foo");
713   EXPECT_FALSE(url_with_two_dots.DomainIs("google.com"));
714 }
715 
TEST(GURLTest,DomainIsWithFilesystemScheme)716 TEST(GURLTest, DomainIsWithFilesystemScheme) {
717   GURL url_1("filesystem:http://www.google.com:99/foo/");
718   EXPECT_TRUE(url_1.DomainIs("google.com"));
719 
720   GURL url_2("filesystem:http://www.iamnotgoogle.com/foo/");
721   EXPECT_FALSE(url_2.DomainIs("google.com"));
722 }
723 
724 // Newlines should be stripped from inputs.
TEST(GURLTest,Newlines)725 TEST(GURLTest, Newlines) {
726   // Constructor.
727   GURL url_1(" \t ht\ntp://\twww.goo\rgle.com/as\ndf \n ");
728   EXPECT_EQ("http://www.google.com/asdf", url_1.spec());
729   EXPECT_FALSE(
730       url_1.parsed_for_possibly_invalid_spec().potentially_dangling_markup);
731 
732   // Relative path resolver.
733   GURL url_2 = url_1.Resolve(" \n /fo\to\r ");
734   EXPECT_EQ("http://www.google.com/foo", url_2.spec());
735   EXPECT_FALSE(
736       url_2.parsed_for_possibly_invalid_spec().potentially_dangling_markup);
737 
738   // Constructor.
739   GURL url_3(" \t ht\ntp://\twww.goo\rgle.com/as\ndf< \n ");
740   EXPECT_EQ("http://www.google.com/asdf%3C", url_3.spec());
741   EXPECT_TRUE(
742       url_3.parsed_for_possibly_invalid_spec().potentially_dangling_markup);
743 
744   // Relative path resolver.
745   GURL url_4 = url_1.Resolve(" \n /fo\to<\r ");
746   EXPECT_EQ("http://www.google.com/foo%3C", url_4.spec());
747   EXPECT_TRUE(
748       url_4.parsed_for_possibly_invalid_spec().potentially_dangling_markup);
749 
750   // Note that newlines are NOT stripped from ReplaceComponents.
751 }
752 
TEST(GURLTest,IsStandard)753 TEST(GURLTest, IsStandard) {
754   GURL a("http:foo/bar");
755   EXPECT_TRUE(a.IsStandard());
756 
757   GURL b("foo:bar/baz");
758   EXPECT_FALSE(b.IsStandard());
759 
760   GURL c("foo://bar/baz");
761   EXPECT_FALSE(c.IsStandard());
762 
763   GURL d("cid:bar@baz");
764   EXPECT_FALSE(d.IsStandard());
765 }
766 
TEST(GURLTest,SchemeIsHTTPOrHTTPS)767 TEST(GURLTest, SchemeIsHTTPOrHTTPS) {
768   EXPECT_TRUE(GURL("http://bar/").SchemeIsHTTPOrHTTPS());
769   EXPECT_TRUE(GURL("HTTPS://BAR").SchemeIsHTTPOrHTTPS());
770   EXPECT_FALSE(GURL("ftp://bar/").SchemeIsHTTPOrHTTPS());
771 }
772 
TEST(GURLTest,SchemeIsWSOrWSS)773 TEST(GURLTest, SchemeIsWSOrWSS) {
774   EXPECT_TRUE(GURL("WS://BAR/").SchemeIsWSOrWSS());
775   EXPECT_TRUE(GURL("wss://bar/").SchemeIsWSOrWSS());
776   EXPECT_FALSE(GURL("http://bar/").SchemeIsWSOrWSS());
777 }
778 
TEST(GURLTest,SchemeIsCryptographic)779 TEST(GURLTest, SchemeIsCryptographic) {
780   EXPECT_TRUE(GURL("https://foo.bar.com/").SchemeIsCryptographic());
781   EXPECT_TRUE(GURL("HTTPS://foo.bar.com/").SchemeIsCryptographic());
782   EXPECT_TRUE(GURL("HtTpS://foo.bar.com/").SchemeIsCryptographic());
783 
784   EXPECT_TRUE(GURL("wss://foo.bar.com/").SchemeIsCryptographic());
785   EXPECT_TRUE(GURL("WSS://foo.bar.com/").SchemeIsCryptographic());
786   EXPECT_TRUE(GURL("WsS://foo.bar.com/").SchemeIsCryptographic());
787 
788   EXPECT_FALSE(GURL("http://foo.bar.com/").SchemeIsCryptographic());
789   EXPECT_FALSE(GURL("ws://foo.bar.com/").SchemeIsCryptographic());
790 }
791 
TEST(GURLTest,SchemeIsCryptographicStatic)792 TEST(GURLTest, SchemeIsCryptographicStatic) {
793   EXPECT_TRUE(GURL::SchemeIsCryptographic("https"));
794   EXPECT_TRUE(GURL::SchemeIsCryptographic("wss"));
795   EXPECT_FALSE(GURL::SchemeIsCryptographic("http"));
796   EXPECT_FALSE(GURL::SchemeIsCryptographic("ws"));
797   EXPECT_FALSE(GURL::SchemeIsCryptographic("ftp"));
798 }
799 
TEST(GURLTest,SchemeIsBlob)800 TEST(GURLTest, SchemeIsBlob) {
801   EXPECT_TRUE(GURL("BLOB://BAR/").SchemeIsBlob());
802   EXPECT_TRUE(GURL("blob://bar/").SchemeIsBlob());
803   EXPECT_FALSE(GURL("http://bar/").SchemeIsBlob());
804 }
805 
806 // Tests that the 'content' of the URL is properly extracted. This can be
807 // complex in cases such as multiple schemes (view-source:http:) or for
808 // javascript URLs. See GURL::GetContent for more details.
TEST(GURLTest,ContentForNonStandardURLs)809 TEST(GURLTest, ContentForNonStandardURLs) {
810   struct TestCase {
811     const char* url;
812     const char* expected;
813   } cases[] = {
814       {"null", ""},
815       {"not-a-standard-scheme:this is arbitrary content",
816        "this is arbitrary content"},
817 
818       // When there are multiple schemes, only the first is excluded from the
819       // content. Note also that for e.g. 'http://', the '//' is part of the
820       // content not the scheme.
821       {"view-source:http://example.com/path", "http://example.com/path"},
822       {"blob:http://example.com/GUID", "http://example.com/GUID"},
823       {"blob://http://example.com/GUID", "//http://example.com/GUID"},
824       {"blob:http://user:password@example.com/GUID",
825        "http://user:password@example.com/GUID"},
826 
827       // The octothorpe character ('#') marks the end of the URL content, and
828       // the start of the fragment. It should not be included in the content.
829       {"http://www.example.com/GUID#ref", "www.example.com/GUID"},
830       {"http://me:secret@example.com/GUID/#ref", "me:secret@example.com/GUID/"},
831       {"data:text/html,Question?<div style=\"color: #bad\">idea</div>",
832        "text/html,Question?<div style=\"color: "},
833 
834       // TODO(mkwst): This seems like a bug. https://crbug.com/513600
835       {"filesystem:http://example.com/path", "/"},
836 
837       // Javascript URLs include '#' symbols in their content.
838       {"javascript:#", "#"},
839       {"javascript:alert('#');", "alert('#');"},
840   };
841 
842   for (const auto& test : cases) {
843     GURL url(test.url);
844     EXPECT_EQ(test.expected, url.GetContent()) << test.url;
845   }
846 }
847 
848 // Tests that the URL path is properly extracted for unusual URLs. This can be
849 // complex in cases such as multiple schemes (view-source:http:) or when
850 // octothorpes ('#') are involved.
TEST(GURLTest,PathForNonStandardURLs)851 TEST(GURLTest, PathForNonStandardURLs) {
852   struct TestCase {
853     const char* url;
854     const char* expected;
855   } cases[] = {
856       {"null", ""},
857       {"not-a-standard-scheme:this is arbitrary content",
858        "this is arbitrary content"},
859       {"view-source:http://example.com/path", "http://example.com/path"},
860       {"blob:http://example.com/GUID", "http://example.com/GUID"},
861       {"blob://http://example.com/GUID", "//http://example.com/GUID"},
862       {"blob:http://user:password@example.com/GUID",
863        "http://user:password@example.com/GUID"},
864 
865       {"http://www.example.com/GUID#ref", "/GUID"},
866       {"http://me:secret@example.com/GUID/#ref", "/GUID/"},
867       {"data:text/html,Question?<div style=\"color: #bad\">idea</div>",
868        "text/html,Question"},
869 
870       // TODO(mkwst): This seems like a bug. https://crbug.com/513600
871       {"filesystem:http://example.com/path", "/"},
872   };
873 
874   for (const auto& test : cases) {
875     GURL url(test.url);
876     EXPECT_EQ(test.expected, url.path()) << test.url;
877   }
878 }
879 
TEST(GURLTest,IsAboutBlank)880 TEST(GURLTest, IsAboutBlank) {
881   const std::string kAboutBlankUrls[] = {"about:blank", "about:blank?foo",
882                                          "about:blank/#foo",
883                                          "about:blank?foo#foo"};
884   for (const auto& url : kAboutBlankUrls)
885     EXPECT_TRUE(GURL(url).IsAboutBlank()) << url;
886 
887   const std::string kNotAboutBlankUrls[] = {
888       "http:blank",      "about:blan",          "about://blank",
889       "about:blank/foo", "about://:8000/blank", "about://foo:foo@/blank",
890       "foo@about:blank", "foo:bar@about:blank", "about:blank:8000",
891       "about:blANk"};
892   for (const auto& url : kNotAboutBlankUrls)
893     EXPECT_FALSE(GURL(url).IsAboutBlank()) << url;
894 }
895 
TEST(GURLTest,IsAboutSrcdoc)896 TEST(GURLTest, IsAboutSrcdoc) {
897   const std::string kAboutSrcdocUrls[] = {
898       "about:srcdoc", "about:srcdoc/", "about:srcdoc?foo", "about:srcdoc/#foo",
899       "about:srcdoc?foo#foo"};
900   for (const auto& url : kAboutSrcdocUrls)
901     EXPECT_TRUE(GURL(url).IsAboutSrcdoc()) << url;
902 
903   const std::string kNotAboutSrcdocUrls[] = {"http:srcdoc",
904                                              "about:srcdo",
905                                              "about://srcdoc",
906                                              "about://srcdoc\\",
907                                              "about:srcdoc/foo",
908                                              "about://:8000/srcdoc",
909                                              "about://foo:foo@/srcdoc",
910                                              "foo@about:srcdoc",
911                                              "foo:bar@about:srcdoc",
912                                              "about:srcdoc:8000",
913                                              "about:srCDOc"};
914   for (const auto& url : kNotAboutSrcdocUrls)
915     EXPECT_FALSE(GURL(url).IsAboutSrcdoc()) << url;
916 }
917 
TEST(GURLTest,EqualsIgnoringRef)918 TEST(GURLTest, EqualsIgnoringRef) {
919   const struct {
920     const char* url_a;
921     const char* url_b;
922     bool are_equals;
923   } kTestCases[] = {
924       // No ref.
925       {"http://a.com", "http://a.com", true},
926       {"http://a.com", "http://b.com", false},
927 
928       // Same Ref.
929       {"http://a.com#foo", "http://a.com#foo", true},
930       {"http://a.com#foo", "http://b.com#foo", false},
931 
932       // Different Refs.
933       {"http://a.com#foo", "http://a.com#bar", true},
934       {"http://a.com#foo", "http://b.com#bar", false},
935 
936       // One has a ref, the other doesn't.
937       {"http://a.com#foo", "http://a.com", true},
938       {"http://a.com#foo", "http://b.com", false},
939 
940       // Empty refs.
941       {"http://a.com#", "http://a.com#", true},
942       {"http://a.com#", "http://a.com", true},
943 
944       // URLs that differ only by their last character.
945       {"http://aaa", "http://aab", false},
946       {"http://aaa#foo", "http://aab#foo", false},
947 
948       // Different size of the part before the ref.
949       {"http://123#a", "http://123456#a", false},
950 
951       // Blob URLs
952       {"blob:http://a.com#foo", "blob:http://a.com#foo", true},
953       {"blob:http://a.com#foo", "blob:http://a.com#bar", true},
954       {"blob:http://a.com#foo", "blob:http://b.com#bar", false},
955 
956       // Filesystem URLs
957       {"filesystem:http://a.com#foo", "filesystem:http://a.com#foo", true},
958       {"filesystem:http://a.com#foo", "filesystem:http://a.com#bar", true},
959       {"filesystem:http://a.com#foo", "filesystem:http://b.com#bar", false},
960 
961       // Data URLs
962       {"data:text/html,a#foo", "data:text/html,a#bar", true},
963       {"data:text/html,a#foo", "data:text/html,a#foo", true},
964       {"data:text/html,a#foo", "data:text/html,b#foo", false},
965   };
966 
967   for (const auto& test_case : kTestCases) {
968     SCOPED_TRACE(testing::Message()
969                  << std::endl
970                  << "url_a = " << test_case.url_a << std::endl
971                  << "url_b = " << test_case.url_b << std::endl);
972     // A versus B.
973     EXPECT_EQ(test_case.are_equals,
974               GURL(test_case.url_a).EqualsIgnoringRef(GURL(test_case.url_b)));
975     // B versus A.
976     EXPECT_EQ(test_case.are_equals,
977               GURL(test_case.url_b).EqualsIgnoringRef(GURL(test_case.url_a)));
978   }
979 }
980 
TEST(GURLTest,DebugAlias)981 TEST(GURLTest, DebugAlias) {
982   GURL url("https://foo.com/bar");
983   DEBUG_ALIAS_FOR_GURL(url_debug_alias, url);
984   EXPECT_STREQ("https://foo.com/bar", url_debug_alias);
985 }
986 
TEST(GURLTest,PortZero)987 TEST(GURLTest, PortZero) {
988   GURL port_zero_url("http://127.0.0.1:0/blah");
989 
990   // https://url.spec.whatwg.org/#port-state says that the port 1) consists of
991   // ASCII digits (this excludes negative numbers) and 2) cannot be greater than
992   // 2^16-1.  This means that port=0 should be valid.
993   EXPECT_TRUE(port_zero_url.is_valid());
994   EXPECT_EQ("0", port_zero_url.port());
995   EXPECT_EQ("127.0.0.1", port_zero_url.host());
996   EXPECT_EQ("http", port_zero_url.scheme());
997 
998   // https://crbug.com/1065532: SchemeHostPort would previously incorrectly
999   // consider port=0 to be invalid.
1000   SchemeHostPort scheme_host_port(port_zero_url);
1001   EXPECT_TRUE(scheme_host_port.IsValid());
1002   EXPECT_EQ(port_zero_url.scheme(), scheme_host_port.scheme());
1003   EXPECT_EQ(port_zero_url.host(), scheme_host_port.host());
1004   EXPECT_EQ(port_zero_url.port(),
1005             base::NumberToString(scheme_host_port.port()));
1006 
1007   // https://crbug.com/1065532: The SchemeHostPort problem above would lead to
1008   // bizarre results below - resolved origin would incorrectly be returned as an
1009   // opaque origin derived from |another_origin|.
1010   url::Origin another_origin = url::Origin::Create(GURL("http://other.com"));
1011   url::Origin resolved_origin =
1012       url::Origin::Resolve(port_zero_url, another_origin);
1013   EXPECT_FALSE(resolved_origin.opaque());
1014   EXPECT_EQ(port_zero_url.scheme(), resolved_origin.scheme());
1015   EXPECT_EQ(port_zero_url.host(), resolved_origin.host());
1016   EXPECT_EQ(port_zero_url.port(), base::NumberToString(resolved_origin.port()));
1017 
1018   // port=0 and default HTTP port are different.
1019   GURL default_port("http://127.0.0.1/foo");
1020   EXPECT_EQ(0, SchemeHostPort(port_zero_url).port());
1021   EXPECT_EQ(80, SchemeHostPort(default_port).port());
1022   url::Origin default_port_origin = url::Origin::Create(default_port);
1023   EXPECT_FALSE(default_port_origin.IsSameOriginWith(resolved_origin));
1024 }
1025 
1026 }  // namespace url
1027