diff options
Diffstat (limited to 'netwerk/protocol/http/HttpAuthUtils.cpp')
-rw-r--r-- | netwerk/protocol/http/HttpAuthUtils.cpp | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/netwerk/protocol/http/HttpAuthUtils.cpp b/netwerk/protocol/http/HttpAuthUtils.cpp new file mode 100644 index 0000000000..9bd34ef769 --- /dev/null +++ b/netwerk/protocol/http/HttpAuthUtils.cpp @@ -0,0 +1,171 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/net/HttpAuthUtils.h" +#include "mozilla/Tokenizer.h" +#include "nsIURI.h" +#include "nsNetUtil.h" +#include "nsUnicharUtils.h" +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" + +namespace mozilla { +namespace net { +namespace auth { + +namespace detail { + +bool MatchesBaseURI(const nsACString& matchScheme, const nsACString& 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; +} + +} // namespace detail + +bool URIMatchesPrefPattern(nsIURI* uri, const char* pref) { + nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (!prefs) { + return false; + } + + nsAutoCString scheme, host; + int32_t port; + + if (NS_FAILED(uri->GetScheme(scheme))) { + return false; + } + if (NS_FAILED(uri->GetAsciiHost(host))) { + return false; + } + + port = NS_GetRealPort(uri); + if (port == -1) { + return false; + } + + nsAutoCString hostList; + if (NS_FAILED(prefs->GetCharPref(pref, hostList))) { + return false; + } + + // pseudo-BNF + // ---------- + // + // url-list base-url ( base-url "," LWS )* + // base-url ( scheme-part | host-part | scheme-part host-part ) + // scheme-part scheme "://" + // host-part host [":" port] + // + // for example: + // "https://, http://office.foo.com" + // + + mozilla::Tokenizer t(hostList); + while (!t.CheckEOF()) { + t.SkipWhites(); + nsDependentCSubstring url; + mozilla::Unused << t.ReadUntil(mozilla::Tokenizer::Token::Char(','), url); + if (url.IsEmpty()) { + continue; + } + if (detail::MatchesBaseURI(scheme, host, port, url)) { + return true; + } + } + + return false; +} + +} // namespace auth +} // namespace net +} // namespace mozilla |