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