tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestLinkHeader.cpp (15169B)


      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/. */
      4 
      5 #include <ostream>
      6 
      7 #include "gtest/gtest-param-test.h"
      8 #include "gtest/gtest.h"
      9 
     10 #include "mozilla/gtest/MozAssertions.h"
     11 #include "nsNetUtil.h"
     12 
     13 using namespace mozilla::net;
     14 
     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;
     31 }
     32 
     33 LinkHeader LinkHeaderSetTitle(nsAString const& v) {
     34  LinkHeader l;
     35  l.mHref = v;
     36  l.mRel = v;
     37  l.mTitle = v;
     38  return l;
     39 }
     40 
     41 LinkHeader LinkHeaderSetMinimum(nsAString const& v) {
     42  LinkHeader l;
     43  l.mHref = v;
     44  l.mRel = v;
     45  return l;
     46 }
     47 
     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 << ", ";
     53    }
     54    first = false;
     55 
     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 << ")";
     70  }
     71 }
     72 
     73 TEST(TestLinkHeader, MultipleLinkHeaders)
     74 {
     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;
     79 
     80  nsTArray<LinkHeader> linkHeaders = ParseLinkHeader(link);
     81 
     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));
     86 
     87  ASSERT_EQ(linkHeaders, expected);
     88 }
     89 
     90 // title* has to be tested separately
     91 TEST(TestLinkHeader, MultipleLinkHeadersTitleStar)
     92 {
     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;
     97 
     98  nsTArray<LinkHeader> linkHeaders = ParseLinkHeader(link);
     99 
    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));
    104 
    105  ASSERT_EQ(linkHeaders, expected);
    106 }
    107 
    108 struct SimpleParseTestData {
    109  nsString link;
    110  bool valid;
    111  nsString url;
    112  nsString rel;
    113  nsString as;
    114  nsString fetchpriority;
    115 
    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         << ")";
    121  }
    122 };
    123 
    124 class SimpleParseTest : public ::testing::TestWithParam<SimpleParseTestData> {};
    125 
    126 TEST_P(SimpleParseTest, Simple) {
    127  const SimpleParseTestData test = GetParam();
    128 
    129  nsTArray<LinkHeader> linkHeaders = ParseLinkHeader(test.link);
    130 
    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);
    138  }
    139 }
    140 
    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,
    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},
    292 };
    293 
    294 INSTANTIATE_TEST_SUITE_P(TestLinkHeader, SimpleParseTest,
    295                         testing::ValuesIn(simple_parse_tests));
    296 
    297 // Test anchor
    298 
    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;
    305 };
    306 
    307 class AnchorTest : public ::testing::TestWithParam<AnchorTestData> {};
    308 
    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"},
    330 };
    331 
    332 LinkHeader LinkHeaderFromHrefAndAnchor(nsAString const& aHref,
    333                                       nsAString const& aAnchor) {
    334  LinkHeader l;
    335  l.mHref = aHref;
    336  l.mAnchor = aAnchor;
    337  return l;
    338 }
    339 
    340 TEST_P(AnchorTest, Anchor) {
    341  const AnchorTestData test = GetParam();
    342 
    343  LinkHeader linkHeader = LinkHeaderFromHrefAndAnchor(test.href, test.anchor);
    344 
    345  nsCOMPtr<nsIURI> baseURI;
    346  ASSERT_NS_SUCCEEDED(NS_NewURI(getter_AddRefs(baseURI), test.baseURI));
    347 
    348  nsCOMPtr<nsIURI> resolved;
    349  ASSERT_TRUE(NS_SUCCEEDED(
    350      linkHeader.NewResolveHref(getter_AddRefs(resolved), baseURI)));
    351 
    352  ASSERT_STREQ(resolved->GetSpecOrDefault().get(), test.resolved);
    353 }
    354 
    355 INSTANTIATE_TEST_SUITE_P(TestLinkHeader, AnchorTest,
    356                         testing::ValuesIn(anchor_tests));