Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/http/AlternateServices.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set sw=2 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
#include "HttpLog.h"
8
9
#include "AlternateServices.h"
10
#include "LoadInfo.h"
11
#include "nsEscape.h"
12
#include "nsHttpConnectionInfo.h"
13
#include "nsHttpChannel.h"
14
#include "nsHttpHandler.h"
15
#include "nsThreadUtils.h"
16
#include "nsHttpTransaction.h"
17
#include "NullHttpTransaction.h"
18
#include "nsISSLSocketControl.h"
19
#include "nsIWellKnownOpportunisticUtils.h"
20
21
/* RFC 7838 Alternative Services
22
   http://httpwg.org/http-extensions/opsec.html
23
    note that connections currently do not do mixed-scheme (the I attribute
24
    in the ConnectionInfo prevents it) but could, do not honor tls-commit and should
25
    not, and always require authentication
26
*/
27
28
namespace mozilla {
29
namespace net {
30
31
// function places true in outIsHTTPS if scheme is https, false if
32
// http, and returns an error if neither. originScheme passed into
33
// alternate service should already be normalized to those lower case
34
// strings by the URI parser (and so there is an assert)- this is an extra check.
35
static nsresult
36
SchemeIsHTTPS(const nsACString &originScheme, bool &outIsHTTPS)
37
0
{
38
0
  outIsHTTPS = originScheme.EqualsLiteral("https");
39
0
40
0
  if (!outIsHTTPS && !originScheme.EqualsLiteral("http")) {
41
0
      MOZ_ASSERT(false, "unexpected scheme");
42
0
      return NS_ERROR_UNEXPECTED;
43
0
  }
44
0
  return NS_OK;
45
0
}
46
47
bool
48
AltSvcMapping::AcceptableProxy(nsProxyInfo *proxyInfo)
49
0
{
50
0
  return !proxyInfo || proxyInfo->IsDirect() || proxyInfo->IsSOCKS();
51
0
}
52
53
void
54
AltSvcMapping::ProcessHeader(const nsCString &buf, const nsCString &originScheme,
55
                             const nsCString &originHost, int32_t originPort,
56
                             const nsACString &username, bool privateBrowsing,
57
                             nsIInterfaceRequestor *callbacks, nsProxyInfo *proxyInfo,
58
                             uint32_t caps, const OriginAttributes &originAttributes)
59
0
{
60
0
  MOZ_ASSERT(NS_IsMainThread());
61
0
  LOG(("AltSvcMapping::ProcessHeader: %s\n", buf.get()));
62
0
  if (!callbacks) {
63
0
    return;
64
0
  }
65
0
66
0
  if (!AcceptableProxy(proxyInfo)) {
67
0
    LOG(("AltSvcMapping::ProcessHeader ignoring due to proxy\n"));
68
0
    return;
69
0
  }
70
0
71
0
  bool isHTTPS;
72
0
  if (NS_FAILED(SchemeIsHTTPS(originScheme, isHTTPS))) {
73
0
    return;
74
0
  }
75
0
  if (!isHTTPS && !gHttpHandler->AllowAltSvcOE()) {
76
0
    LOG(("Alt-Svc Response Header for http:// origin but OE disabled\n"));
77
0
    return;
78
0
  }
79
0
80
0
  LOG(("Alt-Svc Response Header %s\n", buf.get()));
81
0
  ParsedHeaderValueListList parsedAltSvc(buf);
82
0
83
0
  for (uint32_t index = 0; index < parsedAltSvc.mValues.Length(); ++index) {
84
0
    uint32_t maxage = 86400; // default
85
0
    nsAutoCString hostname;
86
0
    nsAutoCString npnToken;
87
0
    int32_t portno = originPort;
88
0
    bool clearEntry = false;
89
0
90
0
    for (uint32_t pairIndex = 0;
91
0
         pairIndex < parsedAltSvc.mValues[index].mValues.Length();
92
0
         ++pairIndex) {
93
0
      nsDependentCSubstring &currentName =
94
0
        parsedAltSvc.mValues[index].mValues[pairIndex].mName;
95
0
      nsDependentCSubstring &currentValue =
96
0
        parsedAltSvc.mValues[index].mValues[pairIndex].mValue;
97
0
98
0
      if (!pairIndex) {
99
0
        if (currentName.EqualsLiteral("clear")) {
100
0
          clearEntry = true;
101
0
          break;
102
0
        }
103
0
104
0
        // h2=[hostname]:443
105
0
        npnToken = currentName;
106
0
        int32_t colonIndex = currentValue.FindChar(':');
107
0
        if (colonIndex >= 0) {
108
0
          portno =
109
0
            atoi(PromiseFlatCString(currentValue).get() + colonIndex + 1);
110
0
        } else {
111
0
          colonIndex = 0;
112
0
        }
113
0
        hostname.Assign(currentValue.BeginReading(), colonIndex);
114
0
      } else if (currentName.EqualsLiteral("ma")) {
115
0
        maxage = atoi(PromiseFlatCString(currentValue).get());
116
0
        break;
117
0
      } else {
118
0
        LOG(("Alt Svc ignoring parameter %s", currentName.BeginReading()));
119
0
      }
120
0
    }
121
0
122
0
    if (clearEntry) {
123
0
      nsCString suffix;
124
0
      originAttributes.CreateSuffix(suffix);
125
0
      LOG(("Alt Svc clearing mapping for %s:%d:%s", originHost.get(),
126
0
           originPort, suffix.get()));
127
0
      gHttpHandler->ConnMgr()->ClearHostMapping(originHost, originPort, originAttributes);
128
0
      continue;
129
0
    }
130
0
131
0
    // unescape modifies a c string in place, so afterwards
132
0
    // update nsCString length
133
0
    nsUnescape(npnToken.BeginWriting());
134
0
    npnToken.SetLength(strlen(npnToken.BeginReading()));
135
0
136
0
    uint32_t spdyIndex;
137
0
    SpdyInformation *spdyInfo = gHttpHandler->SpdyInfo();
138
0
    if (!(NS_SUCCEEDED(spdyInfo->GetNPNIndex(npnToken, &spdyIndex)) &&
139
0
          spdyInfo->ProtocolEnabled(spdyIndex))) {
140
0
      LOG(("Alt Svc unknown protocol %s, ignoring", npnToken.get()));
141
0
      continue;
142
0
    }
143
0
144
0
    RefPtr<AltSvcMapping> mapping = new AltSvcMapping(gHttpHandler->ConnMgr()->GetStoragePtr(),
145
0
                                                      gHttpHandler->ConnMgr()->StorageEpoch(),
146
0
                                                      originScheme,
147
0
                                                      originHost, originPort,
148
0
                                                      username, privateBrowsing,
149
0
                                                      NowInSeconds() + maxage,
150
0
                                                      hostname, portno, npnToken,
151
0
                                                      originAttributes);
152
0
    if (mapping->TTL() <= 0) {
153
0
      LOG(("Alt Svc invalid map"));
154
0
      mapping = nullptr;
155
0
      // since this isn't a parse error, let's clear any existing mapping
156
0
      // as that would have happened if we had accepted the parameters.
157
0
      gHttpHandler->ConnMgr()->ClearHostMapping(originHost, originPort, originAttributes);
158
0
    } else {
159
0
      gHttpHandler->UpdateAltServiceMapping(mapping, proxyInfo, callbacks, caps,
160
0
                                            originAttributes);
161
0
    }
162
0
  }
163
0
}
164
165
AltSvcMapping::AltSvcMapping(DataStorage *storage, int32_t epoch,
166
                             const nsACString &originScheme,
167
                             const nsACString &originHost,
168
                             int32_t originPort,
169
                             const nsACString &username,
170
                             bool privateBrowsing,
171
                             uint32_t expiresAt,
172
                             const nsACString &alternateHost,
173
                             int32_t alternatePort,
174
                             const nsACString &npnToken,
175
                             const OriginAttributes &originAttributes)
176
  : mStorage(storage)
177
  , mStorageEpoch(epoch)
178
  , mAlternateHost(alternateHost)
179
  , mAlternatePort(alternatePort)
180
  , mOriginHost(originHost)
181
  , mOriginPort(originPort)
182
  , mUsername(username)
183
  , mPrivate(privateBrowsing)
184
  , mExpiresAt(expiresAt)
185
  , mValidated(false)
186
  , mMixedScheme(false)
187
  , mNPNToken(npnToken)
188
  , mOriginAttributes(originAttributes)
189
0
{
190
0
  MOZ_ASSERT(NS_IsMainThread());
191
0
192
0
  if (NS_FAILED(SchemeIsHTTPS(originScheme, mHttps))) {
193
0
    LOG(("AltSvcMapping ctor %p invalid scheme\n", this));
194
0
    mExpiresAt = 0; // invalid
195
0
  }
196
0
197
0
  if (mAlternatePort == -1) {
198
0
    mAlternatePort = mHttps ? NS_HTTPS_DEFAULT_PORT : NS_HTTP_DEFAULT_PORT;
199
0
  }
200
0
  if (mOriginPort == -1) {
201
0
    mOriginPort = mHttps ? NS_HTTPS_DEFAULT_PORT : NS_HTTP_DEFAULT_PORT;
202
0
  }
203
0
204
0
  LOG(("AltSvcMapping ctor %p %s://%s:%d to %s:%d\n", this,
205
0
       nsCString(originScheme).get(), mOriginHost.get(), mOriginPort,
206
0
       mAlternateHost.get(), mAlternatePort));
207
0
208
0
  if (mAlternateHost.IsEmpty()) {
209
0
    mAlternateHost = mOriginHost;
210
0
  }
211
0
212
0
  if ((mAlternatePort == mOriginPort) &&
213
0
      mAlternateHost.EqualsIgnoreCase(mOriginHost.get())) {
214
0
    LOG(("Alt Svc is also origin Svc - ignoring\n"));
215
0
    mExpiresAt = 0; // invalid
216
0
  }
217
0
218
0
  if (mExpiresAt) {
219
0
    MakeHashKey(mHashKey, originScheme, mOriginHost, mOriginPort, mPrivate,
220
0
                mOriginAttributes);
221
0
  }
222
0
}
223
224
void
225
AltSvcMapping::MakeHashKey(nsCString &outKey,
226
                           const nsACString &originScheme,
227
                           const nsACString &originHost,
228
                           int32_t originPort,
229
                           bool privateBrowsing,
230
                           const OriginAttributes &originAttributes)
231
0
{
232
0
  outKey.Truncate();
233
0
234
0
  if (originPort == -1) {
235
0
    bool isHttps = originScheme.EqualsLiteral("https");
236
0
    originPort = isHttps ? NS_HTTPS_DEFAULT_PORT : NS_HTTP_DEFAULT_PORT;
237
0
  }
238
0
239
0
  outKey.Append(originScheme);
240
0
  outKey.Append(':');
241
0
  outKey.Append(originHost);
242
0
  outKey.Append(':');
243
0
  outKey.AppendInt(originPort);
244
0
  outKey.Append(':');
245
0
  outKey.Append(privateBrowsing ? 'P' : '.');
246
0
  outKey.Append(':');
247
0
  nsAutoCString suffix;
248
0
  originAttributes.CreateSuffix(suffix);
249
0
  outKey.Append(suffix);
250
0
}
251
252
int32_t
253
AltSvcMapping::TTL()
254
0
{
255
0
  return mExpiresAt - NowInSeconds();
256
0
}
257
258
void
259
AltSvcMapping::SyncString(const nsCString& str)
260
0
{
261
0
  MOZ_ASSERT(NS_IsMainThread());
262
0
  mStorage->Put(HashKey(), str,
263
0
                mPrivate ? DataStorage_Private : DataStorage_Persistent);
264
0
}
265
266
void
267
AltSvcMapping::Sync()
268
0
{
269
0
  if (!mStorage) {
270
0
    return;
271
0
  }
272
0
  nsCString value;
273
0
  Serialize(value);
274
0
275
0
  if (!NS_IsMainThread()) {
276
0
    nsCOMPtr<nsIRunnable> r;
277
0
    r = NewRunnableMethod<nsCString>("net::AltSvcMapping::SyncString",
278
0
                                     this,
279
0
                                     &AltSvcMapping::SyncString,
280
0
                                     value);
281
0
    NS_DispatchToMainThread(r, NS_DISPATCH_NORMAL);
282
0
    return;
283
0
  }
284
0
285
0
  mStorage->Put(HashKey(), value,
286
0
                mPrivate ? DataStorage_Private : DataStorage_Persistent);
287
0
}
288
289
void
290
AltSvcMapping::SetValidated(bool val)
291
0
{
292
0
  mValidated = val;
293
0
  Sync();
294
0
}
295
296
void
297
AltSvcMapping::SetMixedScheme(bool val)
298
0
{
299
0
  mMixedScheme = val;
300
0
  Sync();
301
0
}
302
303
void
304
AltSvcMapping::SetExpiresAt(int32_t val)
305
0
{
306
0
  mExpiresAt = val;
307
0
  Sync();
308
0
}
309
310
void
311
AltSvcMapping::SetExpired()
312
0
{
313
0
  LOG(("AltSvcMapping SetExpired %p origin %s alternate %s\n", this,
314
0
       mOriginHost.get(), mAlternateHost.get()));
315
0
  mExpiresAt = NowInSeconds() - 1;
316
0
  Sync();
317
0
}
318
319
bool
320
AltSvcMapping::RouteEquals(AltSvcMapping *map)
321
0
{
322
0
  MOZ_ASSERT(map->mHashKey.Equals(mHashKey));
323
0
  return mAlternateHost.Equals(map->mAlternateHost) &&
324
0
    (mAlternatePort == map->mAlternatePort) &&
325
0
    mNPNToken.Equals(map->mNPNToken);
326
0
}
327
328
void
329
AltSvcMapping::GetConnectionInfo(nsHttpConnectionInfo **outCI,
330
                                 nsProxyInfo *pi,
331
                                 const OriginAttributes &originAttributes)
332
0
{
333
0
  RefPtr<nsHttpConnectionInfo> ci =
334
0
    new nsHttpConnectionInfo(mOriginHost, mOriginPort, mNPNToken,
335
0
                             mUsername, pi, originAttributes,
336
0
                             mAlternateHost, mAlternatePort);
337
0
338
0
  // http:// without the mixed-scheme attribute needs to be segmented in the
339
0
  // connection manager connection information hash with this attribute
340
0
  if (!mHttps && !mMixedScheme) {
341
0
    ci->SetInsecureScheme(true);
342
0
  }
343
0
  ci->SetPrivate(mPrivate);
344
0
  ci.forget(outCI);
345
0
}
346
347
void
348
AltSvcMapping::Serialize(nsCString &out)
349
0
{
350
0
  out = mHttps ? NS_LITERAL_CSTRING("https:") : NS_LITERAL_CSTRING("http:");
351
0
  out.Append(mOriginHost);
352
0
  out.Append(':');
353
0
  out.AppendInt(mOriginPort);
354
0
  out.Append(':');
355
0
  out.Append(mAlternateHost);
356
0
  out.Append(':');
357
0
  out.AppendInt(mAlternatePort);
358
0
  out.Append(':');
359
0
  out.Append(mUsername);
360
0
  out.Append(':');
361
0
  out.Append(mPrivate ? 'y' : 'n');
362
0
  out.Append(':');
363
0
  out.AppendInt(mExpiresAt);
364
0
  out.Append(':');
365
0
  out.Append(mNPNToken);
366
0
  out.Append(':');
367
0
  out.Append(mValidated ? 'y' : 'n');
368
0
  out.Append(':');
369
0
  out.AppendInt(mStorageEpoch);
370
0
  out.Append(':');
371
0
  out.Append(mMixedScheme ? 'y' : 'n');
372
0
  out.Append(':');
373
0
  nsAutoCString suffix;
374
0
  mOriginAttributes.CreateSuffix(suffix);
375
0
  out.Append(suffix);
376
0
  out.Append(':');
377
0
}
378
379
AltSvcMapping::AltSvcMapping(DataStorage *storage, int32_t epoch, const nsCString &str)
380
  : mStorage(storage)
381
  , mStorageEpoch(epoch)
382
0
{
383
0
  mValidated = false;
384
0
  nsresult code;
385
0
386
0
  // The the do {} while(0) loop acts like try/catch(e){} with the break in _NS_NEXT_TOKEN
387
0
  do {
388
#ifdef _NS_NEXT_TOKEN
389
COMPILER ERROR
390
#endif
391
0
    #define _NS_NEXT_TOKEN start = idx + 1; idx = str.FindChar(':', start); if (idx < 0) break;
392
0
    int32_t start = 0;
393
0
    int32_t idx;
394
0
    idx = str.FindChar(':', start); if (idx < 0) break;
395
0
    mHttps = Substring(str, start, idx - start).EqualsLiteral("https");
396
0
    _NS_NEXT_TOKEN;
397
0
    mOriginHost = Substring(str, start, idx - start);
398
0
    _NS_NEXT_TOKEN;
399
0
    mOriginPort = nsCString(Substring(str, start, idx - start)).ToInteger(&code);
400
0
    _NS_NEXT_TOKEN;
401
0
    mAlternateHost = Substring(str, start, idx - start);
402
0
    _NS_NEXT_TOKEN;
403
0
    mAlternatePort = nsCString(Substring(str, start, idx - start)).ToInteger(&code);
404
0
    _NS_NEXT_TOKEN;
405
0
    mUsername = Substring(str, start, idx - start);
406
0
    _NS_NEXT_TOKEN;
407
0
    mPrivate = Substring(str, start, idx - start).EqualsLiteral("y");
408
0
    _NS_NEXT_TOKEN;
409
0
    mExpiresAt = nsCString(Substring(str, start, idx - start)).ToInteger(&code);
410
0
    _NS_NEXT_TOKEN;
411
0
    mNPNToken = Substring(str, start, idx - start);
412
0
    _NS_NEXT_TOKEN;
413
0
    mValidated = Substring(str, start, idx - start).EqualsLiteral("y");
414
0
    _NS_NEXT_TOKEN;
415
0
    mStorageEpoch = nsCString(Substring(str, start, idx - start)).ToInteger(&code);
416
0
    _NS_NEXT_TOKEN;
417
0
    mMixedScheme = Substring(str, start, idx - start).EqualsLiteral("y");
418
0
    _NS_NEXT_TOKEN;
419
0
    Unused << mOriginAttributes.PopulateFromSuffix(Substring(str, start, idx - start));
420
0
    #undef _NS_NEXT_TOKEN
421
0
422
0
    MakeHashKey(mHashKey, mHttps ? NS_LITERAL_CSTRING("https") : NS_LITERAL_CSTRING("http"),
423
0
                mOriginHost, mOriginPort, mPrivate, mOriginAttributes);
424
0
  } while (false);
425
0
}
426
427
// This is the asynchronous null transaction used to validate
428
// an alt-svc advertisement only for https://
429
class AltSvcTransaction final : public NullHttpTransaction
430
{
431
public:
432
    AltSvcTransaction(AltSvcMapping *map,
433
                      nsHttpConnectionInfo *ci,
434
                      nsIInterfaceRequestor *callbacks,
435
                      uint32_t caps)
436
    : NullHttpTransaction(ci, callbacks, caps & ~NS_HTTP_ALLOW_KEEPALIVE)
437
    , mMapping(map)
438
    , mRunning(true)
439
    , mTriedToValidate(false)
440
    , mTriedToWrite(false)
441
0
  {
442
0
    LOG(("AltSvcTransaction ctor %p map %p [%s -> %s]",
443
0
         this, map, map->OriginHost().get(), map->AlternateHost().get()));
444
0
    MOZ_ASSERT(mMapping);
445
0
    MOZ_ASSERT(mMapping->HTTPS());
446
0
  }
447
448
  ~AltSvcTransaction() override
449
0
  {
450
0
    LOG(("AltSvcTransaction dtor %p map %p running %d",
451
0
         this, mMapping.get(), mRunning));
452
0
453
0
    if (mRunning) {
454
0
      MaybeValidate(NS_OK);
455
0
    }
456
0
    if (!mMapping->Validated()) {
457
0
      // try again later
458
0
      mMapping->SetExpiresAt(NowInSeconds() + 2);
459
0
    }
460
0
    LOG(("AltSvcTransaction dtor %p map %p validated %d [%s]",
461
0
         this, mMapping.get(), mMapping->Validated(),
462
0
         mMapping->HashKey().get()));
463
0
  }
464
465
private:
466
  // check on alternate route.
467
  // also evaluate 'reasonable assurances' for opportunistic security
468
  void MaybeValidate(nsresult reason)
469
0
  {
470
0
    MOZ_ASSERT(mMapping->HTTPS()); // http:// uses the .wk path
471
0
472
0
    if (mTriedToValidate) {
473
0
      return;
474
0
    }
475
0
    mTriedToValidate = true;
476
0
477
0
    LOG(("AltSvcTransaction::MaybeValidate() %p reason=%" PRIx32 " running=%d conn=%p write=%d",
478
0
         this, static_cast<uint32_t>(reason), mRunning, mConnection.get(), mTriedToWrite));
479
0
480
0
    if (mTriedToWrite && reason == NS_BASE_STREAM_CLOSED) {
481
0
      // The normal course of events is to cause the transaction to fail with CLOSED
482
0
      // on a write - so that's a success that means the HTTP/2 session is setup.
483
0
      reason = NS_OK;
484
0
    }
485
0
486
0
    if (NS_FAILED(reason) || !mRunning || !mConnection) {
487
0
      LOG(("AltSvcTransaction::MaybeValidate %p Failed due to precondition", this));
488
0
      return;
489
0
    }
490
0
491
0
    // insist on >= http/2
492
0
    HttpVersion version = mConnection->Version();
493
0
    LOG(("AltSvcTransaction::MaybeValidate() %p version %d\n", this, static_cast<int32_t>(version)));
494
0
    if (version != HttpVersion::v2_0) {
495
0
      LOG(("AltSvcTransaction::MaybeValidate %p Failed due to protocol version", this));
496
0
      return;
497
0
    }
498
0
499
0
    nsCOMPtr<nsISupports> secInfo;
500
0
    mConnection->GetSecurityInfo(getter_AddRefs(secInfo));
501
0
    nsCOMPtr<nsISSLSocketControl> socketControl = do_QueryInterface(secInfo);
502
0
503
0
    LOG(("AltSvcTransaction::MaybeValidate() %p socketControl=%p\n",
504
0
         this, socketControl.get()));
505
0
506
0
    if (socketControl->GetFailedVerification()) {
507
0
      LOG(("AltSvcTransaction::MaybeValidate() %p "
508
0
           "not validated due to auth error", this));
509
0
      return;
510
0
    }
511
0
512
0
    LOG(("AltSvcTransaction::MaybeValidate() %p "
513
0
         "validating alternate service with successful auth check", this));
514
0
    mMapping->SetValidated(true);
515
0
  }
516
517
public:
518
  void Close(nsresult reason) override
519
0
  {
520
0
    LOG(("AltSvcTransaction::Close() %p reason=%" PRIx32 " running %d",
521
0
         this, static_cast<uint32_t>(reason), mRunning));
522
0
523
0
    MaybeValidate(reason);
524
0
    if (!mMapping->Validated() && mConnection) {
525
0
      mConnection->DontReuse();
526
0
    }
527
0
    NullHttpTransaction::Close(reason);
528
0
  }
529
530
  nsresult ReadSegments(nsAHttpSegmentReader *reader,
531
                        uint32_t count, uint32_t *countRead) override
532
0
  {
533
0
    LOG(("AltSvcTransaction::ReadSegements() %p\n", this));
534
0
    mTriedToWrite = true;
535
0
    return NullHttpTransaction::ReadSegments(reader, count, countRead);
536
0
  }
537
538
private:
539
  RefPtr<AltSvcMapping>   mMapping;
540
  uint32_t                mRunning : 1;
541
  uint32_t                mTriedToValidate : 1;
542
  uint32_t                mTriedToWrite : 1;
543
};
544
545
class WellKnownChecker
546
{
547
public:
548
  WellKnownChecker(nsIURI *uri, const nsCString &origin, uint32_t caps, nsHttpConnectionInfo *ci, AltSvcMapping *mapping)
549
    : mWaiting(2) // waiting for 2 channels (default and alternate) to complete
550
    , mOrigin(origin)
551
    , mAlternatePort(ci->RoutedPort())
552
    , mMapping(mapping)
553
    , mCI(ci)
554
    , mURI(uri)
555
    , mCaps(caps)
556
0
  {
557
0
    LOG(("WellKnownChecker ctor %p\n", this));
558
0
    MOZ_ASSERT(!mMapping->HTTPS());
559
0
  }
560
561
  nsresult Start()
562
0
  {
563
0
    LOG(("WellKnownChecker::Start %p\n", this));
564
0
    nsCOMPtr<nsILoadInfo> loadInfo = new LoadInfo(nsContentUtils::GetSystemPrincipal(),
565
0
                                                  nullptr, nullptr,
566
0
                                                  nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
567
0
                                                  nsIContentPolicy::TYPE_OTHER);
568
0
    loadInfo->SetOriginAttributes(mCI->GetOriginAttributes());
569
0
570
0
    RefPtr<nsHttpChannel> chan = new nsHttpChannel();
571
0
    nsresult rv;
572
0
573
0
    mTransactionAlternate = new TransactionObserver(chan, this);
574
0
    RefPtr<nsHttpConnectionInfo> newCI = mCI->Clone();
575
0
    rv = MakeChannel(chan, mTransactionAlternate, newCI, mURI, mCaps, loadInfo);
576
0
    if (NS_FAILED(rv)) {
577
0
      return rv;
578
0
    }
579
0
    chan = new nsHttpChannel();
580
0
    mTransactionOrigin = new TransactionObserver(chan, this);
581
0
    newCI = nullptr;
582
0
    return MakeChannel(chan, mTransactionOrigin, newCI, mURI, mCaps, loadInfo);
583
0
  }
584
585
  void Done(TransactionObserver *finished)
586
0
  {
587
0
    MOZ_ASSERT(NS_IsMainThread());
588
0
    LOG(("WellKnownChecker::Done %p waiting for %d\n", this, mWaiting));
589
0
590
0
    mWaiting--; // another channel is complete
591
0
    if (!mWaiting) { // there are all complete!
592
0
      nsAutoCString mAlternateCT, mOriginCT;
593
0
      mTransactionOrigin->mChannel->GetContentType(mOriginCT);
594
0
      mTransactionAlternate->mChannel->GetContentType(mAlternateCT);
595
0
      nsCOMPtr<nsIWellKnownOpportunisticUtils> uu = do_CreateInstance(NS_WELLKNOWNOPPORTUNISTICUTILS_CONTRACTID);
596
0
      bool accepted = false;
597
0
598
0
      if (!mTransactionOrigin->mStatusOK) {
599
0
        LOG(("WellKnownChecker::Done %p origin was not 200 response code\n", this));
600
0
      } else if (!mTransactionAlternate->mAuthOK) {
601
0
        LOG(("WellKnownChecker::Done %p alternate was not TLS authenticated\n", this));
602
0
      } else if (!mTransactionAlternate->mStatusOK) {
603
0
        LOG(("WellKnownChecker::Done %p alternate was not 200 response code\n", this));
604
0
      } else if (!mTransactionAlternate->mVersionOK) {
605
0
        LOG(("WellKnownChecker::Done %p alternate was not at least h2\n", this));
606
0
      } else if (!mTransactionAlternate->mWKResponse.Equals(mTransactionOrigin->mWKResponse)) {
607
0
        LOG(("WellKnownChecker::Done %p alternate and origin "
608
0
             ".wk representations don't match\norigin: %s\alternate:%s\n", this,
609
0
             mTransactionOrigin->mWKResponse.get(),
610
0
             mTransactionAlternate->mWKResponse.get()));
611
0
      } else if (!mAlternateCT.Equals(mOriginCT)) {
612
0
        LOG(("WellKnownChecker::Done %p alternate and origin content types dont match\n", this));
613
0
      } else if (!mAlternateCT.EqualsLiteral("application/json")) {
614
0
        LOG(("WellKnownChecker::Done %p .wk content type is %s\n", this, mAlternateCT.get()));
615
0
      } else if (!uu) {
616
0
        LOG(("WellKnownChecker::Done %p json parser service unavailable\n", this));
617
0
      } else {
618
0
        accepted = true;
619
0
      }
620
0
621
0
      if (accepted) {
622
0
        MOZ_ASSERT(!mMapping->HTTPS()); // https:// does not use .wk
623
0
624
0
        nsresult rv = uu->Verify(mTransactionAlternate->mWKResponse, mOrigin, mAlternatePort);
625
0
        if (NS_SUCCEEDED(rv)) {
626
0
          bool validWK = false;
627
0
          bool mixedScheme = false;
628
0
          int32_t lifetime = 0;
629
0
          Unused << uu->GetValid(&validWK);
630
0
          Unused << uu->GetLifetime(&lifetime);
631
0
          Unused << uu->GetMixed(&mixedScheme);
632
0
          if (!validWK) {
633
0
            LOG(("WellKnownChecker::Done %p json parser declares invalid\n%s\n", this, mTransactionAlternate->mWKResponse.get()));
634
0
            accepted = false;
635
0
          }
636
0
          if (accepted && (lifetime > 0)) {
637
0
            if (mMapping->TTL() > lifetime) {
638
0
              LOG(("WellKnownChecker::Done %p atl-svc lifetime reduced by .wk\n", this));
639
0
              mMapping->SetExpiresAt(NowInSeconds() + lifetime);
640
0
            } else {
641
0
              LOG(("WellKnownChecker::Done %p .wk lifetime exceeded alt-svc ma so ignored\n", this));
642
0
            }
643
0
          }
644
0
          if (accepted && mixedScheme) {
645
0
            mMapping->SetMixedScheme(true);
646
0
            LOG(("WellKnownChecker::Done %p atl-svc .wk allows mixed scheme\n", this));
647
0
          }
648
0
        } else {
649
0
          LOG(("WellKnownChecker::Done %p .wk jason eval failed to run\n", this));
650
0
          accepted = false;
651
0
        }
652
0
      }
653
0
654
0
      MOZ_ASSERT(!mMapping->Validated());
655
0
      if (accepted) {
656
0
        LOG(("WellKnownChecker::Done %p Alternate for %s ACCEPTED\n", this, mOrigin.get()));
657
0
        mMapping->SetValidated(true);
658
0
      } else {
659
0
        LOG(("WellKnownChecker::Done %p Alternate for %s FAILED\n", this, mOrigin.get()));
660
0
        // try again soon
661
0
        mMapping->SetExpiresAt(NowInSeconds() + 2);
662
0
      }
663
0
664
0
      delete this;
665
0
    }
666
0
  }
667
668
  ~WellKnownChecker()
669
0
  {
670
0
    LOG(("WellKnownChecker dtor %p\n", this));
671
0
  }
672
673
private:
674
  nsresult
675
  MakeChannel(nsHttpChannel *chan, TransactionObserver *obs, nsHttpConnectionInfo *ci,
676
              nsIURI *uri, uint32_t caps, nsILoadInfo *loadInfo)
677
0
  {
678
0
    uint64_t channelId;
679
0
    nsLoadFlags flags;
680
0
    if (NS_FAILED(gHttpHandler->NewChannelId(channelId)) ||
681
0
        NS_FAILED(chan->Init(uri, caps, nullptr, 0, nullptr, channelId)) ||
682
0
        NS_FAILED(chan->SetAllowAltSvc(false)) ||
683
0
        NS_FAILED(chan->SetRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_ERROR)) ||
684
0
        NS_FAILED(chan->SetLoadInfo(loadInfo)) ||
685
0
        NS_FAILED(chan->GetLoadFlags(&flags))) {
686
0
      return NS_ERROR_FAILURE;
687
0
    }
688
0
    flags |= HttpBaseChannel::LOAD_BYPASS_CACHE;
689
0
    if (NS_FAILED(chan->SetLoadFlags(flags))) {
690
0
      return NS_ERROR_FAILURE;
691
0
    }
692
0
    chan->SetTransactionObserver(obs);
693
0
    chan->SetConnectionInfo(ci);
694
0
    return chan->AsyncOpen2(obs);
695
0
  }
696
697
  RefPtr<TransactionObserver>  mTransactionAlternate;
698
  RefPtr<TransactionObserver>  mTransactionOrigin;
699
  uint32_t                     mWaiting; // semaphore
700
  nsCString                    mOrigin;
701
  int32_t                      mAlternatePort;
702
  RefPtr<AltSvcMapping>        mMapping;
703
  RefPtr<nsHttpConnectionInfo> mCI;
704
  nsCOMPtr<nsIURI>             mURI;
705
  uint32_t                     mCaps;
706
};
707
708
NS_IMPL_ISUPPORTS(TransactionObserver, nsIStreamListener)
709
710
TransactionObserver::TransactionObserver(nsHttpChannel *channel, WellKnownChecker *checker)
711
  : mChannel(channel)
712
  , mChecker(checker)
713
  , mRanOnce(false)
714
  , mAuthOK(false)
715
  , mVersionOK(false)
716
  , mStatusOK(false)
717
0
{
718
0
  LOG(("TransactionObserver ctor %p channel %p checker %p\n", this, channel, checker));
719
0
  mChannelRef = do_QueryInterface((nsIHttpChannel *)channel);
720
0
}
721
722
void
723
TransactionObserver::Complete(nsHttpTransaction *aTrans, nsresult reason)
724
0
{
725
0
  // socket thread
726
0
  MOZ_ASSERT(!NS_IsMainThread());
727
0
  if (mRanOnce) {
728
0
    return;
729
0
  }
730
0
  mRanOnce = true;
731
0
732
0
  RefPtr<nsAHttpConnection> conn = aTrans->GetConnectionReference();
733
0
  LOG(("TransactionObserver::Complete %p aTrans %p reason %" PRIx32 " conn %p\n",
734
0
       this, aTrans, static_cast<uint32_t>(reason), conn.get()));
735
0
  if (!conn) {
736
0
    return;
737
0
  }
738
0
  HttpVersion version = conn->Version();
739
0
  mVersionOK = (((reason == NS_BASE_STREAM_CLOSED) || (reason == NS_OK)) &&
740
0
                conn->Version() == HttpVersion::v2_0);
741
0
742
0
  nsCOMPtr<nsISupports> secInfo;
743
0
  conn->GetSecurityInfo(getter_AddRefs(secInfo));
744
0
  nsCOMPtr<nsISSLSocketControl> socketControl = do_QueryInterface(secInfo);
745
0
  LOG(("TransactionObserver::Complete version %u socketControl %p\n",
746
0
       static_cast<int32_t>(version), socketControl.get()));
747
0
  if (!socketControl) {
748
0
    return;
749
0
  }
750
0
751
0
  mAuthOK = !socketControl->GetFailedVerification();
752
0
  LOG(("TransactionObserve::Complete %p trans %p authOK %d versionOK %d\n",
753
0
       this, aTrans, mAuthOK, mVersionOK));
754
0
}
755
756
0
#define MAX_WK 32768
757
758
NS_IMETHODIMP
759
TransactionObserver::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
760
0
{
761
0
  MOZ_ASSERT(NS_IsMainThread());
762
0
  // only consider the first 32KB.. because really.
763
0
  mWKResponse.SetCapacity(MAX_WK);
764
0
  return NS_OK;
765
0
}
766
767
NS_IMETHODIMP
768
TransactionObserver::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
769
                                     nsIInputStream *aStream, uint64_t aOffset, uint32_t aCount)
770
0
{
771
0
  MOZ_ASSERT(NS_IsMainThread());
772
0
  uint32_t oldLen = mWKResponse.Length();
773
0
  uint64_t newLen = aCount + oldLen;
774
0
  if (newLen < MAX_WK) {
775
0
    nsresult rv;
776
0
    auto handle = mWKResponse.BulkWrite(newLen, oldLen, false, rv);
777
0
    if (NS_FAILED(rv)) {
778
0
      return rv;
779
0
    }
780
0
    uint32_t amtRead;
781
0
    if (NS_SUCCEEDED(aStream->Read(handle.Elements() + oldLen, aCount, &amtRead))) {
782
0
      MOZ_ASSERT(oldLen + amtRead <= newLen);
783
0
      handle.Finish(oldLen + amtRead, false);
784
0
      LOG(("TransactionObserver onDataAvailable %p read %d of .wk [%d]\n",
785
0
           this, amtRead, mWKResponse.Length()));
786
0
    } else {
787
0
      LOG(("TransactionObserver onDataAvailable %p read error\n", this));
788
0
    }
789
0
  }
790
0
  return NS_OK;
791
0
}
792
793
NS_IMETHODIMP
794
TransactionObserver::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, nsresult code)
795
0
{
796
0
  MOZ_ASSERT(NS_IsMainThread());
797
0
  LOG(("TransactionObserver onStopRequest %p code %" PRIx32 "\n",
798
0
       this, static_cast<uint32_t>(code)));
799
0
  if (NS_SUCCEEDED(code)) {
800
0
    nsHttpResponseHead *hdrs = mChannel->GetResponseHead();
801
0
    LOG(("TransactionObserver onStopRequest %p http resp %d\n",
802
0
         this, hdrs ? hdrs->Status() : -1));
803
0
    mStatusOK = hdrs && (hdrs->Status() == 200);
804
0
  }
805
0
  if (mChecker) {
806
0
    mChecker->Done(this);
807
0
  }
808
0
  return NS_OK;
809
0
}
810
811
already_AddRefed<AltSvcMapping>
812
AltSvcCache::LookupMapping(const nsCString &key, bool privateBrowsing)
813
0
{
814
0
  LOG(("AltSvcCache::LookupMapping %p %s\n", this, key.get()));
815
0
  if (!mStorage) {
816
0
    LOG(("AltSvcCache::LookupMapping %p no backing store\n", this));
817
0
    return nullptr;
818
0
  }
819
0
  nsCString val(mStorage->Get(key,
820
0
                              privateBrowsing ? DataStorage_Private : DataStorage_Persistent));
821
0
  if (val.IsEmpty()) {
822
0
    LOG(("AltSvcCache::LookupMapping %p MISS\n", this));
823
0
    return nullptr;
824
0
  }
825
0
  RefPtr<AltSvcMapping> rv = new AltSvcMapping(mStorage, mStorageEpoch, val);
826
0
  if (!rv->Validated() && (rv->StorageEpoch() != mStorageEpoch)) {
827
0
    // this was an in progress validation abandoned in a different session
828
0
    // rare edge case will not detect session change - that's ok as only impact
829
0
    // will be loss of alt-svc to this origin for this session.
830
0
    LOG(("AltSvcCache::LookupMapping %p invalid hit - MISS\n", this));
831
0
    mStorage->Remove(key,
832
0
                     rv->Private() ? DataStorage_Private : DataStorage_Persistent);
833
0
    return nullptr;
834
0
  }
835
0
836
0
  if (rv->TTL() <= 0) {
837
0
    LOG(("AltSvcCache::LookupMapping %p expired hit - MISS\n", this));
838
0
    mStorage->Remove(key,
839
0
                     rv->Private() ? DataStorage_Private : DataStorage_Persistent);
840
0
    return nullptr;
841
0
  }
842
0
843
0
  MOZ_ASSERT(rv->Private() == privateBrowsing);
844
0
  LOG(("AltSvcCache::LookupMapping %p HIT %p\n", this, rv.get()));
845
0
  return rv.forget();
846
0
}
847
848
void
849
AltSvcCache::UpdateAltServiceMapping(AltSvcMapping *map, nsProxyInfo *pi,
850
                                     nsIInterfaceRequestor *aCallbacks,
851
                                     uint32_t caps,
852
                                     const OriginAttributes &originAttributes)
853
0
{
854
0
  MOZ_ASSERT(NS_IsMainThread());
855
0
  if (!mStorage) {
856
0
    return;
857
0
  }
858
0
  RefPtr<AltSvcMapping> existing = LookupMapping(map->HashKey(), map->Private());
859
0
  LOG(("AltSvcCache::UpdateAltServiceMapping %p map %p existing %p %s validated=%d",
860
0
       this, map, existing.get(), map->AlternateHost().get(),
861
0
       existing ? existing->Validated() : 0));
862
0
863
0
  if (existing && existing->Validated()) {
864
0
    if (existing->RouteEquals(map)){
865
0
      // update expires in storage
866
0
      // if this is http:// then a ttl can only be extended via .wk, so ignore this
867
0
      // header path unless it is making things shorter
868
0
      if (existing->HTTPS()) {
869
0
        LOG(("AltSvcCache::UpdateAltServiceMapping %p map %p updates ttl of %p\n",
870
0
             this, map, existing.get()));
871
0
        existing->SetExpiresAt(map->GetExpiresAt());
872
0
      } else {
873
0
        if (map->GetExpiresAt() < existing->GetExpiresAt()) {
874
0
          LOG(("AltSvcCache::UpdateAltServiceMapping %p map %p reduces ttl of %p\n",
875
0
               this, map, existing.get()));
876
0
          existing->SetExpiresAt(map->GetExpiresAt());
877
0
        } else {
878
0
          LOG(("AltSvcCache::UpdateAltServiceMapping %p map %p tries to extend %p but"
879
0
               " cannot as without .wk\n",
880
0
               this, map, existing.get()));
881
0
        }
882
0
      }
883
0
      return;
884
0
    }
885
0
886
0
    // new alternate. remove old entry and start new validation
887
0
    LOG(("AltSvcCache::UpdateAltServiceMapping %p map %p overwrites %p\n",
888
0
         this, map, existing.get()));
889
0
    existing = nullptr;
890
0
    mStorage->Remove(map->HashKey(),
891
0
                     map->Private() ? DataStorage_Private : DataStorage_Persistent);
892
0
  }
893
0
894
0
  if (existing && !existing->Validated()) {
895
0
    LOG(("AltSvcCache::UpdateAltServiceMapping %p map %p ignored because %p "
896
0
         "still in progress\n", this, map, existing.get()));
897
0
    return;
898
0
  }
899
0
900
0
  // start new validation
901
0
  MOZ_ASSERT(!map->Validated());
902
0
  map->Sync();
903
0
904
0
  RefPtr<nsHttpConnectionInfo> ci;
905
0
  map->GetConnectionInfo(getter_AddRefs(ci), pi, originAttributes);
906
0
  caps |= ci->GetAnonymous() ? NS_HTTP_LOAD_ANONYMOUS : 0;
907
0
  caps |= NS_HTTP_ERROR_SOFTLY;
908
0
909
0
  if (map->HTTPS()) {
910
0
    LOG(("AltSvcCache::UpdateAltServiceMapping %p validation via "
911
0
         "speculative connect started\n", this));
912
0
    // for https resources we only establish a connection
913
0
    nsCOMPtr<nsIInterfaceRequestor> callbacks = new AltSvcOverride(aCallbacks);
914
0
    RefPtr<AltSvcTransaction> nullTransaction =
915
0
      new AltSvcTransaction(map, ci, aCallbacks, caps);
916
0
    nsresult rv = gHttpHandler->ConnMgr()->SpeculativeConnect(ci, callbacks, caps, nullTransaction);
917
0
    if (NS_FAILED(rv)) {
918
0
      LOG(("AltSvcCache::UpdateAltServiceMapping %p "
919
0
           "speculative connect failed with code %08x\n", this,
920
0
           static_cast<uint32_t>(rv)));
921
0
    }
922
0
  } else {
923
0
    // for http:// resources we fetch .well-known too
924
0
    nsAutoCString origin (NS_LITERAL_CSTRING("http://") + map->OriginHost());
925
0
    if (map->OriginPort() != NS_HTTP_DEFAULT_PORT) {
926
0
      origin.Append(':');
927
0
      origin.AppendInt(map->OriginPort());
928
0
    }
929
0
930
0
    nsCOMPtr<nsIURI> wellKnown;
931
0
    nsAutoCString uri(origin);
932
0
    uri.AppendLiteral("/.well-known/http-opportunistic");
933
0
    NS_NewURI(getter_AddRefs(wellKnown), uri);
934
0
935
0
    auto *checker = new WellKnownChecker(wellKnown, origin, caps, ci, map);
936
0
    if (NS_FAILED(checker->Start())) {
937
0
      LOG(("AltSvcCache::UpdateAltServiceMapping %p .wk checker failed to start\n", this));
938
0
      map->SetExpired();
939
0
      delete checker;
940
0
      checker = nullptr;
941
0
    } else {
942
0
      // object deletes itself when done if started
943
0
      LOG(("AltSvcCache::UpdateAltServiceMapping %p .wk checker started %p\n", this, checker));
944
0
    }
945
0
  }
946
0
}
947
948
already_AddRefed<AltSvcMapping>
949
AltSvcCache::GetAltServiceMapping(const nsACString &scheme, const nsACString &host,
950
                                  int32_t port, bool privateBrowsing,
951
                                  const OriginAttributes &originAttributes)
952
0
{
953
0
  bool isHTTPS;
954
0
  MOZ_ASSERT(NS_IsMainThread());
955
0
  if (!mStorage) {
956
0
    // DataStorage gives synchronous access to a memory based hash table
957
0
    // that is backed by disk where those writes are done asynchronously
958
0
    // on another thread
959
0
    mStorage = DataStorage::Get(DataStorageClass::AlternateServices);
960
0
    if (mStorage) {
961
0
      bool storageWillPersist = false;
962
0
      if (NS_FAILED(mStorage->Init(storageWillPersist))) {
963
0
        mStorage = nullptr;
964
0
      }
965
0
    }
966
0
    if (!mStorage) {
967
0
      LOG(("AltSvcCache::GetAltServiceMapping WARN NO STORAGE\n"));
968
0
    }
969
0
    mStorageEpoch = NowInSeconds();
970
0
  }
971
0
972
0
  if (NS_FAILED(SchemeIsHTTPS(scheme, isHTTPS))) {
973
0
    return nullptr;
974
0
  }
975
0
  if (!gHttpHandler->AllowAltSvc()) {
976
0
    return nullptr;
977
0
  }
978
0
  if (!gHttpHandler->AllowAltSvcOE() && !isHTTPS) {
979
0
    return nullptr;
980
0
  }
981
0
982
0
  nsAutoCString key;
983
0
  AltSvcMapping::MakeHashKey(key, scheme, host, port, privateBrowsing, originAttributes);
984
0
  RefPtr<AltSvcMapping> existing = LookupMapping(key, privateBrowsing);
985
0
  LOG(("AltSvcCache::GetAltServiceMapping %p key=%s "
986
0
       "existing=%p validated=%d ttl=%d",
987
0
       this, key.get(), existing.get(), existing ? existing->Validated() : 0,
988
0
       existing ? existing->TTL() : 0));
989
0
  if (existing && !existing->Validated()) {
990
0
    existing = nullptr;
991
0
  }
992
0
  return existing.forget();
993
0
}
994
995
class ProxyClearHostMapping : public Runnable {
996
public:
997
  explicit ProxyClearHostMapping(const nsACString& host,
998
                                 int32_t port,
999
                                 const OriginAttributes& originAttributes)
1000
    : Runnable("net::ProxyClearHostMapping")
1001
    , mHost(host)
1002
    , mPort(port)
1003
    , mOriginAttributes(originAttributes)
1004
0
  {
1005
0
  }
1006
1007
  NS_IMETHOD Run() override
1008
0
  {
1009
0
    MOZ_ASSERT(NS_IsMainThread());
1010
0
    gHttpHandler->ConnMgr()->ClearHostMapping(mHost, mPort, mOriginAttributes);
1011
0
    return NS_OK;
1012
0
    }
1013
private:
1014
    nsCString mHost;
1015
    int32_t mPort;
1016
    OriginAttributes mOriginAttributes;
1017
};
1018
1019
void
1020
AltSvcCache::ClearHostMapping(const nsACString &host, int32_t port,
1021
                              const OriginAttributes &originAttributes)
1022
0
{
1023
0
  if (!NS_IsMainThread()) {
1024
0
    nsCOMPtr<nsIRunnable> event = new ProxyClearHostMapping(host, port, originAttributes);
1025
0
    if (event) {
1026
0
      NS_DispatchToMainThread(event);
1027
0
    }
1028
0
    return;
1029
0
  }
1030
0
  nsAutoCString key;
1031
0
  AltSvcMapping::MakeHashKey(key, NS_LITERAL_CSTRING("http"), host, port, true,
1032
0
                             originAttributes);
1033
0
  RefPtr<AltSvcMapping> existing = LookupMapping(key, true);
1034
0
  if (existing) {
1035
0
    existing->SetExpired();
1036
0
  }
1037
0
1038
0
  AltSvcMapping::MakeHashKey(key, NS_LITERAL_CSTRING("https"), host, port, true,
1039
0
                             originAttributes);
1040
0
  existing = LookupMapping(key, true);
1041
0
  if (existing) {
1042
0
    existing->SetExpired();
1043
0
  }
1044
0
1045
0
  AltSvcMapping::MakeHashKey(key, NS_LITERAL_CSTRING("http"), host, port, false,
1046
0
                             originAttributes);
1047
0
  existing = LookupMapping(key, false);
1048
0
  if (existing) {
1049
0
    existing->SetExpired();
1050
0
  }
1051
0
1052
0
  AltSvcMapping::MakeHashKey(key, NS_LITERAL_CSTRING("https"), host, port, false,
1053
0
                             originAttributes);
1054
0
  existing = LookupMapping(key, false);
1055
0
  if (existing) {
1056
0
    existing->SetExpired();
1057
0
  }
1058
0
}
1059
1060
void
1061
AltSvcCache::ClearHostMapping(nsHttpConnectionInfo *ci)
1062
0
{
1063
0
  if (!ci->GetOrigin().IsEmpty()) {
1064
0
    ClearHostMapping(ci->GetOrigin(), ci->OriginPort(), ci->GetOriginAttributes());
1065
0
  }
1066
0
}
1067
1068
void
1069
AltSvcCache::ClearAltServiceMappings()
1070
0
{
1071
0
    MOZ_ASSERT(NS_IsMainThread());
1072
0
    if (mStorage) {
1073
0
      mStorage->Clear();
1074
0
    }
1075
0
}
1076
1077
NS_IMETHODIMP
1078
AltSvcOverride::GetInterface(const nsIID &iid, void **result)
1079
0
{
1080
0
  if (NS_SUCCEEDED(QueryInterface(iid, result)) && *result) {
1081
0
    return NS_OK;
1082
0
  }
1083
0
  return mCallbacks->GetInterface(iid, result);
1084
0
}
1085
1086
NS_IMETHODIMP
1087
AltSvcOverride::GetIgnoreIdle(bool *ignoreIdle)
1088
0
{
1089
0
  *ignoreIdle = true;
1090
0
  return NS_OK;
1091
0
}
1092
1093
NS_IMETHODIMP
1094
AltSvcOverride::GetParallelSpeculativeConnectLimit(
1095
  uint32_t *parallelSpeculativeConnectLimit)
1096
0
{
1097
0
  *parallelSpeculativeConnectLimit = 32;
1098
0
  return NS_OK;
1099
0
}
1100
1101
NS_IMETHODIMP
1102
AltSvcOverride::GetIsFromPredictor(bool *isFromPredictor)
1103
0
{
1104
0
  *isFromPredictor = false;
1105
0
  return NS_OK;
1106
0
}
1107
1108
NS_IMETHODIMP
1109
AltSvcOverride::GetAllow1918(bool *allow)
1110
0
{
1111
0
  // normally we don't do speculative connects to 1918.. and we use
1112
0
  // speculative connects for the mapping validation, so override
1113
0
  // that default here for alt-svc
1114
0
  *allow = true;
1115
0
  return NS_OK;
1116
0
}
1117
1118
NS_IMPL_ISUPPORTS(AltSvcOverride, nsIInterfaceRequestor, nsISpeculativeConnectionOverrider)
1119
1120
} // namespace net
1121
} // namespace mozilla