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 "nsIPrefService.h"
8 #include "nsIURI.h"
9 #include "nsNetUtil.h"
10 #include "nsUnicharUtils.h"
11
12 namespace mozilla {
13 namespace net {
14 namespace auth {
15
16 namespace detail {
17
MatchesBaseURI(const nsACString & matchScheme,const nsACString & matchHost,int32_t matchPort,nsDependentCSubstring const & url)18 bool MatchesBaseURI(const nsACString& matchScheme, const nsACString& matchHost,
19 int32_t matchPort, nsDependentCSubstring const& url) {
20 // check if scheme://host:port matches baseURI
21
22 // parse the base URI
23 mozilla::Tokenizer t(url);
24 mozilla::Tokenizer::Token token;
25
26 t.SkipWhites();
27
28 // We don't know if the url to check against starts with scheme
29 // or a host name. Start recording here.
30 t.Record();
31
32 mozilla::Unused << t.Next(token);
33
34 // The ipv6 literals MUST be enclosed with [] in the preference.
35 bool ipv6 = false;
36 if (token.Equals(mozilla::Tokenizer::Token::Char('['))) {
37 nsDependentCSubstring ipv6BareLiteral;
38 if (!t.ReadUntil(mozilla::Tokenizer::Token::Char(']'), ipv6BareLiteral)) {
39 // Broken ipv6 literal
40 return false;
41 }
42
43 nsDependentCSubstring ipv6Literal;
44 t.Claim(ipv6Literal, mozilla::Tokenizer::INCLUDE_LAST);
45 if (!matchHost.Equals(ipv6Literal,
46 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
URIMatchesPrefPattern(nsIURI * uri,const char * pref)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 mozilla::Unused << 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
172