Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set sw=4 ts=8 et tw=80 : */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : // HttpLog.h should generally be included first
8 : #include "HttpLog.h"
9 :
10 : // Log on level :5, instead of default :4.
11 : #undef LOG
12 : #define LOG(args) LOG5(args)
13 : #undef LOG_ENABLED
14 : #define LOG_ENABLED() LOG5_ENABLED()
15 :
16 : #include "nsHttpConnectionInfo.h"
17 : #include "mozilla/net/DNS.h"
18 : #include "prnetdb.h"
19 : #include "nsICryptoHash.h"
20 : #include "nsComponentManagerUtils.h"
21 : #include "nsIProtocolProxyService.h"
22 :
23 : static nsresult
24 0 : SHA256(const char* aPlainText, nsAutoCString& aResult)
25 : {
26 : static nsICryptoHash* hasher = nullptr;
27 : nsresult rv;
28 0 : if (!hasher) {
29 0 : rv = CallCreateInstance("@mozilla.org/security/hash;1", &hasher);
30 0 : if (NS_FAILED(rv)) {
31 0 : LOG(("nsHttpDigestAuth: no crypto hash!\n"));
32 0 : return rv;
33 : }
34 : }
35 :
36 0 : rv = hasher->Init(nsICryptoHash::SHA256);
37 0 : NS_ENSURE_SUCCESS(rv, rv);
38 :
39 0 : rv = hasher->Update((unsigned char*) aPlainText, strlen(aPlainText));
40 0 : NS_ENSURE_SUCCESS(rv, rv);
41 :
42 0 : rv = hasher->Finish(false, aResult);
43 0 : return rv;
44 : }
45 :
46 : namespace mozilla {
47 : namespace net {
48 :
49 8 : nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &originHost,
50 : int32_t originPort,
51 : const nsACString &npnToken,
52 : const nsACString &username,
53 : nsProxyInfo *proxyInfo,
54 : const OriginAttributes &originAttributes,
55 8 : bool endToEndSSL)
56 8 : : mRoutedPort(443)
57 : {
58 8 : Init(originHost, originPort, npnToken, username, proxyInfo, originAttributes, endToEndSSL);
59 8 : }
60 :
61 0 : nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &originHost,
62 : int32_t originPort,
63 : const nsACString &npnToken,
64 : const nsACString &username,
65 : nsProxyInfo *proxyInfo,
66 : const OriginAttributes &originAttributes,
67 : const nsACString &routedHost,
68 0 : int32_t routedPort)
69 : {
70 0 : mEndToEndSSL = true; // so DefaultPort() works
71 0 : mRoutedPort = routedPort == -1 ? DefaultPort() : routedPort;
72 :
73 0 : if (!originHost.Equals(routedHost) || (originPort != routedPort)) {
74 0 : mRoutedHost = routedHost;
75 : }
76 0 : Init(originHost, originPort, npnToken, username, proxyInfo, originAttributes, true);
77 0 : }
78 :
79 : void
80 8 : nsHttpConnectionInfo::Init(const nsACString &host, int32_t port,
81 : const nsACString &npnToken,
82 : const nsACString &username,
83 : nsProxyInfo* proxyInfo,
84 : const OriginAttributes &originAttributes,
85 : bool e2eSSL)
86 : {
87 8 : LOG(("Init nsHttpConnectionInfo @%p\n", this));
88 :
89 8 : mUsername = username;
90 8 : mProxyInfo = proxyInfo;
91 8 : mEndToEndSSL = e2eSSL;
92 8 : mUsingConnect = false;
93 8 : mNPNToken = npnToken;
94 8 : mOriginAttributes = originAttributes;
95 :
96 8 : mUsingHttpsProxy = (proxyInfo && proxyInfo->IsHTTPS());
97 8 : mUsingHttpProxy = mUsingHttpsProxy || (proxyInfo && proxyInfo->IsHTTP());
98 :
99 8 : if (mUsingHttpProxy) {
100 0 : mUsingConnect = mEndToEndSSL; // SSL always uses CONNECT
101 0 : uint32_t resolveFlags = 0;
102 0 : if (NS_SUCCEEDED(mProxyInfo->GetResolveFlags(&resolveFlags)) &&
103 0 : resolveFlags & nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL) {
104 0 : mUsingConnect = true;
105 : }
106 : }
107 :
108 8 : SetOriginServer(host, port);
109 8 : }
110 :
111 : void
112 0 : nsHttpConnectionInfo::SetNetworkInterfaceId(const nsACString& aNetworkInterfaceId)
113 : {
114 0 : mNetworkInterfaceId = aNetworkInterfaceId;
115 0 : BuildHashKey();
116 0 : }
117 :
118 8 : void nsHttpConnectionInfo::BuildHashKey()
119 : {
120 : //
121 : // build hash key:
122 : //
123 : // the hash key uniquely identifies the connection type. two connections
124 : // are "equal" if they end up talking the same protocol to the same server
125 : // and are both used for anonymous or non-anonymous connection only;
126 : // anonymity of the connection is setup later from nsHttpChannel::AsyncOpen
127 : // where we know we use anonymous connection (LOAD_ANONYMOUS load flag)
128 : //
129 :
130 : const char *keyHost;
131 : int32_t keyPort;
132 :
133 8 : if (mUsingHttpProxy && !mUsingConnect) {
134 0 : keyHost = ProxyHost();
135 0 : keyPort = ProxyPort();
136 : } else {
137 8 : keyHost = Origin();
138 8 : keyPort = OriginPort();
139 : }
140 :
141 : // The hashkey has 4 fields followed by host connection info
142 : // byte 0 is P/T/. {P,T} for Plaintext/TLS Proxy over HTTP
143 : // byte 1 is S/. S is for end to end ssl such as https:// uris
144 : // byte 2 is A/. A is for an anonymous channel (no cookies, etc..)
145 : // byte 3 is P/. P is for a private browising channel
146 : // byte 4 is I/. I is for insecure scheme on TLS for http:// uris
147 : // byte 5 is X/. X is for disallow_spdy flag
148 : // byte 6 is C/. C is for be Conservative
149 :
150 8 : mHashKey.AssignLiteral(".......");
151 8 : mHashKey.Append(keyHost);
152 8 : if (!mNetworkInterfaceId.IsEmpty()) {
153 0 : mHashKey.Append('(');
154 0 : mHashKey.Append(mNetworkInterfaceId);
155 0 : mHashKey.Append(')');
156 : }
157 8 : mHashKey.Append(':');
158 8 : mHashKey.AppendInt(keyPort);
159 8 : if (!mUsername.IsEmpty()) {
160 0 : mHashKey.Append('[');
161 0 : mHashKey.Append(mUsername);
162 0 : mHashKey.Append(']');
163 : }
164 :
165 8 : if (mUsingHttpsProxy) {
166 0 : mHashKey.SetCharAt('T', 0);
167 8 : } else if (mUsingHttpProxy) {
168 0 : mHashKey.SetCharAt('P', 0);
169 : }
170 8 : if (mEndToEndSSL) {
171 0 : mHashKey.SetCharAt('S', 1);
172 : }
173 :
174 : // NOTE: for transparent proxies (e.g., SOCKS) we need to encode the proxy
175 : // info in the hash key (this ensures that we will continue to speak the
176 : // right protocol even if our proxy preferences change).
177 : //
178 : // NOTE: for SSL tunnels add the proxy information to the cache key.
179 : // We cannot use the proxy as the host parameter (as we do for non SSL)
180 : // because this is a single host tunnel, but we need to include the proxy
181 : // information so that a change in proxy config will mean this connection
182 : // is not reused
183 :
184 : // NOTE: Adding the username and the password provides a means to isolate
185 : // keep-alive to the URL bar domain as well: If the username is the URL bar
186 : // domain, keep-alive connections are not reused by resources bound to
187 : // different URL bar domains as the respective hash keys are not matching.
188 :
189 16 : if ((!mUsingHttpProxy && ProxyHost()) ||
190 8 : (mUsingHttpProxy && mUsingConnect)) {
191 0 : mHashKey.AppendLiteral(" (");
192 0 : mHashKey.Append(ProxyType());
193 0 : mHashKey.Append(':');
194 0 : mHashKey.Append(ProxyHost());
195 0 : mHashKey.Append(':');
196 0 : mHashKey.AppendInt(ProxyPort());
197 0 : mHashKey.Append(')');
198 0 : mHashKey.Append('[');
199 0 : mHashKey.Append(ProxyUsername());
200 0 : mHashKey.Append(':');
201 0 : const char* password = ProxyPassword();
202 0 : if (strlen(password) > 0) {
203 0 : nsAutoCString digestedPassword;
204 0 : nsresult rv = SHA256(password, digestedPassword);
205 0 : if (rv == NS_OK) {
206 0 : mHashKey.Append(digestedPassword);
207 : }
208 : }
209 0 : mHashKey.Append(']');
210 : }
211 :
212 8 : if(!mRoutedHost.IsEmpty()) {
213 0 : mHashKey.AppendLiteral(" <ROUTE-via ");
214 0 : mHashKey.Append(mRoutedHost);
215 0 : mHashKey.Append(':');
216 0 : mHashKey.AppendInt(mRoutedPort);
217 0 : mHashKey.Append('>');
218 : }
219 :
220 8 : if (!mNPNToken.IsEmpty()) {
221 0 : mHashKey.AppendLiteral(" {NPN-TOKEN ");
222 0 : mHashKey.Append(mNPNToken);
223 0 : mHashKey.AppendLiteral("}");
224 : }
225 :
226 16 : nsAutoCString originAttributes;
227 8 : mOriginAttributes.CreateSuffix(originAttributes);
228 8 : mHashKey.Append(originAttributes);
229 8 : }
230 :
231 : void
232 8 : nsHttpConnectionInfo::SetOriginServer(const nsACString &host, int32_t port)
233 : {
234 8 : mOrigin = host;
235 8 : mOriginPort = port == -1 ? DefaultPort() : port;
236 8 : BuildHashKey();
237 8 : }
238 :
239 : nsHttpConnectionInfo*
240 2 : nsHttpConnectionInfo::Clone() const
241 : {
242 : nsHttpConnectionInfo *clone;
243 2 : if (mRoutedHost.IsEmpty()) {
244 4 : clone = new nsHttpConnectionInfo(mOrigin, mOriginPort, mNPNToken, mUsername, mProxyInfo,
245 6 : mOriginAttributes, mEndToEndSSL);
246 : } else {
247 0 : MOZ_ASSERT(mEndToEndSSL);
248 0 : clone = new nsHttpConnectionInfo(mOrigin, mOriginPort, mNPNToken, mUsername, mProxyInfo,
249 0 : mOriginAttributes, mRoutedHost, mRoutedPort);
250 : }
251 :
252 2 : if (!mNetworkInterfaceId.IsEmpty()) {
253 0 : clone->SetNetworkInterfaceId(mNetworkInterfaceId);
254 : }
255 :
256 : // Make sure the anonymous, insecure-scheme, and private flags are transferred
257 2 : clone->SetAnonymous(GetAnonymous());
258 2 : clone->SetPrivate(GetPrivate());
259 2 : clone->SetInsecureScheme(GetInsecureScheme());
260 2 : clone->SetNoSpdy(GetNoSpdy());
261 2 : clone->SetBeConservative(GetBeConservative());
262 2 : MOZ_ASSERT(clone->Equals(this));
263 :
264 2 : return clone;
265 : }
266 :
267 : void
268 0 : nsHttpConnectionInfo::CloneAsDirectRoute(nsHttpConnectionInfo **outCI)
269 : {
270 0 : if (mRoutedHost.IsEmpty()) {
271 0 : *outCI = Clone();
272 0 : return;
273 : }
274 :
275 : RefPtr<nsHttpConnectionInfo> clone =
276 : new nsHttpConnectionInfo(mOrigin, mOriginPort,
277 0 : EmptyCString(), mUsername, mProxyInfo,
278 0 : mOriginAttributes, mEndToEndSSL);
279 : // Make sure the anonymous, insecure-scheme, and private flags are transferred
280 0 : clone->SetAnonymous(GetAnonymous());
281 0 : clone->SetPrivate(GetPrivate());
282 0 : clone->SetInsecureScheme(GetInsecureScheme());
283 0 : clone->SetNoSpdy(GetNoSpdy());
284 0 : clone->SetBeConservative(GetBeConservative());
285 0 : if (!mNetworkInterfaceId.IsEmpty()) {
286 0 : clone->SetNetworkInterfaceId(mNetworkInterfaceId);
287 : }
288 0 : clone.forget(outCI);
289 : }
290 :
291 : nsresult
292 0 : nsHttpConnectionInfo::CreateWildCard(nsHttpConnectionInfo **outParam)
293 : {
294 : // T???mozilla.org:443 (https:proxy.ducksong.com:3128) [specifc form]
295 : // TS??*:0 (https:proxy.ducksong.com:3128) [wildcard form]
296 :
297 0 : if (!mUsingHttpsProxy) {
298 0 : MOZ_ASSERT(false);
299 : return NS_ERROR_NOT_IMPLEMENTED;
300 : }
301 :
302 0 : RefPtr<nsHttpConnectionInfo> clone;
303 0 : clone = new nsHttpConnectionInfo(NS_LITERAL_CSTRING("*"), 0,
304 : mNPNToken, mUsername, mProxyInfo,
305 0 : mOriginAttributes, true);
306 : // Make sure the anonymous and private flags are transferred!
307 0 : clone->SetAnonymous(GetAnonymous());
308 0 : clone->SetPrivate(GetPrivate());
309 0 : clone.forget(outParam);
310 0 : return NS_OK;
311 : }
312 :
313 : bool
314 3 : nsHttpConnectionInfo::UsingProxy()
315 : {
316 3 : if (!mProxyInfo)
317 3 : return false;
318 0 : return !mProxyInfo->IsDirect();
319 : }
320 :
321 : bool
322 5 : nsHttpConnectionInfo::HostIsLocalIPLiteral() const
323 : {
324 : PRNetAddr prAddr;
325 : // If the host/proxy host is not an IP address literal, return false.
326 5 : if (ProxyHost()) {
327 0 : if (PR_StringToNetAddr(ProxyHost(), &prAddr) != PR_SUCCESS) {
328 0 : return false;
329 : }
330 5 : } else if (PR_StringToNetAddr(Origin(), &prAddr) != PR_SUCCESS) {
331 4 : return false;
332 : }
333 : NetAddr netAddr;
334 1 : PRNetAddrToNetAddr(&prAddr, &netAddr);
335 1 : return IsIPAddrLocal(&netAddr);
336 : }
337 :
338 : } // namespace net
339 : } // namespace mozilla
|