tor-browser

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

HttpAuthUtils.cpp (4716B)


      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 "mozilla/net/HttpAuthUtils.h"
      6 #include "mozilla/Tokenizer.h"
      7 #include "nsIURI.h"
      8 #include "nsNetUtil.h"
      9 #include "nsUnicharUtils.h"
     10 #include "nsIPrefBranch.h"
     11 #include "nsIPrefService.h"
     12 
     13 namespace mozilla {
     14 namespace net {
     15 namespace auth {
     16 
     17 namespace detail {
     18 
     19 bool MatchesBaseURI(const nsACString& matchScheme, const nsACString& matchHost,
     20                    int32_t matchPort, nsDependentCSubstring const& url) {
     21  // check if scheme://host:port matches baseURI
     22 
     23  // parse the base URI
     24  mozilla::Tokenizer t(url);
     25  mozilla::Tokenizer::Token token;
     26 
     27  t.SkipWhites();
     28 
     29  // We don't know if the url to check against starts with scheme
     30  // or a host name.  Start recording here.
     31  t.Record();
     32 
     33  (void)t.Next(token);
     34 
     35  // The ipv6 literals MUST be enclosed with [] in the preference.
     36  bool ipv6 = false;
     37  if (token.Equals(mozilla::Tokenizer::Token::Char('['))) {
     38    nsDependentCSubstring ipv6BareLiteral;
     39    if (!t.ReadUntil(mozilla::Tokenizer::Token::Char(']'), ipv6BareLiteral)) {
     40      // Broken ipv6 literal
     41      return false;
     42    }
     43 
     44    nsDependentCSubstring ipv6Literal;
     45    t.Claim(ipv6Literal, mozilla::Tokenizer::INCLUDE_LAST);
     46    if (!matchHost.Equals(ipv6Literal, nsCaseInsensitiveUTF8StringComparator) &&
     47        !matchHost.Equals(ipv6BareLiteral,
     48                          nsCaseInsensitiveUTF8StringComparator)) {
     49      return false;
     50    }
     51 
     52    ipv6 = true;
     53  } else if (t.CheckChar(':') && t.CheckChar('/') && t.CheckChar('/')) {
     54    if (!matchScheme.Equals(token.Fragment())) {
     55      return false;
     56    }
     57    // Re-start recording the hostname from the point after scheme://.
     58    t.Record();
     59  }
     60 
     61  while (t.Next(token)) {
     62    bool eof = token.Equals(mozilla::Tokenizer::Token::EndOfFile());
     63    bool port = token.Equals(mozilla::Tokenizer::Token::Char(':'));
     64 
     65    if (eof || port) {
     66      if (!ipv6) {  // Match already performed above.
     67        nsDependentCSubstring hostName;
     68        t.Claim(hostName);
     69 
     70        // An empty hostname means to accept everything for the schema
     71        if (!hostName.IsEmpty()) {
     72          /*
     73           host:      bar.com   foo.bar.com   foobar.com  foo.bar.com    bar.com
     74           pref:      bar.com       bar.com      bar.com     .bar.com   .bar.com
     75           result:     accept        accept       reject       accept     reject
     76          */
     77          if (!StringEndsWith(matchHost, hostName,
     78                              nsCaseInsensitiveUTF8StringComparator)) {
     79            return false;
     80          }
     81          if (matchHost.Length() > hostName.Length() &&
     82              matchHost[matchHost.Length() - hostName.Length() - 1] != '.' &&
     83              hostName[0] != '.') {
     84            return false;
     85          }
     86        }
     87      }
     88 
     89      if (port) {
     90        uint16_t portNumber;
     91        if (!t.ReadInteger(&portNumber)) {
     92          // Missing port number
     93          return false;
     94        }
     95        if (matchPort != portNumber) {
     96          return false;
     97        }
     98        if (!t.CheckEOF()) {
     99          return false;
    100        }
    101      }
    102    } else if (ipv6) {
    103      // After an ipv6 literal there can only be EOF or :port.  Everything else
    104      // must be treated as non-match/broken input.
    105      return false;
    106    }
    107  }
    108 
    109  // All negative checks has passed positively.
    110  return true;
    111 }
    112 
    113 }  // namespace detail
    114 
    115 bool URIMatchesPrefPattern(nsIURI* uri, const char* pref) {
    116  nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
    117  if (!prefs) {
    118    return false;
    119  }
    120 
    121  nsAutoCString scheme, host;
    122  int32_t port;
    123 
    124  if (NS_FAILED(uri->GetScheme(scheme))) {
    125    return false;
    126  }
    127  if (NS_FAILED(uri->GetAsciiHost(host))) {
    128    return false;
    129  }
    130 
    131  port = NS_GetRealPort(uri);
    132  if (port == -1) {
    133    return false;
    134  }
    135 
    136  nsAutoCString hostList;
    137  if (NS_FAILED(prefs->GetCharPref(pref, hostList))) {
    138    return false;
    139  }
    140 
    141  // pseudo-BNF
    142  // ----------
    143  //
    144  // url-list       base-url ( base-url "," LWS )*
    145  // base-url       ( scheme-part | host-part | scheme-part host-part )
    146  // scheme-part    scheme "://"
    147  // host-part      host [":" port]
    148  //
    149  // for example:
    150  //   "https://, http://office.foo.com"
    151  //
    152 
    153  mozilla::Tokenizer t(hostList);
    154  while (!t.CheckEOF()) {
    155    t.SkipWhites();
    156    nsDependentCSubstring url;
    157    (void)t.ReadUntil(mozilla::Tokenizer::Token::Char(','), url);
    158    if (url.IsEmpty()) {
    159      continue;
    160    }
    161    if (detail::MatchesBaseURI(scheme, host, port, url)) {
    162      return true;
    163    }
    164  }
    165 
    166  return false;
    167 }
    168 
    169 }  // namespace auth
    170 }  // namespace net
    171 }  // namespace mozilla