Coverage Report

Created: 2018-09-25 14:53

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