1 #include "gtest/gtest.h"
2 #include "gtest/MozGTestBench.h" // For MOZ_GTEST_BENCH
3
4 #include <regex>
5 #include "json/json.h"
6 #include "json/reader.h"
7 #include "mozilla/TextUtils.h"
8 #include "mozilla/net/MozURL.h"
9 #include "nsCOMPtr.h"
10 #include "nsDirectoryServiceDefs.h"
11 #include "nsNetUtil.h"
12 #include "nsIFile.h"
13 #include "nsIURI.h"
14 #include "nsStreamUtils.h"
15
16 using namespace mozilla;
17 using namespace mozilla::net;
18
TEST(TestMozURL,Getters)19 TEST(TestMozURL, Getters)
20 {
21 nsAutoCString href("http://user:pass@example.com/path?query#ref");
22 RefPtr<MozURL> url;
23 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
24
25 ASSERT_TRUE(url->Scheme().EqualsLiteral("http"));
26
27 ASSERT_TRUE(url->Spec() == href);
28
29 ASSERT_TRUE(url->Username().EqualsLiteral("user"));
30
31 ASSERT_TRUE(url->Password().EqualsLiteral("pass"));
32
33 ASSERT_TRUE(url->Host().EqualsLiteral("example.com"));
34
35 ASSERT_TRUE(url->FilePath().EqualsLiteral("/path"));
36
37 ASSERT_TRUE(url->Query().EqualsLiteral("query"));
38
39 ASSERT_TRUE(url->Ref().EqualsLiteral("ref"));
40
41 url = nullptr;
42 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), ""_ns), NS_ERROR_MALFORMED_URI);
43 ASSERT_EQ(url, nullptr);
44 }
45
TEST(TestMozURL,MutatorChain)46 TEST(TestMozURL, MutatorChain)
47 {
48 nsAutoCString href("http://user:pass@example.com/path?query#ref");
49 RefPtr<MozURL> url;
50 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
51 nsAutoCString out;
52
53 RefPtr<MozURL> url2;
54 ASSERT_EQ(url->Mutate()
55 .SetScheme("https"_ns)
56 .SetUsername("newuser"_ns)
57 .SetPassword("newpass"_ns)
58 .SetHostname("test"_ns)
59 .SetFilePath("new/file/path"_ns)
60 .SetQuery("bla"_ns)
61 .SetRef("huh"_ns)
62 .Finalize(getter_AddRefs(url2)),
63 NS_OK);
64
65 ASSERT_TRUE(url2->Spec().EqualsLiteral(
66 "https://newuser:newpass@test/new/file/path?bla#huh"));
67 }
68
TEST(TestMozURL,MutatorFinalizeTwice)69 TEST(TestMozURL, MutatorFinalizeTwice)
70 {
71 nsAutoCString href("http://user:pass@example.com/path?query#ref");
72 RefPtr<MozURL> url;
73 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
74 nsAutoCString out;
75
76 RefPtr<MozURL> url2;
77 MozURL::Mutator mut = url->Mutate();
78 mut.SetScheme("https"_ns); // Change the scheme to https
79 ASSERT_EQ(mut.Finalize(getter_AddRefs(url2)), NS_OK);
80 ASSERT_TRUE(url2->Spec().EqualsLiteral(
81 "https://user:pass@example.com/path?query#ref"));
82
83 // Test that a second call to Finalize will result in an error code
84 url2 = nullptr;
85 ASSERT_EQ(mut.Finalize(getter_AddRefs(url2)), NS_ERROR_NOT_AVAILABLE);
86 ASSERT_EQ(url2, nullptr);
87 }
88
TEST(TestMozURL,MutatorErrorStatus)89 TEST(TestMozURL, MutatorErrorStatus)
90 {
91 nsAutoCString href("http://user:pass@example.com/path?query#ref");
92 RefPtr<MozURL> url;
93 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
94 nsAutoCString out;
95
96 // Test that trying to set the scheme to a bad value will get you an error
97 MozURL::Mutator mut = url->Mutate();
98 mut.SetScheme("!@#$%^&*("_ns);
99 ASSERT_EQ(mut.GetStatus(), NS_ERROR_MALFORMED_URI);
100
101 // Test that the mutator will not work after one faulty operation
102 mut.SetScheme("test"_ns);
103 ASSERT_EQ(mut.GetStatus(), NS_ERROR_MALFORMED_URI);
104 }
105
TEST(TestMozURL,InitWithBase)106 TEST(TestMozURL, InitWithBase)
107 {
108 nsAutoCString href("https://example.net/a/b.html");
109 RefPtr<MozURL> url;
110 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
111
112 ASSERT_TRUE(url->Spec().EqualsLiteral("https://example.net/a/b.html"));
113
114 RefPtr<MozURL> url2;
115 ASSERT_EQ(MozURL::Init(getter_AddRefs(url2), "c.png"_ns, url), NS_OK);
116
117 ASSERT_TRUE(url2->Spec().EqualsLiteral("https://example.net/a/c.png"));
118 }
119
TEST(TestMozURL,Path)120 TEST(TestMozURL, Path)
121 {
122 nsAutoCString href("about:blank");
123 RefPtr<MozURL> url;
124 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
125
126 ASSERT_TRUE(url->Spec().EqualsLiteral("about:blank"));
127
128 ASSERT_TRUE(url->Scheme().EqualsLiteral("about"));
129
130 ASSERT_TRUE(url->FilePath().EqualsLiteral("blank"));
131 }
132
TEST(TestMozURL,HostPort)133 TEST(TestMozURL, HostPort)
134 {
135 nsAutoCString href("https://user:pass@example.net:1234/path?query#ref");
136 RefPtr<MozURL> url;
137 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
138
139 ASSERT_TRUE(url->HostPort().EqualsLiteral("example.net:1234"));
140
141 RefPtr<MozURL> url2;
142 url->Mutate().SetHostPort("test:321"_ns).Finalize(getter_AddRefs(url2));
143
144 ASSERT_TRUE(url2->HostPort().EqualsLiteral("test:321"));
145 ASSERT_TRUE(
146 url2->Spec().EqualsLiteral("https://user:pass@test:321/path?query#ref"));
147
148 href.Assign("https://user:pass@example.net:443/path?query#ref");
149 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
150 ASSERT_TRUE(url->HostPort().EqualsLiteral("example.net"));
151 ASSERT_EQ(url->Port(), -1);
152 }
153
TEST(TestMozURL,Origin)154 TEST(TestMozURL, Origin)
155 {
156 nsAutoCString href("https://user:pass@example.net:1234/path?query#ref");
157 RefPtr<MozURL> url;
158 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
159
160 nsAutoCString out;
161 url->Origin(out);
162 ASSERT_TRUE(out.EqualsLiteral("https://example.net:1234"));
163
164 RefPtr<MozURL> url2;
165 ASSERT_EQ(MozURL::Init(getter_AddRefs(url2), "file:///tmp/foo"_ns), NS_OK);
166 url2->Origin(out);
167 ASSERT_TRUE(out.EqualsLiteral("file:///tmp/foo"));
168
169 RefPtr<MozURL> url3;
170 ASSERT_EQ(
171 MozURL::Init(getter_AddRefs(url3),
172 nsLiteralCString(
173 "moz-extension://53711a8f-65ed-e742-9671-1f02e267c0bc/"
174 "foo/bar.html")),
175 NS_OK);
176 url3->Origin(out);
177 ASSERT_TRUE(out.EqualsLiteral(
178 "moz-extension://53711a8f-65ed-e742-9671-1f02e267c0bc"));
179
180 RefPtr<MozURL> url4;
181 ASSERT_EQ(MozURL::Init(getter_AddRefs(url4), "resource://foo/bar.html"_ns),
182 NS_OK);
183 url4->Origin(out);
184 ASSERT_TRUE(out.EqualsLiteral("resource://foo"));
185
186 RefPtr<MozURL> url5;
187 ASSERT_EQ(MozURL::Init(getter_AddRefs(url5), "about:home"_ns), NS_OK);
188 url5->Origin(out);
189 ASSERT_TRUE(out.EqualsLiteral("about:home"));
190 }
191
TEST(TestMozURL,BaseDomain)192 TEST(TestMozURL, BaseDomain)
193 {
194 nsAutoCString href("https://user:pass@example.net:1234/path?query#ref");
195 RefPtr<MozURL> url;
196 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), href), NS_OK);
197
198 nsAutoCString out;
199 ASSERT_EQ(url->BaseDomain(out), NS_OK);
200 ASSERT_TRUE(out.EqualsLiteral("example.net"));
201
202 RefPtr<MozURL> url2;
203 ASSERT_EQ(MozURL::Init(getter_AddRefs(url2), "file:///tmp/foo"_ns), NS_OK);
204 ASSERT_EQ(url2->BaseDomain(out), NS_OK);
205 ASSERT_TRUE(out.EqualsLiteral("/tmp/foo"));
206
207 RefPtr<MozURL> url3;
208 ASSERT_EQ(
209 MozURL::Init(getter_AddRefs(url3),
210 nsLiteralCString(
211 "moz-extension://53711a8f-65ed-e742-9671-1f02e267c0bc/"
212 "foo/bar.html")),
213 NS_OK);
214 ASSERT_EQ(url3->BaseDomain(out), NS_OK);
215 ASSERT_TRUE(out.EqualsLiteral("53711a8f-65ed-e742-9671-1f02e267c0bc"));
216
217 RefPtr<MozURL> url4;
218 ASSERT_EQ(MozURL::Init(getter_AddRefs(url4), "resource://foo/bar.html"_ns),
219 NS_OK);
220 ASSERT_EQ(url4->BaseDomain(out), NS_OK);
221 ASSERT_TRUE(out.EqualsLiteral("foo"));
222
223 RefPtr<MozURL> url5;
224 ASSERT_EQ(MozURL::Init(getter_AddRefs(url5), "about:home"_ns), NS_OK);
225 ASSERT_EQ(url5->BaseDomain(out), NS_OK);
226 ASSERT_TRUE(out.EqualsLiteral("about:home"));
227 }
228
229 namespace {
230
OriginMatchesExpectedOrigin(const nsACString & aOrigin,const nsACString & aExpectedOrigin)231 bool OriginMatchesExpectedOrigin(const nsACString& aOrigin,
232 const nsACString& aExpectedOrigin) {
233 if (aExpectedOrigin.Equals("null") &&
234 StringBeginsWith(aOrigin, "moz-nullprincipal"_ns)) {
235 return true;
236 }
237 return aOrigin == aExpectedOrigin;
238 }
239
IsUUID(const nsACString & aString)240 bool IsUUID(const nsACString& aString) {
241 if (!IsAscii(aString)) {
242 return false;
243 }
244
245 std::regex pattern(
246 "^\\{[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab"
247 "][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\\}$");
248 return regex_match(nsCString(aString).get(), pattern);
249 }
250
BaseDomainsEqual(const nsACString & aBaseDomain1,const nsACString & aBaseDomain2)251 bool BaseDomainsEqual(const nsACString& aBaseDomain1,
252 const nsACString& aBaseDomain2) {
253 if (IsUUID(aBaseDomain1) && IsUUID(aBaseDomain2)) {
254 return true;
255 }
256 return aBaseDomain1 == aBaseDomain2;
257 }
258
CheckOrigin(const nsACString & aSpec,const nsACString & aBase,const nsACString & aOrigin)259 void CheckOrigin(const nsACString& aSpec, const nsACString& aBase,
260 const nsACString& aOrigin) {
261 nsCOMPtr<nsIURI> baseUri;
262 nsresult rv = NS_NewURI(getter_AddRefs(baseUri), aBase);
263 ASSERT_EQ(rv, NS_OK);
264
265 nsCOMPtr<nsIURI> uri;
266 rv = NS_NewURI(getter_AddRefs(uri), aSpec, nullptr, baseUri);
267 ASSERT_EQ(rv, NS_OK);
268
269 OriginAttributes attrs;
270
271 nsCOMPtr<nsIPrincipal> principal =
272 BasePrincipal::CreateContentPrincipal(uri, attrs);
273 ASSERT_TRUE(principal);
274
275 nsCString origin;
276 rv = principal->GetOriginNoSuffix(origin);
277 ASSERT_EQ(rv, NS_OK);
278
279 EXPECT_TRUE(OriginMatchesExpectedOrigin(origin, aOrigin));
280
281 nsCString baseDomain;
282 rv = principal->GetBaseDomain(baseDomain);
283
284 bool baseDomainSucceeded = NS_SUCCEEDED(rv);
285
286 RefPtr<MozURL> baseUrl;
287 ASSERT_EQ(MozURL::Init(getter_AddRefs(baseUrl), aBase), NS_OK);
288
289 RefPtr<MozURL> url;
290 ASSERT_EQ(MozURL::Init(getter_AddRefs(url), aSpec, baseUrl), NS_OK);
291
292 url->Origin(origin);
293
294 EXPECT_TRUE(OriginMatchesExpectedOrigin(origin, aOrigin));
295
296 nsCString baseDomain2;
297 rv = url->BaseDomain(baseDomain2);
298
299 bool baseDomain2Succeeded = NS_SUCCEEDED(rv);
300
301 EXPECT_TRUE(baseDomainSucceeded == baseDomain2Succeeded);
302
303 if (baseDomainSucceeded) {
304 EXPECT_TRUE(BaseDomainsEqual(baseDomain, baseDomain2));
305 }
306 }
307
308 } // namespace
309
TEST(TestMozURL,UrlTestData)310 TEST(TestMozURL, UrlTestData)
311 {
312 nsCOMPtr<nsIFile> file;
313 nsresult rv =
314 NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(file));
315 ASSERT_EQ(rv, NS_OK);
316
317 rv = file->Append(u"urltestdata.json"_ns);
318 ASSERT_EQ(rv, NS_OK);
319
320 bool exists;
321 rv = file->Exists(&exists);
322 ASSERT_EQ(rv, NS_OK);
323
324 ASSERT_TRUE(exists);
325
326 nsCOMPtr<nsIInputStream> stream;
327 rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file);
328 ASSERT_EQ(rv, NS_OK);
329
330 nsCOMPtr<nsIInputStream> bufferedStream;
331 rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
332 stream.forget(), 4096);
333 ASSERT_EQ(rv, NS_OK);
334
335 nsCString data;
336 rv = NS_ConsumeStream(bufferedStream, UINT32_MAX, data);
337 ASSERT_EQ(rv, NS_OK);
338
339 Json::Value root;
340 Json::CharReaderBuilder builder;
341 std::unique_ptr<Json::CharReader> const reader(builder.newCharReader());
342 ASSERT_TRUE(
343 reader->parse(data.BeginReading(), data.EndReading(), &root, nullptr));
344 ASSERT_TRUE(root.isArray());
345
346 for (auto& item : root) {
347 if (!item.isObject()) {
348 continue;
349 }
350
351 const Json::Value& skip = item["skip"];
352 ASSERT_TRUE(skip.isNull() || skip.isBool());
353 if (skip.isBool() && skip.asBool()) {
354 continue;
355 }
356
357 const Json::Value& failure = item["failure"];
358 ASSERT_TRUE(failure.isNull() || failure.isBool());
359 if (failure.isBool() && failure.asBool()) {
360 continue;
361 }
362
363 const Json::Value& origin = item["origin"];
364 ASSERT_TRUE(origin.isNull() || origin.isString());
365 if (origin.isNull()) {
366 continue;
367 }
368 const char* originBegin;
369 const char* originEnd;
370 origin.getString(&originBegin, &originEnd);
371
372 const Json::Value& base = item["base"];
373 ASSERT_TRUE(base.isString());
374 const char* baseBegin;
375 const char* baseEnd;
376 base.getString(&baseBegin, &baseEnd);
377
378 const Json::Value& input = item["input"];
379 ASSERT_TRUE(input.isString());
380 const char* inputBegin;
381 const char* inputEnd;
382 input.getString(&inputBegin, &inputEnd);
383
384 CheckOrigin(nsDependentCString(inputBegin, inputEnd),
385 nsDependentCString(baseBegin, baseEnd),
386 nsDependentCString(originBegin, originEnd));
387 }
388 }
389