bool
nsHttpNegotiateAuth::MatchesBaseURI(const nsCSubstring &matchScheme,
                                    const nsCSubstring &matchHost,
                                    PRInt32             matchPort,
                                    const char         *baseStart,
                                    const char         *baseEnd)
{
    // check if scheme://host:port matches baseURI

    // parse the base URI
    const char *hostStart, *schemeEnd = strstr(baseStart, "://");
    if (schemeEnd) {
        // the given scheme must match the parsed scheme exactly
        if (!matchScheme.Equals(Substring(baseStart, schemeEnd)))
            return false;
        hostStart = schemeEnd + 3;
    }
    else
        hostStart = baseStart;

    // XXX this does not work for IPv6-literals
    const char *hostEnd = strchr(hostStart, ':');
    if (hostEnd && hostEnd < baseEnd) {
        // the given port must match the parsed port exactly
        int port = atoi(hostEnd + 1);
        if (matchPort != (PRInt32) port)
            return false;
    }
    else
        hostEnd = baseEnd;


    // if we didn't parse out a host, then assume we got a match.
    if (hostStart == hostEnd)
        return true;

    PRUint32 hostLen = hostEnd - hostStart;

    // matchHost must either equal host or be a subdomain of host
    if (matchHost.Length() < hostLen)
        return false;

    const char *end = matchHost.EndReading();
    if (PL_strncasecmp(end - hostLen, hostStart, hostLen) == 0) {
        // if matchHost ends with host from the base URI, then make sure it is
        // either an exact match, or prefixed with a dot.  we don't want
        // "foobar.com" to match "bar.com"
        if (matchHost.Length() == hostLen ||
            *(end - hostLen) == '.' ||
            *(end - hostLen - 1) == '.')
            return true;
    }

    return false;
}
Ejemplo n.º 2
0
bool
MatchesBaseURI(const nsCSubstring &matchScheme,
               const nsCSubstring &matchHost,
               int32_t             matchPort,
               nsDependentCSubstring const& url)
{
  // check if scheme://host:port matches baseURI

  // parse the base URI
  mozilla::Tokenizer t(url);
  mozilla::Tokenizer::Token token;

  t.SkipWhites();

  // We don't know if the url to check against starts with scheme
  // or a host name.  Start recording here.
  t.Record();

  mozilla::Unused << t.Next(token);

  // The ipv6 literals MUST be enclosed with [] in the preference.
  bool ipv6 = false;
  if (token.Equals(mozilla::Tokenizer::Token::Char('['))) {
    nsDependentCSubstring ipv6BareLiteral;
    if (!t.ReadUntil(mozilla::Tokenizer::Token::Char(']'), ipv6BareLiteral)) {
      // Broken ipv6 literal
      return false;
    }

    nsDependentCSubstring ipv6Literal;
    t.Claim(ipv6Literal, mozilla::Tokenizer::INCLUDE_LAST);
    if (!matchHost.Equals(ipv6Literal, nsCaseInsensitiveUTF8StringComparator()) &&
        !matchHost.Equals(ipv6BareLiteral, nsCaseInsensitiveUTF8StringComparator())) {
      return false;
    }

    ipv6 = true;
  } else if (t.CheckChar(':') && t.CheckChar('/') && t.CheckChar('/')) {
    if (!matchScheme.Equals(token.Fragment())) {
      return false;
    }
    // Re-start recording the hostname from the point after scheme://.
    t.Record();
  }

  while (t.Next(token)) {
    bool eof = token.Equals(mozilla::Tokenizer::Token::EndOfFile());
    bool port = token.Equals(mozilla::Tokenizer::Token::Char(':'));

    if (eof || port) {
      if (!ipv6) { // Match already performed above.
        nsDependentCSubstring hostName;
        t.Claim(hostName);

        // An empty hostname means to accept everything for the schema
        if (!hostName.IsEmpty()) {
          /*
           host:      bar.com   foo.bar.com   foobar.com  foo.bar.com    bar.com
           pref:      bar.com       bar.com      bar.com     .bar.com   .bar.com
           result:     accept        accept       reject       accept     reject
          */
          if (!StringEndsWith(matchHost, hostName, nsCaseInsensitiveUTF8StringComparator())) {
            return false;
          }
          if (matchHost.Length() > hostName.Length() &&
              matchHost[matchHost.Length() - hostName.Length() - 1] != '.' &&
              hostName[0] != '.') {
            return false;
          }
        }
      }

      if (port) {
        uint16_t portNumber;
        if (!t.ReadInteger(&portNumber)) {
          // Missing port number
          return false;
        }
        if (matchPort != portNumber) {
          return false;
        }
        if (!t.CheckEOF()) {
          return false;
        }
      }
    } else if (ipv6) {
      // After an ipv6 literal there can only be EOF or :port.  Everything else
      // must be treated as non-match/broken input.
      return false;
    }
  }

  // All negative checks has passed positively.
  return true;
}