1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "url/url_util.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include <optional>
10*6777b538SAndroid Build Coastguard Worker #include <string_view>
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker #include "base/test/scoped_feature_list.h"
13*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
14*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest-message.h"
15*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
16*6777b538SAndroid Build Coastguard Worker #include "url/third_party/mozilla/url_parse.h"
17*6777b538SAndroid Build Coastguard Worker #include "url/url_canon.h"
18*6777b538SAndroid Build Coastguard Worker #include "url/url_canon_stdstring.h"
19*6777b538SAndroid Build Coastguard Worker #include "url/url_features.h"
20*6777b538SAndroid Build Coastguard Worker #include "url/url_test_utils.h"
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard Worker namespace url {
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker class URLUtilTest : public testing::Test {
25*6777b538SAndroid Build Coastguard Worker public:
26*6777b538SAndroid Build Coastguard Worker URLUtilTest() = default;
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker URLUtilTest(const URLUtilTest&) = delete;
29*6777b538SAndroid Build Coastguard Worker URLUtilTest& operator=(const URLUtilTest&) = delete;
30*6777b538SAndroid Build Coastguard Worker
31*6777b538SAndroid Build Coastguard Worker ~URLUtilTest() override = default;
32*6777b538SAndroid Build Coastguard Worker
33*6777b538SAndroid Build Coastguard Worker private:
34*6777b538SAndroid Build Coastguard Worker ScopedSchemeRegistryForTests scoped_registry_;
35*6777b538SAndroid Build Coastguard Worker };
36*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,FindAndCompareScheme)37*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, FindAndCompareScheme) {
38*6777b538SAndroid Build Coastguard Worker Component found_scheme;
39*6777b538SAndroid Build Coastguard Worker
40*6777b538SAndroid Build Coastguard Worker // Simple case where the scheme is found and matches.
41*6777b538SAndroid Build Coastguard Worker const char kStr1[] = "http://www.com/";
42*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(FindAndCompareScheme(kStr1, static_cast<int>(strlen(kStr1)),
43*6777b538SAndroid Build Coastguard Worker "http", nullptr));
44*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(FindAndCompareScheme(
45*6777b538SAndroid Build Coastguard Worker kStr1, static_cast<int>(strlen(kStr1)), "http", &found_scheme));
46*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(found_scheme == Component(0, 4));
47*6777b538SAndroid Build Coastguard Worker
48*6777b538SAndroid Build Coastguard Worker // A case where the scheme is found and doesn't match.
49*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(FindAndCompareScheme(
50*6777b538SAndroid Build Coastguard Worker kStr1, static_cast<int>(strlen(kStr1)), "https", &found_scheme));
51*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(found_scheme == Component(0, 4));
52*6777b538SAndroid Build Coastguard Worker
53*6777b538SAndroid Build Coastguard Worker // A case where there is no scheme.
54*6777b538SAndroid Build Coastguard Worker const char kStr2[] = "httpfoobar";
55*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(FindAndCompareScheme(
56*6777b538SAndroid Build Coastguard Worker kStr2, static_cast<int>(strlen(kStr2)), "http", &found_scheme));
57*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(found_scheme == Component());
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker // When there is an empty scheme, it should match the empty scheme.
60*6777b538SAndroid Build Coastguard Worker const char kStr3[] = ":foo.com/";
61*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(FindAndCompareScheme(
62*6777b538SAndroid Build Coastguard Worker kStr3, static_cast<int>(strlen(kStr3)), "", &found_scheme));
63*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(found_scheme == Component(0, 0));
64*6777b538SAndroid Build Coastguard Worker
65*6777b538SAndroid Build Coastguard Worker // But when there is no scheme, it should fail.
66*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(FindAndCompareScheme("", 0, "", &found_scheme));
67*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(found_scheme == Component());
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker // When there is a whitespace char in scheme, it should canonicalize the URL
70*6777b538SAndroid Build Coastguard Worker // before comparison.
71*6777b538SAndroid Build Coastguard Worker const char whtspc_str[] = " \r\n\tjav\ra\nscri\tpt:alert(1)";
72*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(FindAndCompareScheme(whtspc_str,
73*6777b538SAndroid Build Coastguard Worker static_cast<int>(strlen(whtspc_str)),
74*6777b538SAndroid Build Coastguard Worker "javascript", &found_scheme));
75*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(found_scheme == Component(1, 10));
76*6777b538SAndroid Build Coastguard Worker
77*6777b538SAndroid Build Coastguard Worker // Control characters should be stripped out on the ends, and kept in the
78*6777b538SAndroid Build Coastguard Worker // middle.
79*6777b538SAndroid Build Coastguard Worker const char ctrl_str[] = "\02jav\02scr\03ipt:alert(1)";
80*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(FindAndCompareScheme(ctrl_str,
81*6777b538SAndroid Build Coastguard Worker static_cast<int>(strlen(ctrl_str)),
82*6777b538SAndroid Build Coastguard Worker "javascript", &found_scheme));
83*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(found_scheme == Component(1, 11));
84*6777b538SAndroid Build Coastguard Worker }
85*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,IsStandard)86*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, IsStandard) {
87*6777b538SAndroid Build Coastguard Worker const char kHTTPScheme[] = "http";
88*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsStandard(kHTTPScheme, Component(0, strlen(kHTTPScheme))));
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker const char kFooScheme[] = "foo";
91*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(IsStandard(kFooScheme, Component(0, strlen(kFooScheme))));
92*6777b538SAndroid Build Coastguard Worker }
93*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,IsReferrerScheme)94*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, IsReferrerScheme) {
95*6777b538SAndroid Build Coastguard Worker const char kHTTPScheme[] = "http";
96*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsReferrerScheme(kHTTPScheme, Component(0, strlen(kHTTPScheme))));
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker const char kFooScheme[] = "foo";
99*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(IsReferrerScheme(kFooScheme, Component(0, strlen(kFooScheme))));
100*6777b538SAndroid Build Coastguard Worker }
101*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,AddReferrerScheme)102*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, AddReferrerScheme) {
103*6777b538SAndroid Build Coastguard Worker static const char kFooScheme[] = "foo";
104*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(IsReferrerScheme(kFooScheme, Component(0, strlen(kFooScheme))));
105*6777b538SAndroid Build Coastguard Worker
106*6777b538SAndroid Build Coastguard Worker url::ScopedSchemeRegistryForTests scoped_registry;
107*6777b538SAndroid Build Coastguard Worker AddReferrerScheme(kFooScheme, url::SCHEME_WITH_HOST);
108*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsReferrerScheme(kFooScheme, Component(0, strlen(kFooScheme))));
109*6777b538SAndroid Build Coastguard Worker }
110*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,ShutdownCleansUpSchemes)111*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, ShutdownCleansUpSchemes) {
112*6777b538SAndroid Build Coastguard Worker static const char kFooScheme[] = "foo";
113*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(IsReferrerScheme(kFooScheme, Component(0, strlen(kFooScheme))));
114*6777b538SAndroid Build Coastguard Worker
115*6777b538SAndroid Build Coastguard Worker {
116*6777b538SAndroid Build Coastguard Worker url::ScopedSchemeRegistryForTests scoped_registry;
117*6777b538SAndroid Build Coastguard Worker AddReferrerScheme(kFooScheme, url::SCHEME_WITH_HOST);
118*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(IsReferrerScheme(kFooScheme, Component(0, strlen(kFooScheme))));
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker
121*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(IsReferrerScheme(kFooScheme, Component(0, strlen(kFooScheme))));
122*6777b538SAndroid Build Coastguard Worker }
123*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,GetStandardSchemeType)124*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, GetStandardSchemeType) {
125*6777b538SAndroid Build Coastguard Worker url::SchemeType scheme_type;
126*6777b538SAndroid Build Coastguard Worker
127*6777b538SAndroid Build Coastguard Worker const char kHTTPScheme[] = "http";
128*6777b538SAndroid Build Coastguard Worker scheme_type = url::SCHEME_WITHOUT_AUTHORITY;
129*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(GetStandardSchemeType(kHTTPScheme,
130*6777b538SAndroid Build Coastguard Worker Component(0, strlen(kHTTPScheme)),
131*6777b538SAndroid Build Coastguard Worker &scheme_type));
132*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION, scheme_type);
133*6777b538SAndroid Build Coastguard Worker
134*6777b538SAndroid Build Coastguard Worker const char kFilesystemScheme[] = "filesystem";
135*6777b538SAndroid Build Coastguard Worker scheme_type = url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION;
136*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(GetStandardSchemeType(kFilesystemScheme,
137*6777b538SAndroid Build Coastguard Worker Component(0, strlen(kFilesystemScheme)),
138*6777b538SAndroid Build Coastguard Worker &scheme_type));
139*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(url::SCHEME_WITHOUT_AUTHORITY, scheme_type);
140*6777b538SAndroid Build Coastguard Worker
141*6777b538SAndroid Build Coastguard Worker const char kFooScheme[] = "foo";
142*6777b538SAndroid Build Coastguard Worker scheme_type = url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION;
143*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(GetStandardSchemeType(kFooScheme,
144*6777b538SAndroid Build Coastguard Worker Component(0, strlen(kFooScheme)),
145*6777b538SAndroid Build Coastguard Worker &scheme_type));
146*6777b538SAndroid Build Coastguard Worker }
147*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,GetStandardSchemes)148*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, GetStandardSchemes) {
149*6777b538SAndroid Build Coastguard Worker std::vector<std::string> expected = {
150*6777b538SAndroid Build Coastguard Worker kHttpsScheme, kHttpScheme, kFileScheme, kFtpScheme,
151*6777b538SAndroid Build Coastguard Worker kWssScheme, kWsScheme, kFileSystemScheme, "foo",
152*6777b538SAndroid Build Coastguard Worker };
153*6777b538SAndroid Build Coastguard Worker AddStandardScheme("foo", url::SCHEME_WITHOUT_AUTHORITY);
154*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(expected, GetStandardSchemes());
155*6777b538SAndroid Build Coastguard Worker }
156*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,ReplaceComponents)157*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, ReplaceComponents) {
158*6777b538SAndroid Build Coastguard Worker Parsed parsed;
159*6777b538SAndroid Build Coastguard Worker RawCanonOutputT<char> output;
160*6777b538SAndroid Build Coastguard Worker Parsed new_parsed;
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard Worker // Check that the following calls do not cause crash
163*6777b538SAndroid Build Coastguard Worker Replacements<char> replacements;
164*6777b538SAndroid Build Coastguard Worker replacements.SetRef("test", Component(0, 4));
165*6777b538SAndroid Build Coastguard Worker ReplaceComponents(nullptr, 0, parsed, replacements, nullptr, &output,
166*6777b538SAndroid Build Coastguard Worker &new_parsed);
167*6777b538SAndroid Build Coastguard Worker ReplaceComponents("", 0, parsed, replacements, nullptr, &output, &new_parsed);
168*6777b538SAndroid Build Coastguard Worker replacements.ClearRef();
169*6777b538SAndroid Build Coastguard Worker replacements.SetHost("test", Component(0, 4));
170*6777b538SAndroid Build Coastguard Worker ReplaceComponents(nullptr, 0, parsed, replacements, nullptr, &output,
171*6777b538SAndroid Build Coastguard Worker &new_parsed);
172*6777b538SAndroid Build Coastguard Worker ReplaceComponents("", 0, parsed, replacements, nullptr, &output, &new_parsed);
173*6777b538SAndroid Build Coastguard Worker
174*6777b538SAndroid Build Coastguard Worker replacements.ClearHost();
175*6777b538SAndroid Build Coastguard Worker ReplaceComponents(nullptr, 0, parsed, replacements, nullptr, &output,
176*6777b538SAndroid Build Coastguard Worker &new_parsed);
177*6777b538SAndroid Build Coastguard Worker ReplaceComponents("", 0, parsed, replacements, nullptr, &output, &new_parsed);
178*6777b538SAndroid Build Coastguard Worker ReplaceComponents(nullptr, 0, parsed, replacements, nullptr, &output,
179*6777b538SAndroid Build Coastguard Worker &new_parsed);
180*6777b538SAndroid Build Coastguard Worker ReplaceComponents("", 0, parsed, replacements, nullptr, &output, &new_parsed);
181*6777b538SAndroid Build Coastguard Worker }
182*6777b538SAndroid Build Coastguard Worker
CheckReplaceScheme(const char * base_url,const char * scheme)183*6777b538SAndroid Build Coastguard Worker static std::string CheckReplaceScheme(const char* base_url,
184*6777b538SAndroid Build Coastguard Worker const char* scheme) {
185*6777b538SAndroid Build Coastguard Worker // Make sure the input is canonicalized.
186*6777b538SAndroid Build Coastguard Worker RawCanonOutput<32> original;
187*6777b538SAndroid Build Coastguard Worker Parsed original_parsed;
188*6777b538SAndroid Build Coastguard Worker Canonicalize(base_url, strlen(base_url), true, nullptr, &original,
189*6777b538SAndroid Build Coastguard Worker &original_parsed);
190*6777b538SAndroid Build Coastguard Worker
191*6777b538SAndroid Build Coastguard Worker Replacements<char> replacements;
192*6777b538SAndroid Build Coastguard Worker replacements.SetScheme(scheme, Component(0, strlen(scheme)));
193*6777b538SAndroid Build Coastguard Worker
194*6777b538SAndroid Build Coastguard Worker std::string output_string;
195*6777b538SAndroid Build Coastguard Worker StdStringCanonOutput output(&output_string);
196*6777b538SAndroid Build Coastguard Worker Parsed output_parsed;
197*6777b538SAndroid Build Coastguard Worker ReplaceComponents(original.data(), original.length(), original_parsed,
198*6777b538SAndroid Build Coastguard Worker replacements, nullptr, &output, &output_parsed);
199*6777b538SAndroid Build Coastguard Worker
200*6777b538SAndroid Build Coastguard Worker output.Complete();
201*6777b538SAndroid Build Coastguard Worker return output_string;
202*6777b538SAndroid Build Coastguard Worker }
203*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,ReplaceScheme)204*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, ReplaceScheme) {
205*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("https://google.com/",
206*6777b538SAndroid Build Coastguard Worker CheckReplaceScheme("http://google.com/", "https"));
207*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("file://google.com/",
208*6777b538SAndroid Build Coastguard Worker CheckReplaceScheme("http://google.com/", "file"));
209*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("http://home/Build",
210*6777b538SAndroid Build Coastguard Worker CheckReplaceScheme("file:///Home/Build", "http"));
211*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("javascript:foo",
212*6777b538SAndroid Build Coastguard Worker CheckReplaceScheme("about:foo", "javascript"));
213*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("://google.com/",
214*6777b538SAndroid Build Coastguard Worker CheckReplaceScheme("http://google.com/", ""));
215*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("http://google.com/",
216*6777b538SAndroid Build Coastguard Worker CheckReplaceScheme("about:google.com", "http"));
217*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("http:", CheckReplaceScheme("", "http"));
218*6777b538SAndroid Build Coastguard Worker
219*6777b538SAndroid Build Coastguard Worker #ifdef WIN32
220*6777b538SAndroid Build Coastguard Worker // Magic Windows drive letter behavior when converting to a file URL.
221*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("file:///E:/foo/",
222*6777b538SAndroid Build Coastguard Worker CheckReplaceScheme("http://localhost/e:foo/", "file"));
223*6777b538SAndroid Build Coastguard Worker #endif
224*6777b538SAndroid Build Coastguard Worker
225*6777b538SAndroid Build Coastguard Worker // This will probably change to "about://google.com/" when we fix
226*6777b538SAndroid Build Coastguard Worker // http://crbug.com/160 which should also be an acceptable result.
227*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("about://google.com/",
228*6777b538SAndroid Build Coastguard Worker CheckReplaceScheme("http://google.com/", "about"));
229*6777b538SAndroid Build Coastguard Worker
230*6777b538SAndroid Build Coastguard Worker EXPECT_EQ("http://example.com/%20hello%20#%20world",
231*6777b538SAndroid Build Coastguard Worker CheckReplaceScheme("myscheme:example.com/ hello # world ", "http"));
232*6777b538SAndroid Build Coastguard Worker }
233*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,DecodeURLEscapeSequences)234*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, DecodeURLEscapeSequences) {
235*6777b538SAndroid Build Coastguard Worker struct DecodeCase {
236*6777b538SAndroid Build Coastguard Worker const char* input;
237*6777b538SAndroid Build Coastguard Worker const char* output;
238*6777b538SAndroid Build Coastguard Worker } decode_cases[] = {
239*6777b538SAndroid Build Coastguard Worker {"hello, world", "hello, world"},
240*6777b538SAndroid Build Coastguard Worker {"%01%02%03%04%05%06%07%08%09%0a%0B%0C%0D%0e%0f/",
241*6777b538SAndroid Build Coastguard Worker "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0B\x0C\x0D\x0e\x0f/"},
242*6777b538SAndroid Build Coastguard Worker {"%10%11%12%13%14%15%16%17%18%19%1a%1B%1C%1D%1e%1f/",
243*6777b538SAndroid Build Coastguard Worker "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1B\x1C\x1D\x1e\x1f/"},
244*6777b538SAndroid Build Coastguard Worker {"%20%21%22%23%24%25%26%27%28%29%2a%2B%2C%2D%2e%2f/",
245*6777b538SAndroid Build Coastguard Worker " !\"#$%&'()*+,-.//"},
246*6777b538SAndroid Build Coastguard Worker {"%30%31%32%33%34%35%36%37%38%39%3a%3B%3C%3D%3e%3f/",
247*6777b538SAndroid Build Coastguard Worker "0123456789:;<=>?/"},
248*6777b538SAndroid Build Coastguard Worker {"%40%41%42%43%44%45%46%47%48%49%4a%4B%4C%4D%4e%4f/",
249*6777b538SAndroid Build Coastguard Worker "@ABCDEFGHIJKLMNO/"},
250*6777b538SAndroid Build Coastguard Worker {"%50%51%52%53%54%55%56%57%58%59%5a%5B%5C%5D%5e%5f/",
251*6777b538SAndroid Build Coastguard Worker "PQRSTUVWXYZ[\\]^_/"},
252*6777b538SAndroid Build Coastguard Worker {"%60%61%62%63%64%65%66%67%68%69%6a%6B%6C%6D%6e%6f/",
253*6777b538SAndroid Build Coastguard Worker "`abcdefghijklmno/"},
254*6777b538SAndroid Build Coastguard Worker {"%70%71%72%73%74%75%76%77%78%79%7a%7B%7C%7D%7e%7f/",
255*6777b538SAndroid Build Coastguard Worker "pqrstuvwxyz{|}~\x7f/"},
256*6777b538SAndroid Build Coastguard Worker {"%e4%bd%a0%e5%a5%bd", "\xe4\xbd\xa0\xe5\xa5\xbd"},
257*6777b538SAndroid Build Coastguard Worker // U+FFFF (Noncharacter) should not be replaced with U+FFFD (Replacement
258*6777b538SAndroid Build Coastguard Worker // Character) (http://crbug.com/1416021)
259*6777b538SAndroid Build Coastguard Worker {"%ef%bf%bf", "\xef\xbf\xbf"},
260*6777b538SAndroid Build Coastguard Worker // U+FDD0 (Noncharacter)
261*6777b538SAndroid Build Coastguard Worker {"%ef%b7%90", "\xef\xb7\x90"},
262*6777b538SAndroid Build Coastguard Worker // U+FFFD (Replacement Character)
263*6777b538SAndroid Build Coastguard Worker {"%ef%bf%bd", "\xef\xbf\xbd"},
264*6777b538SAndroid Build Coastguard Worker };
265*6777b538SAndroid Build Coastguard Worker
266*6777b538SAndroid Build Coastguard Worker for (const auto& decode_case : decode_cases) {
267*6777b538SAndroid Build Coastguard Worker RawCanonOutputT<char16_t> output;
268*6777b538SAndroid Build Coastguard Worker DecodeURLEscapeSequences(decode_case.input,
269*6777b538SAndroid Build Coastguard Worker DecodeURLMode::kUTF8OrIsomorphic, &output);
270*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(decode_case.output, base::UTF16ToUTF8(std::u16string(
271*6777b538SAndroid Build Coastguard Worker output.data(), output.length())));
272*6777b538SAndroid Build Coastguard Worker
273*6777b538SAndroid Build Coastguard Worker RawCanonOutputT<char16_t> output_utf8;
274*6777b538SAndroid Build Coastguard Worker DecodeURLEscapeSequences(decode_case.input, DecodeURLMode::kUTF8,
275*6777b538SAndroid Build Coastguard Worker &output_utf8);
276*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(decode_case.output,
277*6777b538SAndroid Build Coastguard Worker base::UTF16ToUTF8(
278*6777b538SAndroid Build Coastguard Worker std::u16string(output_utf8.data(), output_utf8.length())));
279*6777b538SAndroid Build Coastguard Worker }
280*6777b538SAndroid Build Coastguard Worker
281*6777b538SAndroid Build Coastguard Worker // Our decode should decode %00
282*6777b538SAndroid Build Coastguard Worker const char zero_input[] = "%00";
283*6777b538SAndroid Build Coastguard Worker RawCanonOutputT<char16_t> zero_output;
284*6777b538SAndroid Build Coastguard Worker DecodeURLEscapeSequences(zero_input, DecodeURLMode::kUTF8, &zero_output);
285*6777b538SAndroid Build Coastguard Worker EXPECT_NE("%00", base::UTF16ToUTF8(std::u16string(zero_output.data(),
286*6777b538SAndroid Build Coastguard Worker zero_output.length())));
287*6777b538SAndroid Build Coastguard Worker
288*6777b538SAndroid Build Coastguard Worker // Test the error behavior for invalid UTF-8.
289*6777b538SAndroid Build Coastguard Worker struct Utf8DecodeCase {
290*6777b538SAndroid Build Coastguard Worker const char* input;
291*6777b538SAndroid Build Coastguard Worker std::vector<char16_t> expected_iso;
292*6777b538SAndroid Build Coastguard Worker std::vector<char16_t> expected_utf8;
293*6777b538SAndroid Build Coastguard Worker } utf8_decode_cases[] = {
294*6777b538SAndroid Build Coastguard Worker // %e5%a5%bd is a valid UTF-8 sequence. U+597D
295*6777b538SAndroid Build Coastguard Worker {"%e4%a0%e5%a5%bd",
296*6777b538SAndroid Build Coastguard Worker {0x00e4, 0x00a0, 0x00e5, 0x00a5, 0x00bd, 0},
297*6777b538SAndroid Build Coastguard Worker {0xfffd, 0x597d, 0}},
298*6777b538SAndroid Build Coastguard Worker {"%e5%a5%bd%e4%a0",
299*6777b538SAndroid Build Coastguard Worker {0x00e5, 0x00a5, 0x00bd, 0x00e4, 0x00a0, 0},
300*6777b538SAndroid Build Coastguard Worker {0x597d, 0xfffd, 0}},
301*6777b538SAndroid Build Coastguard Worker {"%e4%a0%e5%bd",
302*6777b538SAndroid Build Coastguard Worker {0x00e4, 0x00a0, 0x00e5, 0x00bd, 0},
303*6777b538SAndroid Build Coastguard Worker {0xfffd, 0xfffd, 0}},
304*6777b538SAndroid Build Coastguard Worker };
305*6777b538SAndroid Build Coastguard Worker
306*6777b538SAndroid Build Coastguard Worker for (const auto& utf8_decode_case : utf8_decode_cases) {
307*6777b538SAndroid Build Coastguard Worker RawCanonOutputT<char16_t> output_iso;
308*6777b538SAndroid Build Coastguard Worker DecodeURLEscapeSequences(utf8_decode_case.input,
309*6777b538SAndroid Build Coastguard Worker DecodeURLMode::kUTF8OrIsomorphic, &output_iso);
310*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(std::u16string(utf8_decode_case.expected_iso.data()),
311*6777b538SAndroid Build Coastguard Worker std::u16string(output_iso.data(), output_iso.length()));
312*6777b538SAndroid Build Coastguard Worker
313*6777b538SAndroid Build Coastguard Worker RawCanonOutputT<char16_t> output_utf8;
314*6777b538SAndroid Build Coastguard Worker DecodeURLEscapeSequences(utf8_decode_case.input, DecodeURLMode::kUTF8,
315*6777b538SAndroid Build Coastguard Worker &output_utf8);
316*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(std::u16string(utf8_decode_case.expected_utf8.data()),
317*6777b538SAndroid Build Coastguard Worker std::u16string(output_utf8.data(), output_utf8.length()));
318*6777b538SAndroid Build Coastguard Worker }
319*6777b538SAndroid Build Coastguard Worker }
320*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,TestEncodeURIComponent)321*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, TestEncodeURIComponent) {
322*6777b538SAndroid Build Coastguard Worker struct EncodeCase {
323*6777b538SAndroid Build Coastguard Worker const char* input;
324*6777b538SAndroid Build Coastguard Worker const char* output;
325*6777b538SAndroid Build Coastguard Worker } encode_cases[] = {
326*6777b538SAndroid Build Coastguard Worker {"hello, world", "hello%2C%20world"},
327*6777b538SAndroid Build Coastguard Worker {"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
328*6777b538SAndroid Build Coastguard Worker "%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F"},
329*6777b538SAndroid Build Coastguard Worker {"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
330*6777b538SAndroid Build Coastguard Worker "%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F"},
331*6777b538SAndroid Build Coastguard Worker {" !\"#$%&'()*+,-./",
332*6777b538SAndroid Build Coastguard Worker "%20!%22%23%24%25%26%27()*%2B%2C-.%2F"},
333*6777b538SAndroid Build Coastguard Worker {"0123456789:;<=>?",
334*6777b538SAndroid Build Coastguard Worker "0123456789%3A%3B%3C%3D%3E%3F"},
335*6777b538SAndroid Build Coastguard Worker {"@ABCDEFGHIJKLMNO",
336*6777b538SAndroid Build Coastguard Worker "%40ABCDEFGHIJKLMNO"},
337*6777b538SAndroid Build Coastguard Worker {"PQRSTUVWXYZ[\\]^_",
338*6777b538SAndroid Build Coastguard Worker "PQRSTUVWXYZ%5B%5C%5D%5E_"},
339*6777b538SAndroid Build Coastguard Worker {"`abcdefghijklmno",
340*6777b538SAndroid Build Coastguard Worker "%60abcdefghijklmno"},
341*6777b538SAndroid Build Coastguard Worker {"pqrstuvwxyz{|}~\x7f",
342*6777b538SAndroid Build Coastguard Worker "pqrstuvwxyz%7B%7C%7D~%7F"},
343*6777b538SAndroid Build Coastguard Worker };
344*6777b538SAndroid Build Coastguard Worker
345*6777b538SAndroid Build Coastguard Worker for (const auto& encode_case : encode_cases) {
346*6777b538SAndroid Build Coastguard Worker RawCanonOutputT<char> buffer;
347*6777b538SAndroid Build Coastguard Worker EncodeURIComponent(encode_case.input, &buffer);
348*6777b538SAndroid Build Coastguard Worker std::string output(buffer.data(), buffer.length());
349*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(encode_case.output, output);
350*6777b538SAndroid Build Coastguard Worker }
351*6777b538SAndroid Build Coastguard Worker }
352*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,TestResolveRelativeWithNonStandardBase)353*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, TestResolveRelativeWithNonStandardBase) {
354*6777b538SAndroid Build Coastguard Worker // This tests non-standard (in the sense that IsStandard() == false)
355*6777b538SAndroid Build Coastguard Worker // hierarchical schemes.
356*6777b538SAndroid Build Coastguard Worker struct ResolveRelativeCase {
357*6777b538SAndroid Build Coastguard Worker const char* base;
358*6777b538SAndroid Build Coastguard Worker const char* rel;
359*6777b538SAndroid Build Coastguard Worker bool is_valid;
360*6777b538SAndroid Build Coastguard Worker const char* out;
361*6777b538SAndroid Build Coastguard Worker } resolve_non_standard_cases[] = {
362*6777b538SAndroid Build Coastguard Worker // Resolving a relative path against a non-hierarchical URL should fail.
363*6777b538SAndroid Build Coastguard Worker {"scheme:opaque_data", "/path", false, ""},
364*6777b538SAndroid Build Coastguard Worker // Resolving a relative path against a non-standard authority-based base
365*6777b538SAndroid Build Coastguard Worker // URL doesn't alter the authority section.
366*6777b538SAndroid Build Coastguard Worker {"scheme://Authority/", "../path", true, "scheme://Authority/path"},
367*6777b538SAndroid Build Coastguard Worker // A non-standard hierarchical base is resolved with path URL
368*6777b538SAndroid Build Coastguard Worker // canonicalization rules.
369*6777b538SAndroid Build Coastguard Worker {"data:/Blah:Blah/", "file.html", true, "data:/Blah:Blah/file.html"},
370*6777b538SAndroid Build Coastguard Worker {"data:/Path/../part/part2", "file.html", true,
371*6777b538SAndroid Build Coastguard Worker "data:/Path/../part/file.html"},
372*6777b538SAndroid Build Coastguard Worker {"data://text/html,payload", "//user:pass@host:33////payload22", true,
373*6777b538SAndroid Build Coastguard Worker "data://user:pass@host:33////payload22"},
374*6777b538SAndroid Build Coastguard Worker // Path URL canonicalization rules also apply to non-standard authority-
375*6777b538SAndroid Build Coastguard Worker // based URLs.
376*6777b538SAndroid Build Coastguard Worker {"custom://Authority/", "file.html", true,
377*6777b538SAndroid Build Coastguard Worker "custom://Authority/file.html"},
378*6777b538SAndroid Build Coastguard Worker {"custom://Authority/", "other://Auth/", true, "other://Auth/"},
379*6777b538SAndroid Build Coastguard Worker {"custom://Authority/", "../../file.html", true,
380*6777b538SAndroid Build Coastguard Worker "custom://Authority/file.html"},
381*6777b538SAndroid Build Coastguard Worker {"custom://Authority/path/", "file.html", true,
382*6777b538SAndroid Build Coastguard Worker "custom://Authority/path/file.html"},
383*6777b538SAndroid Build Coastguard Worker {"custom://Authority:NoCanon/path/", "file.html", true,
384*6777b538SAndroid Build Coastguard Worker "custom://Authority:NoCanon/path/file.html"},
385*6777b538SAndroid Build Coastguard Worker // A path with an authority section gets canonicalized under standard URL
386*6777b538SAndroid Build Coastguard Worker // rules, even though the base was non-standard.
387*6777b538SAndroid Build Coastguard Worker {"content://content.Provider/", "//other.Provider", true,
388*6777b538SAndroid Build Coastguard Worker "content://other.provider/"},
389*6777b538SAndroid Build Coastguard Worker // Resolving an absolute URL doesn't cause canonicalization of the
390*6777b538SAndroid Build Coastguard Worker // result.
391*6777b538SAndroid Build Coastguard Worker {"about:blank", "custom://Authority", true, "custom://Authority"},
392*6777b538SAndroid Build Coastguard Worker // Fragment URLs can be resolved against a non-standard base.
393*6777b538SAndroid Build Coastguard Worker {"scheme://Authority/path", "#fragment", true,
394*6777b538SAndroid Build Coastguard Worker "scheme://Authority/path#fragment"},
395*6777b538SAndroid Build Coastguard Worker {"scheme://Authority/", "#fragment", true,
396*6777b538SAndroid Build Coastguard Worker "scheme://Authority/#fragment"},
397*6777b538SAndroid Build Coastguard Worker // Test resolving a fragment (only) against any kind of base-URL.
398*6777b538SAndroid Build Coastguard Worker {"about:blank", "#id42", true, "about:blank#id42"},
399*6777b538SAndroid Build Coastguard Worker {"about:blank", " #id42", true, "about:blank#id42"},
400*6777b538SAndroid Build Coastguard Worker {"about:blank#oldfrag", "#newfrag", true, "about:blank#newfrag"},
401*6777b538SAndroid Build Coastguard Worker {"about:blank", " #id:42", true, "about:blank#id:42"},
402*6777b538SAndroid Build Coastguard Worker // A surprising side effect of allowing fragments to resolve against
403*6777b538SAndroid Build Coastguard Worker // any URL scheme is we might break javascript: URLs by doing so...
404*6777b538SAndroid Build Coastguard Worker {"javascript:alert('foo#bar')", "#badfrag", true,
405*6777b538SAndroid Build Coastguard Worker "javascript:alert('foo#badfrag"},
406*6777b538SAndroid Build Coastguard Worker };
407*6777b538SAndroid Build Coastguard Worker
408*6777b538SAndroid Build Coastguard Worker for (const auto& test : resolve_non_standard_cases) {
409*6777b538SAndroid Build Coastguard Worker SCOPED_TRACE(testing::Message()
410*6777b538SAndroid Build Coastguard Worker << "base: " << test.base << ", rel: " << test.rel);
411*6777b538SAndroid Build Coastguard Worker
412*6777b538SAndroid Build Coastguard Worker Parsed base_parsed;
413*6777b538SAndroid Build Coastguard Worker if (url::IsUsingStandardCompliantNonSpecialSchemeURLParsing()) {
414*6777b538SAndroid Build Coastguard Worker ParseNonSpecialURL(test.base, strlen(test.base), &base_parsed);
415*6777b538SAndroid Build Coastguard Worker } else {
416*6777b538SAndroid Build Coastguard Worker ParsePathURL(test.base, strlen(test.base), /*trim_path_end=*/true,
417*6777b538SAndroid Build Coastguard Worker &base_parsed);
418*6777b538SAndroid Build Coastguard Worker }
419*6777b538SAndroid Build Coastguard Worker
420*6777b538SAndroid Build Coastguard Worker std::string resolved;
421*6777b538SAndroid Build Coastguard Worker StdStringCanonOutput output(&resolved);
422*6777b538SAndroid Build Coastguard Worker Parsed resolved_parsed;
423*6777b538SAndroid Build Coastguard Worker bool valid =
424*6777b538SAndroid Build Coastguard Worker ResolveRelative(test.base, strlen(test.base), base_parsed, test.rel,
425*6777b538SAndroid Build Coastguard Worker strlen(test.rel), nullptr, &output, &resolved_parsed);
426*6777b538SAndroid Build Coastguard Worker output.Complete();
427*6777b538SAndroid Build Coastguard Worker
428*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(test.is_valid, valid);
429*6777b538SAndroid Build Coastguard Worker if (test.is_valid && valid) {
430*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(test.out, resolved);
431*6777b538SAndroid Build Coastguard Worker }
432*6777b538SAndroid Build Coastguard Worker }
433*6777b538SAndroid Build Coastguard Worker }
434*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,PotentiallyDanglingMarkup)435*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, PotentiallyDanglingMarkup) {
436*6777b538SAndroid Build Coastguard Worker struct ResolveRelativeCase {
437*6777b538SAndroid Build Coastguard Worker const char* base;
438*6777b538SAndroid Build Coastguard Worker const char* rel;
439*6777b538SAndroid Build Coastguard Worker bool potentially_dangling_markup;
440*6777b538SAndroid Build Coastguard Worker const char* out;
441*6777b538SAndroid Build Coastguard Worker } cases[] = {
442*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/path<", false, "https://example.com/path%3C"},
443*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "\n/path<", true, "https://example.com/path%3C"},
444*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "\r/path<", true, "https://example.com/path%3C"},
445*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "\t/path<", true, "https://example.com/path%3C"},
446*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/pa\nth<", true, "https://example.com/path%3C"},
447*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/pa\rth<", true, "https://example.com/path%3C"},
448*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/pa\tth<", true, "https://example.com/path%3C"},
449*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/path\n<", true, "https://example.com/path%3C"},
450*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/path\r<", true, "https://example.com/path%3C"},
451*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/path\r<", true, "https://example.com/path%3C"},
452*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "\n/<path", true, "https://example.com/%3Cpath"},
453*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "\r/<path", true, "https://example.com/%3Cpath"},
454*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "\t/<path", true, "https://example.com/%3Cpath"},
455*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/<pa\nth", true, "https://example.com/%3Cpath"},
456*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/<pa\rth", true, "https://example.com/%3Cpath"},
457*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/<pa\tth", true, "https://example.com/%3Cpath"},
458*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/<path\n", true, "https://example.com/%3Cpath"},
459*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/<path\r", true, "https://example.com/%3Cpath"},
460*6777b538SAndroid Build Coastguard Worker {"https://example.com/", "/<path\r", true, "https://example.com/%3Cpath"},
461*6777b538SAndroid Build Coastguard Worker };
462*6777b538SAndroid Build Coastguard Worker
463*6777b538SAndroid Build Coastguard Worker for (const auto& test : cases) {
464*6777b538SAndroid Build Coastguard Worker SCOPED_TRACE(::testing::Message() << test.base << ", " << test.rel);
465*6777b538SAndroid Build Coastguard Worker Parsed base_parsed;
466*6777b538SAndroid Build Coastguard Worker ParseStandardURL(test.base, strlen(test.base), &base_parsed);
467*6777b538SAndroid Build Coastguard Worker
468*6777b538SAndroid Build Coastguard Worker std::string resolved;
469*6777b538SAndroid Build Coastguard Worker StdStringCanonOutput output(&resolved);
470*6777b538SAndroid Build Coastguard Worker Parsed resolved_parsed;
471*6777b538SAndroid Build Coastguard Worker bool valid =
472*6777b538SAndroid Build Coastguard Worker ResolveRelative(test.base, strlen(test.base), base_parsed, test.rel,
473*6777b538SAndroid Build Coastguard Worker strlen(test.rel), nullptr, &output, &resolved_parsed);
474*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(valid);
475*6777b538SAndroid Build Coastguard Worker output.Complete();
476*6777b538SAndroid Build Coastguard Worker
477*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(test.potentially_dangling_markup,
478*6777b538SAndroid Build Coastguard Worker resolved_parsed.potentially_dangling_markup);
479*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(test.out, resolved);
480*6777b538SAndroid Build Coastguard Worker }
481*6777b538SAndroid Build Coastguard Worker }
482*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,PotentiallyDanglingMarkupAfterReplacement)483*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, PotentiallyDanglingMarkupAfterReplacement) {
484*6777b538SAndroid Build Coastguard Worker // Parse a URL with potentially dangling markup.
485*6777b538SAndroid Build Coastguard Worker Parsed original_parsed;
486*6777b538SAndroid Build Coastguard Worker RawCanonOutput<32> original;
487*6777b538SAndroid Build Coastguard Worker const char* url = "htt\nps://example.com/<path";
488*6777b538SAndroid Build Coastguard Worker Canonicalize(url, strlen(url), false, nullptr, &original, &original_parsed);
489*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(original_parsed.potentially_dangling_markup);
490*6777b538SAndroid Build Coastguard Worker
491*6777b538SAndroid Build Coastguard Worker // Perform a replacement, and validate that the potentially_dangling_markup
492*6777b538SAndroid Build Coastguard Worker // flag carried over to the new Parsed object.
493*6777b538SAndroid Build Coastguard Worker Replacements<char> replacements;
494*6777b538SAndroid Build Coastguard Worker replacements.ClearRef();
495*6777b538SAndroid Build Coastguard Worker Parsed replaced_parsed;
496*6777b538SAndroid Build Coastguard Worker RawCanonOutput<32> replaced;
497*6777b538SAndroid Build Coastguard Worker ReplaceComponents(original.data(), original.length(), original_parsed,
498*6777b538SAndroid Build Coastguard Worker replacements, nullptr, &replaced, &replaced_parsed);
499*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(replaced_parsed.potentially_dangling_markup);
500*6777b538SAndroid Build Coastguard Worker }
501*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,PotentiallyDanglingMarkupAfterSchemeOnlyReplacement)502*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, PotentiallyDanglingMarkupAfterSchemeOnlyReplacement) {
503*6777b538SAndroid Build Coastguard Worker // Parse a URL with potentially dangling markup.
504*6777b538SAndroid Build Coastguard Worker Parsed original_parsed;
505*6777b538SAndroid Build Coastguard Worker RawCanonOutput<32> original;
506*6777b538SAndroid Build Coastguard Worker const char* url = "http://example.com/\n/<path";
507*6777b538SAndroid Build Coastguard Worker Canonicalize(url, strlen(url), false, nullptr, &original, &original_parsed);
508*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(original_parsed.potentially_dangling_markup);
509*6777b538SAndroid Build Coastguard Worker
510*6777b538SAndroid Build Coastguard Worker // Perform a replacement, and validate that the potentially_dangling_markup
511*6777b538SAndroid Build Coastguard Worker // flag carried over to the new Parsed object.
512*6777b538SAndroid Build Coastguard Worker Replacements<char> replacements;
513*6777b538SAndroid Build Coastguard Worker const char* new_scheme = "https";
514*6777b538SAndroid Build Coastguard Worker replacements.SetScheme(new_scheme, Component(0, strlen(new_scheme)));
515*6777b538SAndroid Build Coastguard Worker Parsed replaced_parsed;
516*6777b538SAndroid Build Coastguard Worker RawCanonOutput<32> replaced;
517*6777b538SAndroid Build Coastguard Worker ReplaceComponents(original.data(), original.length(), original_parsed,
518*6777b538SAndroid Build Coastguard Worker replacements, nullptr, &replaced, &replaced_parsed);
519*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(replaced_parsed.potentially_dangling_markup);
520*6777b538SAndroid Build Coastguard Worker }
521*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,TestDomainIs)522*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, TestDomainIs) {
523*6777b538SAndroid Build Coastguard Worker const struct {
524*6777b538SAndroid Build Coastguard Worker const char* canonicalized_host;
525*6777b538SAndroid Build Coastguard Worker const char* lower_ascii_domain;
526*6777b538SAndroid Build Coastguard Worker bool expected_domain_is;
527*6777b538SAndroid Build Coastguard Worker } kTestCases[] = {
528*6777b538SAndroid Build Coastguard Worker {"google.com", "google.com", true},
529*6777b538SAndroid Build Coastguard Worker {"www.google.com", "google.com", true}, // Subdomain is ignored.
530*6777b538SAndroid Build Coastguard Worker {"www.google.com.cn", "google.com", false}, // Different TLD.
531*6777b538SAndroid Build Coastguard Worker {"www.google.comm", "google.com", false},
532*6777b538SAndroid Build Coastguard Worker {"www.iamnotgoogle.com", "google.com", false}, // Different hostname.
533*6777b538SAndroid Build Coastguard Worker {"www.google.com", "Google.com", false}, // The input is not lower-cased.
534*6777b538SAndroid Build Coastguard Worker
535*6777b538SAndroid Build Coastguard Worker // If the host ends with a dot, it matches domains with or without a dot.
536*6777b538SAndroid Build Coastguard Worker {"www.google.com.", "google.com", true},
537*6777b538SAndroid Build Coastguard Worker {"www.google.com.", "google.com.", true},
538*6777b538SAndroid Build Coastguard Worker {"www.google.com.", ".com", true},
539*6777b538SAndroid Build Coastguard Worker {"www.google.com.", ".com.", true},
540*6777b538SAndroid Build Coastguard Worker
541*6777b538SAndroid Build Coastguard Worker // But, if the host doesn't end with a dot and the input domain does, then
542*6777b538SAndroid Build Coastguard Worker // it's considered to not match.
543*6777b538SAndroid Build Coastguard Worker {"www.google.com", "google.com.", false},
544*6777b538SAndroid Build Coastguard Worker
545*6777b538SAndroid Build Coastguard Worker // If the host ends with two dots, it doesn't match.
546*6777b538SAndroid Build Coastguard Worker {"www.google.com..", "google.com", false},
547*6777b538SAndroid Build Coastguard Worker
548*6777b538SAndroid Build Coastguard Worker // Empty parameters.
549*6777b538SAndroid Build Coastguard Worker {"www.google.com", "", false},
550*6777b538SAndroid Build Coastguard Worker {"", "www.google.com", false},
551*6777b538SAndroid Build Coastguard Worker {"", "", false},
552*6777b538SAndroid Build Coastguard Worker };
553*6777b538SAndroid Build Coastguard Worker
554*6777b538SAndroid Build Coastguard Worker for (const auto& test_case : kTestCases) {
555*6777b538SAndroid Build Coastguard Worker SCOPED_TRACE(testing::Message() << "(host, domain): ("
556*6777b538SAndroid Build Coastguard Worker << test_case.canonicalized_host << ", "
557*6777b538SAndroid Build Coastguard Worker << test_case.lower_ascii_domain << ")");
558*6777b538SAndroid Build Coastguard Worker
559*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(
560*6777b538SAndroid Build Coastguard Worker test_case.expected_domain_is,
561*6777b538SAndroid Build Coastguard Worker DomainIs(test_case.canonicalized_host, test_case.lower_ascii_domain));
562*6777b538SAndroid Build Coastguard Worker }
563*6777b538SAndroid Build Coastguard Worker }
564*6777b538SAndroid Build Coastguard Worker
565*6777b538SAndroid Build Coastguard Worker namespace {
CanonicalizeSpec(std::string_view spec,bool trim_path_end)566*6777b538SAndroid Build Coastguard Worker std::optional<std::string> CanonicalizeSpec(std::string_view spec,
567*6777b538SAndroid Build Coastguard Worker bool trim_path_end) {
568*6777b538SAndroid Build Coastguard Worker std::string canonicalized;
569*6777b538SAndroid Build Coastguard Worker StdStringCanonOutput output(&canonicalized);
570*6777b538SAndroid Build Coastguard Worker Parsed parsed;
571*6777b538SAndroid Build Coastguard Worker if (!Canonicalize(spec.data(), spec.size(), trim_path_end,
572*6777b538SAndroid Build Coastguard Worker /*charset_converter=*/nullptr, &output, &parsed)) {
573*6777b538SAndroid Build Coastguard Worker return {};
574*6777b538SAndroid Build Coastguard Worker }
575*6777b538SAndroid Build Coastguard Worker output.Complete(); // Must be called before string is used.
576*6777b538SAndroid Build Coastguard Worker return canonicalized;
577*6777b538SAndroid Build Coastguard Worker }
578*6777b538SAndroid Build Coastguard Worker } // namespace
579*6777b538SAndroid Build Coastguard Worker
580*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
581*6777b538SAndroid Build Coastguard Worker // Regression test for https://crbug.com/1252658.
TEST_F(URLUtilTest,TestCanonicalizeWindowsPathWithLeadingNUL)582*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, TestCanonicalizeWindowsPathWithLeadingNUL) {
583*6777b538SAndroid Build Coastguard Worker auto PrefixWithNUL = [](std::string&& s) -> std::string { return '\0' + s; };
584*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(CanonicalizeSpec(PrefixWithNUL("w:"), /*trim_path_end=*/false),
585*6777b538SAndroid Build Coastguard Worker std::make_optional("file:///W:"));
586*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(CanonicalizeSpec(PrefixWithNUL("\\\\server\\share"),
587*6777b538SAndroid Build Coastguard Worker /*trim_path_end=*/false),
588*6777b538SAndroid Build Coastguard Worker std::make_optional("file://server/share"));
589*6777b538SAndroid Build Coastguard Worker }
590*6777b538SAndroid Build Coastguard Worker #endif
591*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,TestCanonicalizeIdempotencyWithLeadingControlCharacters)592*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, TestCanonicalizeIdempotencyWithLeadingControlCharacters) {
593*6777b538SAndroid Build Coastguard Worker std::string spec = "_w:";
594*6777b538SAndroid Build Coastguard Worker // Loop over all C0 control characters and the space character.
595*6777b538SAndroid Build Coastguard Worker for (char c = '\0'; c <= ' '; c++) {
596*6777b538SAndroid Build Coastguard Worker SCOPED_TRACE(testing::Message() << "c: " << c);
597*6777b538SAndroid Build Coastguard Worker
598*6777b538SAndroid Build Coastguard Worker // Overwrite the first character of `spec`. Note that replacing the first
599*6777b538SAndroid Build Coastguard Worker // character with NUL will not change the length!
600*6777b538SAndroid Build Coastguard Worker spec[0] = c;
601*6777b538SAndroid Build Coastguard Worker
602*6777b538SAndroid Build Coastguard Worker for (bool trim_path_end : {false, true}) {
603*6777b538SAndroid Build Coastguard Worker SCOPED_TRACE(testing::Message() << "trim_path_end: " << trim_path_end);
604*6777b538SAndroid Build Coastguard Worker
605*6777b538SAndroid Build Coastguard Worker std::optional<std::string> canonicalized =
606*6777b538SAndroid Build Coastguard Worker CanonicalizeSpec(spec, trim_path_end);
607*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(canonicalized);
608*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(canonicalized, CanonicalizeSpec(*canonicalized, trim_path_end));
609*6777b538SAndroid Build Coastguard Worker }
610*6777b538SAndroid Build Coastguard Worker }
611*6777b538SAndroid Build Coastguard Worker }
612*6777b538SAndroid Build Coastguard Worker
TEST_F(URLUtilTest,TestHasInvalidURLEscapeSequences)613*6777b538SAndroid Build Coastguard Worker TEST_F(URLUtilTest, TestHasInvalidURLEscapeSequences) {
614*6777b538SAndroid Build Coastguard Worker struct TestCase {
615*6777b538SAndroid Build Coastguard Worker const char* input;
616*6777b538SAndroid Build Coastguard Worker bool is_invalid;
617*6777b538SAndroid Build Coastguard Worker } cases[] = {
618*6777b538SAndroid Build Coastguard Worker // Edge cases.
619*6777b538SAndroid Build Coastguard Worker {"", false},
620*6777b538SAndroid Build Coastguard Worker {"%", true},
621*6777b538SAndroid Build Coastguard Worker
622*6777b538SAndroid Build Coastguard Worker // Single regular chars with no escaping are valid.
623*6777b538SAndroid Build Coastguard Worker {"a", false},
624*6777b538SAndroid Build Coastguard Worker {"g", false},
625*6777b538SAndroid Build Coastguard Worker {"A", false},
626*6777b538SAndroid Build Coastguard Worker {"G", false},
627*6777b538SAndroid Build Coastguard Worker {":", false},
628*6777b538SAndroid Build Coastguard Worker {"]", false},
629*6777b538SAndroid Build Coastguard Worker {"\x00", false}, // ASCII 'NUL' char
630*6777b538SAndroid Build Coastguard Worker {"\x01", false}, // ASCII 'SOH' char
631*6777b538SAndroid Build Coastguard Worker {"\xC2\xA3", false}, // UTF-8 encoded '£'.
632*6777b538SAndroid Build Coastguard Worker
633*6777b538SAndroid Build Coastguard Worker // Longer strings without escaping are valid.
634*6777b538SAndroid Build Coastguard Worker {"Hello world", false},
635*6777b538SAndroid Build Coastguard Worker {"Here: [%25] <-- a percent-encoded percent character.", false},
636*6777b538SAndroid Build Coastguard Worker
637*6777b538SAndroid Build Coastguard Worker // Valid %-escaped sequences ('%' followed by two hex digits).
638*6777b538SAndroid Build Coastguard Worker {"%00", false},
639*6777b538SAndroid Build Coastguard Worker {"%20", false},
640*6777b538SAndroid Build Coastguard Worker {"%02", false},
641*6777b538SAndroid Build Coastguard Worker {"%ff", false},
642*6777b538SAndroid Build Coastguard Worker {"%FF", false},
643*6777b538SAndroid Build Coastguard Worker {"%0a", false},
644*6777b538SAndroid Build Coastguard Worker {"%0A", false},
645*6777b538SAndroid Build Coastguard Worker {"abc%FF", false},
646*6777b538SAndroid Build Coastguard Worker {"%FFabc", false},
647*6777b538SAndroid Build Coastguard Worker {"abc%FFabc", false},
648*6777b538SAndroid Build Coastguard Worker {"hello %FF world", false},
649*6777b538SAndroid Build Coastguard Worker {"%20hello%20world", false},
650*6777b538SAndroid Build Coastguard Worker {"%25", false},
651*6777b538SAndroid Build Coastguard Worker {"%25%25", false},
652*6777b538SAndroid Build Coastguard Worker {"%250", false},
653*6777b538SAndroid Build Coastguard Worker {"%259", false},
654*6777b538SAndroid Build Coastguard Worker {"%25A", false},
655*6777b538SAndroid Build Coastguard Worker {"%25F", false},
656*6777b538SAndroid Build Coastguard Worker {"%0a:", false},
657*6777b538SAndroid Build Coastguard Worker
658*6777b538SAndroid Build Coastguard Worker // '%' followed by a single character is never a valid sequence.
659*6777b538SAndroid Build Coastguard Worker {"%%", true},
660*6777b538SAndroid Build Coastguard Worker {"%2", true},
661*6777b538SAndroid Build Coastguard Worker {"%a", true},
662*6777b538SAndroid Build Coastguard Worker {"%A", true},
663*6777b538SAndroid Build Coastguard Worker {"%g", true},
664*6777b538SAndroid Build Coastguard Worker {"%G", true},
665*6777b538SAndroid Build Coastguard Worker {"%:", true},
666*6777b538SAndroid Build Coastguard Worker {"%[", true},
667*6777b538SAndroid Build Coastguard Worker {"%F", true},
668*6777b538SAndroid Build Coastguard Worker {"%\xC2\xA3", true}, //% followed by UTF-8 encoded '£'.
669*6777b538SAndroid Build Coastguard Worker
670*6777b538SAndroid Build Coastguard Worker // String ends on a potential escape sequence but without two hex-digits
671*6777b538SAndroid Build Coastguard Worker // is invalid.
672*6777b538SAndroid Build Coastguard Worker {"abc%", true},
673*6777b538SAndroid Build Coastguard Worker {"abc%%", true},
674*6777b538SAndroid Build Coastguard Worker {"abc%%%", true},
675*6777b538SAndroid Build Coastguard Worker {"abc%a", true},
676*6777b538SAndroid Build Coastguard Worker
677*6777b538SAndroid Build Coastguard Worker // One hex and one non-hex digit is invalid.
678*6777b538SAndroid Build Coastguard Worker {"%a:", true},
679*6777b538SAndroid Build Coastguard Worker {"%:a", true},
680*6777b538SAndroid Build Coastguard Worker {"%::", true},
681*6777b538SAndroid Build Coastguard Worker {"%ag", true},
682*6777b538SAndroid Build Coastguard Worker {"%ga", true},
683*6777b538SAndroid Build Coastguard Worker {"%-1", true},
684*6777b538SAndroid Build Coastguard Worker {"%1-", true},
685*6777b538SAndroid Build Coastguard Worker {"%0\xC2\xA3", true}, // %0£.
686*6777b538SAndroid Build Coastguard Worker };
687*6777b538SAndroid Build Coastguard Worker
688*6777b538SAndroid Build Coastguard Worker for (TestCase test_case : cases) {
689*6777b538SAndroid Build Coastguard Worker const char* input = test_case.input;
690*6777b538SAndroid Build Coastguard Worker bool result = HasInvalidURLEscapeSequences(input);
691*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(test_case.is_invalid, result)
692*6777b538SAndroid Build Coastguard Worker << "Invalid result for '" << input << "'";
693*6777b538SAndroid Build Coastguard Worker }
694*6777b538SAndroid Build Coastguard Worker }
695*6777b538SAndroid Build Coastguard Worker
696*6777b538SAndroid Build Coastguard Worker class URLUtilTypedTest : public ::testing::TestWithParam<bool> {
697*6777b538SAndroid Build Coastguard Worker public:
URLUtilTypedTest()698*6777b538SAndroid Build Coastguard Worker URLUtilTypedTest()
699*6777b538SAndroid Build Coastguard Worker : use_standard_compliant_non_special_scheme_url_parsing_(GetParam()) {
700*6777b538SAndroid Build Coastguard Worker if (use_standard_compliant_non_special_scheme_url_parsing_) {
701*6777b538SAndroid Build Coastguard Worker scoped_feature_list_.InitAndEnableFeature(
702*6777b538SAndroid Build Coastguard Worker kStandardCompliantNonSpecialSchemeURLParsing);
703*6777b538SAndroid Build Coastguard Worker } else {
704*6777b538SAndroid Build Coastguard Worker scoped_feature_list_.InitAndDisableFeature(
705*6777b538SAndroid Build Coastguard Worker kStandardCompliantNonSpecialSchemeURLParsing);
706*6777b538SAndroid Build Coastguard Worker }
707*6777b538SAndroid Build Coastguard Worker }
708*6777b538SAndroid Build Coastguard Worker
709*6777b538SAndroid Build Coastguard Worker protected:
710*6777b538SAndroid Build Coastguard Worker struct URLCase {
711*6777b538SAndroid Build Coastguard Worker const std::string_view input;
712*6777b538SAndroid Build Coastguard Worker const std::string_view expected;
713*6777b538SAndroid Build Coastguard Worker bool expected_success;
714*6777b538SAndroid Build Coastguard Worker };
715*6777b538SAndroid Build Coastguard Worker
716*6777b538SAndroid Build Coastguard Worker struct ResolveRelativeCase {
717*6777b538SAndroid Build Coastguard Worker const std::string_view base;
718*6777b538SAndroid Build Coastguard Worker const std::string_view rel;
719*6777b538SAndroid Build Coastguard Worker std::optional<std::string_view> expected;
720*6777b538SAndroid Build Coastguard Worker };
721*6777b538SAndroid Build Coastguard Worker
TestCanonicalize(const URLCase & url_case)722*6777b538SAndroid Build Coastguard Worker void TestCanonicalize(const URLCase& url_case) {
723*6777b538SAndroid Build Coastguard Worker std::string canonicalized;
724*6777b538SAndroid Build Coastguard Worker StdStringCanonOutput output(&canonicalized);
725*6777b538SAndroid Build Coastguard Worker Parsed parsed;
726*6777b538SAndroid Build Coastguard Worker bool success =
727*6777b538SAndroid Build Coastguard Worker Canonicalize(url_case.input.data(), url_case.input.size(),
728*6777b538SAndroid Build Coastguard Worker /*trim_path_end=*/false,
729*6777b538SAndroid Build Coastguard Worker /*charset_converter=*/nullptr, &output, &parsed);
730*6777b538SAndroid Build Coastguard Worker output.Complete();
731*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(success, url_case.expected_success);
732*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(output.view(), url_case.expected);
733*6777b538SAndroid Build Coastguard Worker }
734*6777b538SAndroid Build Coastguard Worker
TestResolveRelative(const ResolveRelativeCase & test)735*6777b538SAndroid Build Coastguard Worker void TestResolveRelative(const ResolveRelativeCase& test) {
736*6777b538SAndroid Build Coastguard Worker SCOPED_TRACE(testing::Message()
737*6777b538SAndroid Build Coastguard Worker << "base: " << test.base << ", rel: " << test.rel);
738*6777b538SAndroid Build Coastguard Worker
739*6777b538SAndroid Build Coastguard Worker Parsed base_parsed;
740*6777b538SAndroid Build Coastguard Worker if (url::IsUsingStandardCompliantNonSpecialSchemeURLParsing()) {
741*6777b538SAndroid Build Coastguard Worker ParseNonSpecialURL(test.base.data(), test.base.size(), &base_parsed);
742*6777b538SAndroid Build Coastguard Worker } else {
743*6777b538SAndroid Build Coastguard Worker ParsePathURL(test.base.data(), test.base.size(), /*trim_path_end=*/true,
744*6777b538SAndroid Build Coastguard Worker &base_parsed);
745*6777b538SAndroid Build Coastguard Worker }
746*6777b538SAndroid Build Coastguard Worker
747*6777b538SAndroid Build Coastguard Worker std::string resolved;
748*6777b538SAndroid Build Coastguard Worker StdStringCanonOutput output(&resolved);
749*6777b538SAndroid Build Coastguard Worker
750*6777b538SAndroid Build Coastguard Worker Parsed resolved_parsed;
751*6777b538SAndroid Build Coastguard Worker bool valid = ResolveRelative(test.base.data(), test.base.size(),
752*6777b538SAndroid Build Coastguard Worker base_parsed, test.rel.data(), test.rel.size(),
753*6777b538SAndroid Build Coastguard Worker nullptr, &output, &resolved_parsed);
754*6777b538SAndroid Build Coastguard Worker output.Complete();
755*6777b538SAndroid Build Coastguard Worker
756*6777b538SAndroid Build Coastguard Worker if (valid) {
757*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(test.expected);
758*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(resolved, *test.expected);
759*6777b538SAndroid Build Coastguard Worker } else {
760*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(test.expected);
761*6777b538SAndroid Build Coastguard Worker }
762*6777b538SAndroid Build Coastguard Worker }
763*6777b538SAndroid Build Coastguard Worker
764*6777b538SAndroid Build Coastguard Worker bool use_standard_compliant_non_special_scheme_url_parsing_;
765*6777b538SAndroid Build Coastguard Worker
766*6777b538SAndroid Build Coastguard Worker private:
767*6777b538SAndroid Build Coastguard Worker base::test::ScopedFeatureList scoped_feature_list_;
768*6777b538SAndroid Build Coastguard Worker };
769*6777b538SAndroid Build Coastguard Worker
TEST_P(URLUtilTypedTest,TestNoRefComponent)770*6777b538SAndroid Build Coastguard Worker TEST_P(URLUtilTypedTest, TestNoRefComponent) {
771*6777b538SAndroid Build Coastguard Worker // This test was originally written before full support for non-special URLs
772*6777b538SAndroid Build Coastguard Worker // became available. We need a flag-dependent test here because the test uses
773*6777b538SAndroid Build Coastguard Worker // an internal parse function. See http://crbug.com/40063064 for details.
774*6777b538SAndroid Build Coastguard Worker //
775*6777b538SAndroid Build Coastguard Worker // The test case corresponds to the following user scenario:
776*6777b538SAndroid Build Coastguard Worker //
777*6777b538SAndroid Build Coastguard Worker // > const url = new URL("any#body", "mailto://to/");
778*6777b538SAndroid Build Coastguard Worker // > assertEquals(url.href, "mailto://to/any#body");
779*6777b538SAndroid Build Coastguard Worker //
780*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/40063064): Remove this test once the flag is enabled.
781*6777b538SAndroid Build Coastguard Worker const std::string_view base = "mailto://to/";
782*6777b538SAndroid Build Coastguard Worker const std::string_view rel = "any#body";
783*6777b538SAndroid Build Coastguard Worker if (use_standard_compliant_non_special_scheme_url_parsing_) {
784*6777b538SAndroid Build Coastguard Worker // We probably don't need to test with the flag enabled, however, including
785*6777b538SAndroid Build Coastguard Worker // a test with the flag enabled would be beneficial for comparison purposes,
786*6777b538SAndroid Build Coastguard Worker // at least until we enable the flag by default.
787*6777b538SAndroid Build Coastguard Worker Parsed base_parsed;
788*6777b538SAndroid Build Coastguard Worker ParseNonSpecialURL(base.data(), base.size(), &base_parsed);
789*6777b538SAndroid Build Coastguard Worker
790*6777b538SAndroid Build Coastguard Worker std::string resolved;
791*6777b538SAndroid Build Coastguard Worker StdStringCanonOutput output(&resolved);
792*6777b538SAndroid Build Coastguard Worker Parsed resolved_parsed;
793*6777b538SAndroid Build Coastguard Worker
794*6777b538SAndroid Build Coastguard Worker bool valid =
795*6777b538SAndroid Build Coastguard Worker ResolveRelative(base.data(), base.size(), base_parsed, rel.data(),
796*6777b538SAndroid Build Coastguard Worker rel.size(), nullptr, &output, &resolved_parsed);
797*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(valid);
798*6777b538SAndroid Build Coastguard Worker // Note: If the flag is enabled and the correct parsing function is used,
799*6777b538SAndroid Build Coastguard Worker // resolved_parsed.ref becomes valid correctly.
800*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(resolved_parsed.ref.is_valid());
801*6777b538SAndroid Build Coastguard Worker output.Complete();
802*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(resolved, "mailto://to/any#body");
803*6777b538SAndroid Build Coastguard Worker } else {
804*6777b538SAndroid Build Coastguard Worker // Note: See the description of https://codereview.chromium.org/767713002/
805*6777b538SAndroid Build Coastguard Worker // for the intention of this test, which added this test to record a wrong
806*6777b538SAndroid Build Coastguard Worker // result if a wrong parser function is used. I kept the following original
807*6777b538SAndroid Build Coastguard Worker // comment as is:
808*6777b538SAndroid Build Coastguard Worker //
809*6777b538SAndroid Build Coastguard Worker // The hash-mark must be ignored when mailto: scheme is parsed,
810*6777b538SAndroid Build Coastguard Worker // even if the URL has a base and relative part.
811*6777b538SAndroid Build Coastguard Worker Parsed base_parsed;
812*6777b538SAndroid Build Coastguard Worker ParsePathURL(base.data(), base.size(), false, &base_parsed);
813*6777b538SAndroid Build Coastguard Worker
814*6777b538SAndroid Build Coastguard Worker std::string resolved;
815*6777b538SAndroid Build Coastguard Worker StdStringCanonOutput output(&resolved);
816*6777b538SAndroid Build Coastguard Worker Parsed resolved_parsed;
817*6777b538SAndroid Build Coastguard Worker
818*6777b538SAndroid Build Coastguard Worker bool valid =
819*6777b538SAndroid Build Coastguard Worker ResolveRelative(base.data(), base.size(), base_parsed, rel.data(),
820*6777b538SAndroid Build Coastguard Worker rel.size(), nullptr, &output, &resolved_parsed);
821*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(valid);
822*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(resolved_parsed.ref.is_valid());
823*6777b538SAndroid Build Coastguard Worker }
824*6777b538SAndroid Build Coastguard Worker }
825*6777b538SAndroid Build Coastguard Worker
TEST_P(URLUtilTypedTest,Cannolicalize)826*6777b538SAndroid Build Coastguard Worker TEST_P(URLUtilTypedTest, Cannolicalize) {
827*6777b538SAndroid Build Coastguard Worker // Verify that the feature flag changes canonicalization behavior,
828*6777b538SAndroid Build Coastguard Worker // focusing on key cases here as comprehesive testing is covered in other unit
829*6777b538SAndroid Build Coastguard Worker // tests.
830*6777b538SAndroid Build Coastguard Worker if (use_standard_compliant_non_special_scheme_url_parsing_) {
831*6777b538SAndroid Build Coastguard Worker URLCase cases[] = {
832*6777b538SAndroid Build Coastguard Worker {"git://host/..", "git://host/", true},
833*6777b538SAndroid Build Coastguard Worker {"git:// /", "git:///", false},
834*6777b538SAndroid Build Coastguard Worker {"git:/..", "git:/", true},
835*6777b538SAndroid Build Coastguard Worker {"mailto:/..", "mailto:/", true},
836*6777b538SAndroid Build Coastguard Worker };
837*6777b538SAndroid Build Coastguard Worker for (const auto& i : cases) {
838*6777b538SAndroid Build Coastguard Worker TestCanonicalize(i);
839*6777b538SAndroid Build Coastguard Worker }
840*6777b538SAndroid Build Coastguard Worker } else {
841*6777b538SAndroid Build Coastguard Worker // Every non-special URL is considered as an opaque path if the feature is
842*6777b538SAndroid Build Coastguard Worker // disabled.
843*6777b538SAndroid Build Coastguard Worker URLCase cases[] = {
844*6777b538SAndroid Build Coastguard Worker {"git://host/..", "git://host/..", true},
845*6777b538SAndroid Build Coastguard Worker {"git:// /", "git:// /", true},
846*6777b538SAndroid Build Coastguard Worker {"git:/..", "git:/..", true},
847*6777b538SAndroid Build Coastguard Worker {"mailto:/..", "mailto:/..", true},
848*6777b538SAndroid Build Coastguard Worker };
849*6777b538SAndroid Build Coastguard Worker for (const auto& i : cases) {
850*6777b538SAndroid Build Coastguard Worker TestCanonicalize(i);
851*6777b538SAndroid Build Coastguard Worker }
852*6777b538SAndroid Build Coastguard Worker }
853*6777b538SAndroid Build Coastguard Worker }
854*6777b538SAndroid Build Coastguard Worker
TEST_P(URLUtilTypedTest,TestResolveRelativeWithNonSpecialBase)855*6777b538SAndroid Build Coastguard Worker TEST_P(URLUtilTypedTest, TestResolveRelativeWithNonSpecialBase) {
856*6777b538SAndroid Build Coastguard Worker // Test flag-dependent behaviors. Existing tests in
857*6777b538SAndroid Build Coastguard Worker // URLUtilTest::TestResolveRelativeWithNonStandardBase cover common cases.
858*6777b538SAndroid Build Coastguard Worker //
859*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1416006): Test common cases in this typed test too.
860*6777b538SAndroid Build Coastguard Worker if (use_standard_compliant_non_special_scheme_url_parsing_) {
861*6777b538SAndroid Build Coastguard Worker ResolveRelativeCase cases[] = {
862*6777b538SAndroid Build Coastguard Worker {"scheme://Authority", "path", "scheme://Authority/path"},
863*6777b538SAndroid Build Coastguard Worker };
864*6777b538SAndroid Build Coastguard Worker for (const auto& i : cases) {
865*6777b538SAndroid Build Coastguard Worker TestResolveRelative(i);
866*6777b538SAndroid Build Coastguard Worker }
867*6777b538SAndroid Build Coastguard Worker } else {
868*6777b538SAndroid Build Coastguard Worker ResolveRelativeCase cases[] = {
869*6777b538SAndroid Build Coastguard Worker // It's still possible to get an invalid path URL.
870*6777b538SAndroid Build Coastguard Worker //
871*6777b538SAndroid Build Coastguard Worker // Note: If the flag is enabled, "custom://Invalid:!#Auth/" is an
872*6777b538SAndroid Build Coastguard Worker // invalid URL.
873*6777b538SAndroid Build Coastguard Worker // ResolveRelative() should be never called.
874*6777b538SAndroid Build Coastguard Worker {"custom://Invalid:!#Auth/", "file.html", std::nullopt},
875*6777b538SAndroid Build Coastguard Worker
876*6777b538SAndroid Build Coastguard Worker // Resolving should fail if the base URL is authority-based but is
877*6777b538SAndroid Build Coastguard Worker // missing a path component (the '/' at the end).
878*6777b538SAndroid Build Coastguard Worker {"scheme://Authority", "path", std::nullopt},
879*6777b538SAndroid Build Coastguard Worker
880*6777b538SAndroid Build Coastguard Worker // In this case, the backslashes will not be canonicalized because it's
881*6777b538SAndroid Build Coastguard Worker // a non-standard URL, but they will be treated as a path separators,
882*6777b538SAndroid Build Coastguard Worker // giving the base URL here a path of "\".
883*6777b538SAndroid Build Coastguard Worker //
884*6777b538SAndroid Build Coastguard Worker // The result here is somewhat arbitrary. One could argue it should be
885*6777b538SAndroid Build Coastguard Worker // either "aaa://a\" or "aaa://a/" since the path is being replaced with
886*6777b538SAndroid Build Coastguard Worker // the "current directory". But in the context of resolving on data
887*6777b538SAndroid Build Coastguard Worker // URLs, adding the requested dot doesn't seem wrong either.
888*6777b538SAndroid Build Coastguard Worker //
889*6777b538SAndroid Build Coastguard Worker // Note: If the flag is enabled, "aaa://a\\" is an invalid URL.
890*6777b538SAndroid Build Coastguard Worker // ResolveRelative() should be never called.
891*6777b538SAndroid Build Coastguard Worker {"aaa://a\\", "aaa:.", "aaa://a\\."}};
892*6777b538SAndroid Build Coastguard Worker for (const auto& i : cases) {
893*6777b538SAndroid Build Coastguard Worker TestResolveRelative(i);
894*6777b538SAndroid Build Coastguard Worker }
895*6777b538SAndroid Build Coastguard Worker }
896*6777b538SAndroid Build Coastguard Worker }
897*6777b538SAndroid Build Coastguard Worker
898*6777b538SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(All, URLUtilTypedTest, ::testing::Bool());
899*6777b538SAndroid Build Coastguard Worker
900*6777b538SAndroid Build Coastguard Worker } // namespace url
901