1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "gtest/gtest-param-test.h"
8 #include "gtest/gtest.h"
10 #include "mozilla/gtest/MozAssertions.h"
11 #include "nsNetUtil.h"
13 using namespace mozilla::net
;
15 LinkHeader
LinkHeaderSetAll(nsAString
const& v
) {
27 l
.mReferrerPolicy
= v
;
33 LinkHeader
LinkHeaderSetTitle(nsAString
const& v
) {
41 LinkHeader
LinkHeaderSetMinimum(nsAString
const& v
) {
48 void PrintTo(const nsTArray
<LinkHeader
>& aLinkHeaders
, std::ostream
* aOs
) {
50 for (const auto& header
: aLinkHeaders
) {
56 *aOs
<< "(mHref=" << header
.mHref
<< ", "
57 << "mRel=" << header
.mRel
<< ", "
58 << "mTitle=" << header
.mTitle
<< ", "
59 << "mNonce=" << header
.mNonce
<< ", "
60 << "mIntegrity=" << header
.mIntegrity
<< ", "
61 << "mSrcset=" << header
.mSrcset
<< ", "
62 << "mSizes=" << header
.mSizes
<< ", "
63 << "mType=" << header
.mType
<< ", "
64 << "mMedia=" << header
.mMedia
<< ", "
65 << "mAnchor=" << header
.mAnchor
<< ", "
66 << "mCrossOrigin=" << header
.mCrossOrigin
<< ", "
67 << "mReferrerPolicy=" << header
.mReferrerPolicy
<< ", "
68 << "mAs=" << header
.mAs
<< ", "
69 << "mFetchPriority=" << header
.mFetchPriority
<< ")";
73 TEST(TestLinkHeader
, MultipleLinkHeaders
)
76 u
"<a>; rel=a; title=a; integrity=a; imagesrcset=a; imagesizes=a; type=a; media=a; anchor=a; crossorigin=a; referrerpolicy=a; as=a; fetchpriority=a,"_ns
77 u
"<b>; rel=b; title=b; integrity=b; imagesrcset=b; imagesizes=b; type=b; media=b; anchor=b; crossorigin=b; referrerpolicy=b; as=b; fetchpriority=b,"_ns
80 nsTArray
<LinkHeader
> linkHeaders
= ParseLinkHeader(link
);
82 nsTArray
<LinkHeader
> expected
;
83 expected
.AppendElement(LinkHeaderSetAll(u
"a"_ns
));
84 expected
.AppendElement(LinkHeaderSetAll(u
"b"_ns
));
85 expected
.AppendElement(LinkHeaderSetMinimum(u
"c"_ns
));
87 ASSERT_EQ(linkHeaders
, expected
);
90 // title* has to be tested separately
91 TEST(TestLinkHeader
, MultipleLinkHeadersTitleStar
)
94 u
"<d>; rel=d; title*=UTF-8'de'd,"_ns
95 u
"<e>; rel=e; title*=UTF-8'de'e; title=g,"_ns
98 nsTArray
<LinkHeader
> linkHeaders
= ParseLinkHeader(link
);
100 nsTArray
<LinkHeader
> expected
;
101 expected
.AppendElement(LinkHeaderSetTitle(u
"d"_ns
));
102 expected
.AppendElement(LinkHeaderSetTitle(u
"e"_ns
));
103 expected
.AppendElement(LinkHeaderSetMinimum(u
"f"_ns
));
105 ASSERT_EQ(linkHeaders
, expected
);
108 struct SimpleParseTestData
{
114 nsString fetchpriority
;
116 friend void PrintTo(const SimpleParseTestData
& aData
, std::ostream
* aOs
) {
117 *aOs
<< "link=" << aData
.link
<< ", valid=" << aData
.valid
118 << ", url=" << aData
.url
<< ", rel=" << aData
.rel
119 << ", as=" << aData
.as
<< ", fetchpriority=" << aData
.fetchpriority
124 class SimpleParseTest
: public ::testing::TestWithParam
<SimpleParseTestData
> {};
126 TEST_P(SimpleParseTest
, Simple
) {
127 const SimpleParseTestData test
= GetParam();
129 nsTArray
<LinkHeader
> linkHeaders
= ParseLinkHeader(test
.link
);
131 EXPECT_EQ(test
.valid
, !linkHeaders
.IsEmpty());
133 ASSERT_EQ(linkHeaders
.Length(), (nsTArray
<LinkHeader
>::size_type
)1);
134 EXPECT_EQ(test
.url
, linkHeaders
[0].mHref
);
135 EXPECT_EQ(test
.rel
, linkHeaders
[0].mRel
);
136 EXPECT_EQ(test
.as
, linkHeaders
[0].mAs
);
137 EXPECT_EQ(test
.fetchpriority
, linkHeaders
[0].mFetchPriority
);
141 // Some test data copied and adapted from
142 // https://source.chromium.org/chromium/chromium/src/+/main:components/link_header_util/link_header_util_unittest.cc
143 // the different behavior of the parser is commented above each test case.
144 MOZ_RUNINIT
const SimpleParseTestData simple_parse_tests
[] = {
145 {u
"<s.css>; rel=stylesheet; fetchpriority=\"auto\""_ns
, true, u
"s.css"_ns
,
146 u
"stylesheet"_ns
, u
""_ns
, u
"auto"_ns
},
147 {u
"<s.css>; rel=stylesheet; fetchpriority=\"low\""_ns
, true, u
"s.css"_ns
,
148 u
"stylesheet"_ns
, u
""_ns
, u
"low"_ns
},
149 {u
"<s.css>; rel=stylesheet; fetchpriority=\"high\""_ns
, true, u
"s.css"_ns
,
150 u
"stylesheet"_ns
, u
""_ns
, u
"high"_ns
},
151 {u
"<s.css>; rel=stylesheet; fetchpriority=\"foo\""_ns
, true, u
"s.css"_ns
,
152 u
"stylesheet"_ns
, u
""_ns
, u
"foo"_ns
},
153 {u
"<s.css>; rel=stylesheet; fetchpriority=\"\""_ns
, true, u
"s.css"_ns
,
154 u
"stylesheet"_ns
, u
""_ns
, u
""_ns
},
155 {u
"<s.css>; rel=stylesheet; fetchpriority=fooWithoutDoubleQuotes"_ns
, true,
156 u
"s.css"_ns
, u
"stylesheet"_ns
, u
""_ns
, u
"fooWithoutDoubleQuotes"_ns
},
157 {u
"</images/cat.jpg>; rel=prefetch"_ns
, true, u
"/images/cat.jpg"_ns
,
158 u
"prefetch"_ns
, u
""_ns
},
159 {u
"</images/cat.jpg>;rel=prefetch"_ns
, true, u
"/images/cat.jpg"_ns
,
160 u
"prefetch"_ns
, u
""_ns
},
161 {u
"</images/cat.jpg> ;rel=prefetch"_ns
, true, u
"/images/cat.jpg"_ns
,
162 u
"prefetch"_ns
, u
""_ns
},
163 {u
"</images/cat.jpg> ; rel=prefetch"_ns
, true, u
"/images/cat.jpg"_ns
,
164 u
"prefetch"_ns
, u
""_ns
},
165 {u
"< /images/cat.jpg> ; rel=prefetch"_ns
, true, u
"/images/cat.jpg"_ns
,
166 u
"prefetch"_ns
, u
""_ns
},
167 {u
"</images/cat.jpg > ; rel=prefetch"_ns
, true, u
"/images/cat.jpg"_ns
,
168 u
"prefetch"_ns
, u
""_ns
},
169 // TODO(1744051): don't ignore spaces in href
170 // {u"</images/cat.jpg wutwut> ; rel=prefetch"_ns, true,
171 // u"/images/cat.jpg wutwut"_ns, u"prefetch"_ns, u""_ns},
172 {u
"</images/cat.jpg wutwut> ; rel=prefetch"_ns
, true,
173 u
"/images/cat.jpgwutwut"_ns
, u
"prefetch"_ns
, u
""_ns
},
174 // TODO(1744051): don't ignore spaces in href
175 // {u"</images/cat.jpg wutwut \t > ; rel=prefetch"_ns, true,
176 // u"/images/cat.jpg wutwut"_ns, u"prefetch"_ns, u""_ns},
177 {u
"</images/cat.jpg wutwut \t > ; rel=prefetch"_ns
, true,
178 u
"/images/cat.jpgwutwut"_ns
, u
"prefetch"_ns
, u
""_ns
},
179 {u
"</images/cat.jpg>; rel=prefetch "_ns
, true, u
"/images/cat.jpg"_ns
,
180 u
"prefetch"_ns
, u
""_ns
},
181 {u
"</images/cat.jpg>; Rel=prefetch "_ns
, true, u
"/images/cat.jpg"_ns
,
182 u
"prefetch"_ns
, u
""_ns
},
183 {u
"</images/cat.jpg>; Rel=PReFetCh "_ns
, true, u
"/images/cat.jpg"_ns
,
184 u
"PReFetCh"_ns
, u
""_ns
},
185 {u
"</images/cat.jpg>; rel=prefetch; rel=somethingelse"_ns
, true,
186 u
"/images/cat.jpg"_ns
, u
"prefetch"_ns
, u
""_ns
},
187 {u
"</images/cat.jpg>\t\t ; \trel=prefetch \t "_ns
, true,
188 u
"/images/cat.jpg"_ns
, u
"prefetch"_ns
, u
""_ns
},
189 {u
"</images/cat.jpg>; rel= prefetch"_ns
, true, u
"/images/cat.jpg"_ns
,
190 u
"prefetch"_ns
, u
""_ns
},
191 {u
"<../images/cat.jpg?dog>; rel= prefetch"_ns
, true,
192 u
"../images/cat.jpg?dog"_ns
, u
"prefetch"_ns
, u
""_ns
},
193 {u
"</images/cat.jpg>; rel =prefetch"_ns
, true, u
"/images/cat.jpg"_ns
,
194 u
"prefetch"_ns
, u
""_ns
},
195 {u
"</images/cat.jpg>; rel pel=prefetch"_ns
, false},
196 // different from chromium test case, because we already check for
197 // existence of "rel" parameter
198 {u
"< /images/cat.jpg>"_ns
, false},
199 {u
"</images/cat.jpg>; wut=sup; rel =prefetch"_ns
, true,
200 u
"/images/cat.jpg"_ns
, u
"prefetch"_ns
, u
""_ns
},
201 {u
"</images/cat.jpg>; wut=sup ; rel =prefetch"_ns
, true,
202 u
"/images/cat.jpg"_ns
, u
"prefetch"_ns
, u
""_ns
},
203 {u
"</images/cat.jpg>; wut=sup ; rel =prefetch \t ;"_ns
, true,
204 u
"/images/cat.jpg"_ns
, u
"prefetch"_ns
, u
""_ns
},
205 // TODO(1744051): forbid non-whitespace characters between '>' and the first
206 // semicolon making it conform RFC 8288 Sec 3
207 // {u"</images/cat.jpg> wut=sup ; rel =prefetch \t ;"_ns, false},
208 {u
"</images/cat.jpg> wut=sup ; rel =prefetch \t ;"_ns
, true,
209 u
"/images/cat.jpg"_ns
, u
"prefetch"_ns
, u
""_ns
},
210 {u
"< /images/cat.jpg"_ns
, false},
211 // TODO(1744051): don't ignore spaces in href
212 // {u"< http://wut.com/ sdfsdf ?sd>; rel=dns-prefetch"_ns, true,
213 // u"http://wut.com/ sdfsdf ?sd"_ns, u"dns-prefetch"_ns, u""_ns},
214 {u
"< http://wut.com/ sdfsdf ?sd>; rel=dns-prefetch"_ns
, true,
215 u
"http://wut.com/sdfsdf?sd"_ns
, u
"dns-prefetch"_ns
, u
""_ns
},
216 {u
"< http://wut.com/%20%20%3dsdfsdf?sd>; rel=dns-prefetch"_ns
, true,
217 u
"http://wut.com/%20%20%3dsdfsdf?sd"_ns
, u
"dns-prefetch"_ns
, u
""_ns
},
218 {u
"< http://wut.com/dfsdf?sdf=ghj&wer=rty>; rel=prefetch"_ns
, true,
219 u
"http://wut.com/dfsdf?sdf=ghj&wer=rty"_ns
, u
"prefetch"_ns
, u
""_ns
},
220 {u
"< http://wut.com/dfsdf?sdf=ghj&wer=rty>;;;;; rel=prefetch"_ns
, true,
221 u
"http://wut.com/dfsdf?sdf=ghj&wer=rty"_ns
, u
"prefetch"_ns
, u
""_ns
},
222 {u
"< http://wut.com/%20%20%3dsdfsdf?sd>; rel=preload;as=image"_ns
, true,
223 u
"http://wut.com/%20%20%3dsdfsdf?sd"_ns
, u
"preload"_ns
, u
"image"_ns
},
224 {u
"< http://wut.com/%20%20%3dsdfsdf?sd>; rel=preload;as=whatever"_ns
,
225 true, u
"http://wut.com/%20%20%3dsdfsdf?sd"_ns
, u
"preload"_ns
,
227 {u
"</images/cat.jpg>; rel=prefetch;"_ns
, true, u
"/images/cat.jpg"_ns
,
228 u
"prefetch"_ns
, u
""_ns
},
229 {u
"</images/cat.jpg>; rel=prefetch ;"_ns
, true, u
"/images/cat.jpg"_ns
,
230 u
"prefetch"_ns
, u
""_ns
},
231 {u
"</images/ca,t.jpg>; rel=prefetch ;"_ns
, true, u
"/images/ca,t.jpg"_ns
,
232 u
"prefetch"_ns
, u
""_ns
},
233 {u
"<simple.css>; rel=stylesheet; title=\"title with a DQUOTE and "
235 true, u
"simple.css"_ns
, u
"stylesheet"_ns
, u
""_ns
},
236 // TODO(1744051): forbid missing end quote
237 // {u"<simple.css>; rel=stylesheet; title=\"title with a DQUOTE \\\" and "
238 // "backslash: \\\""_ns, false},
239 {u
"<simple.css>; rel=stylesheet; title=\"title with a DQUOTE \\\" and backslash: \\\""_ns
,
240 true, u
"simple.css"_ns
, u
"stylesheet"_ns
, u
""_ns
},
241 {u
"<simple.css>; title=\"title with a DQUOTE \\\" and backslash: \"; "
242 "rel=stylesheet; "_ns
,
243 true, u
"simple.css"_ns
, u
"stylesheet"_ns
, u
""_ns
},
244 {u
"<simple.css>; title=\'title with a DQUOTE \\\' and backslash: \'; "
245 "rel=stylesheet; "_ns
,
246 true, u
"simple.css"_ns
, u
"stylesheet"_ns
, u
""_ns
},
247 {u
"<simple.css>; title=\"title with a DQUOTE \\\" and ;backslash,: \"; "
248 "rel=stylesheet; "_ns
,
249 true, u
"simple.css"_ns
, u
"stylesheet"_ns
, u
""_ns
},
250 {u
"<simple.css>; title=\"title with a DQUOTE \' and ;backslash,: \"; "
251 "rel=stylesheet; "_ns
,
252 true, u
"simple.css"_ns
, u
"stylesheet"_ns
, u
""_ns
},
253 {u
"<simple.css>; title=\"\"; rel=stylesheet; "_ns
, true, u
"simple.css"_ns
,
254 u
"stylesheet"_ns
, u
""_ns
},
255 {u
"<simple.css>; title=\"\"; rel=\"stylesheet\"; "_ns
, true,
256 u
"simple.css"_ns
, u
"stylesheet"_ns
, u
""_ns
},
257 // TODO(1744051): forbid missing end quote
258 // {u"<simple.css>; rel=stylesheet; title=\""_ns, false},
259 {u
"<simple.css>; rel=stylesheet; title=\""_ns
, true, u
"simple.css"_ns
,
260 u
"stylesheet"_ns
, u
""_ns
},
261 {u
"<simple.css>; rel=stylesheet; title=\"\""_ns
, true, u
"simple.css"_ns
,
262 u
"stylesheet"_ns
, u
""_ns
},
263 // TODO(1744051): forbid missing end quote
264 // {u"<simple.css>; rel=\"stylesheet\"; title=\""_ns, false},
265 {u
"<simple.css>; rel=\"stylesheet\"; title=\""_ns
, true, u
"simple.css"_ns
,
266 u
"stylesheet"_ns
, u
""_ns
},
267 // TODO(1744051): forbid missing end quote
268 // {u"<simple.css>; rel=\";style,sheet\"; title=\""_ns, false},
269 {u
"<simple.css>; rel=\";style,sheet\"; title=\""_ns
, true, u
"simple.css"_ns
,
270 u
";style,sheet"_ns
, u
""_ns
},
271 // TODO(1744051): forbid missing end quote
272 // {u"<simple.css>; rel=\"bla'sdf\"; title=\""_ns, false}
273 {u
"<simple.css>; rel=\"bla'sdf\"; title=\""_ns
, true, u
"simple.css"_ns
,
274 u
"bla'sdf"_ns
, u
""_ns
},
275 // TODO(1744051): allow explicit empty rel
276 // {u"<simple.css>; rel=\"\"; title=\"\""_ns, true, u"simple.css"_ns,
278 {u
"<simple.css>; rel=\"\"; title=\"\""_ns
, false},
279 {u
"<simple.css>; rel=''; title=\"\""_ns
, true, u
"simple.css"_ns
, u
"''"_ns
,
281 {u
"<simple.css>; rel=''; bla"_ns
, true, u
"simple.css"_ns
, u
"''"_ns
, u
""_ns
},
282 {u
"<simple.css>; rel='prefetch"_ns
, true, u
"simple.css"_ns
, u
"'prefetch"_ns
,
284 // TODO(1744051): forbid missing end quote
285 // {u"<simple.css>; rel=\"prefetch"_ns, false},
286 {u
"<simple.css>; rel=\"prefetch"_ns
, true, u
"simple.css"_ns
,
287 u
"\"prefetch"_ns
, u
""_ns
},
288 {u
"<simple.css>; rel=\""_ns
, false},
289 {u
"simple.css; rel=prefetch"_ns
, false},
290 {u
"<simple.css>; rel=prefetch; rel=foobar"_ns
, true, u
"simple.css"_ns
,
291 u
"prefetch"_ns
, u
""_ns
},
294 INSTANTIATE_TEST_SUITE_P(TestLinkHeader
, SimpleParseTest
,
295 testing::ValuesIn(simple_parse_tests
));
299 struct AnchorTestData
{
301 // building the new anchor in combination with the baseURI
304 const char* resolved
;
307 class AnchorTest
: public ::testing::TestWithParam
<AnchorTestData
> {};
309 MOZ_RUNINIT
const AnchorTestData anchor_tests
[] = {
310 {u
"http://example.com/path/to/index.html"_ns
, u
""_ns
, u
"page.html"_ns
,
311 "http://example.com/path/to/page.html"},
312 {u
"http://example.com/path/to/index.html"_ns
,
313 u
"http://example.com/path/"_ns
, u
"page.html"_ns
,
314 "http://example.com/path/page.html"},
315 {u
"http://example.com/path/to/index.html"_ns
,
316 u
"http://example.com/path/"_ns
, u
"/page.html"_ns
,
317 "http://example.com/page.html"},
318 {u
"http://example.com/path/to/index.html"_ns
, u
".."_ns
, u
"page.html"_ns
,
319 "http://example.com/path/page.html"},
320 {u
"http://example.com/path/to/index.html"_ns
, u
".."_ns
,
321 u
"from/page.html"_ns
, "http://example.com/path/from/page.html"},
322 {u
"http://example.com/path/to/index.html"_ns
, u
"/hello/"_ns
,
323 u
"page.html"_ns
, "http://example.com/hello/page.html"},
324 {u
"http://example.com/path/to/index.html"_ns
, u
"/hello"_ns
, u
"page.html"_ns
,
325 "http://example.com/page.html"},
326 {u
"http://example.com/path/to/index.html"_ns
, u
"#necko"_ns
, u
"page.html"_ns
,
327 "http://example.com/path/to/page.html"},
328 {u
"http://example.com/path/to/index.html"_ns
, u
"https://example.net/"_ns
,
329 u
"to/page.html"_ns
, "https://example.net/to/page.html"},
332 LinkHeader
LinkHeaderFromHrefAndAnchor(nsAString
const& aHref
,
333 nsAString
const& aAnchor
) {
340 TEST_P(AnchorTest
, Anchor
) {
341 const AnchorTestData test
= GetParam();
343 LinkHeader linkHeader
= LinkHeaderFromHrefAndAnchor(test
.href
, test
.anchor
);
345 nsCOMPtr
<nsIURI
> baseURI
;
346 ASSERT_NS_SUCCEEDED(NS_NewURI(getter_AddRefs(baseURI
), test
.baseURI
));
348 nsCOMPtr
<nsIURI
> resolved
;
349 ASSERT_TRUE(NS_SUCCEEDED(
350 linkHeader
.NewResolveHref(getter_AddRefs(resolved
), baseURI
)));
352 ASSERT_STREQ(resolved
->GetSpecOrDefault().get(), test
.resolved
);
355 INSTANTIATE_TEST_SUITE_P(TestLinkHeader
, AnchorTest
,
356 testing::ValuesIn(anchor_tests
));