Bug 1857386 [wpt PR 42383] - Update wpt metadata, a=testonly
[gecko.git] / netwerk / test / gtest / TestLinkHeader.cpp
blob4da7002f8730e4f3528dd85198932f1576184be8
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/. */
5 #include <ostream>
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) {
16 LinkHeader l;
17 l.mHref = v;
18 l.mRel = v;
19 l.mTitle = v;
20 l.mIntegrity = v;
21 l.mSrcset = v;
22 l.mSizes = v;
23 l.mType = v;
24 l.mMedia = v;
25 l.mAnchor = v;
26 l.mCrossOrigin = v;
27 l.mReferrerPolicy = v;
28 l.mAs = v;
29 l.mFetchPriority = v;
30 return l;
33 LinkHeader LinkHeaderSetTitle(nsAString const& v) {
34 LinkHeader l;
35 l.mHref = v;
36 l.mRel = v;
37 l.mTitle = v;
38 return l;
41 LinkHeader LinkHeaderSetMinimum(nsAString const& v) {
42 LinkHeader l;
43 l.mHref = v;
44 l.mRel = v;
45 return l;
48 void PrintTo(const nsTArray<LinkHeader>& aLinkHeaders, std::ostream* aOs) {
49 bool first = true;
50 for (const auto& header : aLinkHeaders) {
51 if (!first) {
52 *aOs << ", ";
54 first = false;
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)
75 nsString link =
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
78 u"<c>; rel=c"_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)
93 nsString link =
94 u"<d>; rel=d; title*=UTF-8'de'd,"_ns
95 u"<e>; rel=e; title*=UTF-8'de'e; title=g,"_ns
96 u"<f>; rel=f"_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 {
109 nsString link;
110 bool valid;
111 nsString url;
112 nsString rel;
113 nsString as;
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
120 << ")";
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());
132 if (test.valid) {
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 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,
226 u"whatever"_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 "
234 "backslash\""_ns,
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,
277 // u""_ns, u""_ns}
278 {u"<simple.css>; rel=\"\"; title=\"\""_ns, false},
279 {u"<simple.css>; rel=''; title=\"\""_ns, true, u"simple.css"_ns, u"''"_ns,
280 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,
283 u""_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));
297 // Test anchor
299 struct AnchorTestData {
300 nsString baseURI;
301 // building the new anchor in combination with the baseURI
302 nsString anchor;
303 nsString href;
304 const char* resolved;
307 class AnchorTest : public ::testing::TestWithParam<AnchorTestData> {};
309 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) {
334 LinkHeader l;
335 l.mHref = aHref;
336 l.mAnchor = aAnchor;
337 return l;
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));