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