Backed out changeset af645c9220f1 (bug 1835805) for causing bustage on DNSPacket...
[gecko.git] / netwerk / protocol / http / TRRServiceChannel.cpp
blob033c0ae26ed6042a908c3ee8f9d2429c48dc750c
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "TRRServiceChannel.h"
10 #include "HttpLog.h"
11 #include "AltServiceChild.h"
12 #include "mozilla/ScopeExit.h"
13 #include "mozilla/StaticPrefs_network.h"
14 #include "mozilla/Unused.h"
15 #include "nsDNSPrefetch.h"
16 #include "nsEscape.h"
17 #include "nsHttpTransaction.h"
18 #include "nsICancelable.h"
19 #include "nsICachingChannel.h"
20 #include "nsIHttpPushListener.h"
21 #include "nsIProtocolProxyService2.h"
22 #include "nsIOService.h"
23 #include "nsISeekableStream.h"
24 #include "nsURLHelper.h"
25 #include "ProxyConfigLookup.h"
26 #include "TRRLoadInfo.h"
27 #include "ReferrerInfo.h"
28 #include "TRR.h"
29 #include "TRRService.h"
31 namespace mozilla::net {
33 NS_IMPL_ADDREF(TRRServiceChannel)
35 // Because nsSupportsWeakReference isn't thread-safe we must ensure that
36 // TRRServiceChannel is destroyed on the target thread. Any Release() called
37 // on a different thread is dispatched to the target thread.
38 bool TRRServiceChannel::DispatchRelease() {
39 if (mCurrentEventTarget->IsOnCurrentThread()) {
40 return false;
43 mCurrentEventTarget->Dispatch(
44 NewNonOwningRunnableMethod("net::TRRServiceChannel::Release", this,
45 &TRRServiceChannel::Release),
46 NS_DISPATCH_NORMAL);
48 return true;
51 NS_IMETHODIMP_(MozExternalRefCountType)
52 TRRServiceChannel::Release() {
53 nsrefcnt count = mRefCnt - 1;
54 if (DispatchRelease()) {
55 // Redispatched to the target thread.
56 return count;
59 MOZ_ASSERT(0 != mRefCnt, "dup release");
60 count = --mRefCnt;
61 NS_LOG_RELEASE(this, count, "TRRServiceChannel");
63 if (0 == count) {
64 mRefCnt = 1;
65 delete (this);
66 return 0;
69 return count;
72 NS_INTERFACE_MAP_BEGIN(TRRServiceChannel)
73 NS_INTERFACE_MAP_ENTRY(nsIRequest)
74 NS_INTERFACE_MAP_ENTRY(nsIChannel)
75 NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
76 NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
77 NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
78 NS_INTERFACE_MAP_ENTRY(nsIClassOfService)
79 NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
80 NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyCallback)
81 NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
82 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
83 NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
84 NS_INTERFACE_MAP_ENTRY(nsIDNSListener)
85 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
86 NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
87 NS_INTERFACE_MAP_ENTRY_CONCRETE(TRRServiceChannel)
88 NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
90 TRRServiceChannel::TRRServiceChannel()
91 : HttpAsyncAborter<TRRServiceChannel>(this),
92 mProxyRequest(nullptr, "TRRServiceChannel::mProxyRequest"),
93 mCurrentEventTarget(GetCurrentSerialEventTarget()) {
94 LOG(("TRRServiceChannel ctor [this=%p]\n", this));
97 TRRServiceChannel::~TRRServiceChannel() {
98 LOG(("TRRServiceChannel dtor [this=%p]\n", this));
101 NS_IMETHODIMP TRRServiceChannel::SetCanceledReason(const nsACString& aReason) {
102 return SetCanceledReasonImpl(aReason);
105 NS_IMETHODIMP TRRServiceChannel::GetCanceledReason(nsACString& aReason) {
106 return GetCanceledReasonImpl(aReason);
109 NS_IMETHODIMP
110 TRRServiceChannel::CancelWithReason(nsresult aStatus,
111 const nsACString& aReason) {
112 return CancelWithReasonImpl(aStatus, aReason);
115 NS_IMETHODIMP
116 TRRServiceChannel::Cancel(nsresult status) {
117 LOG(("TRRServiceChannel::Cancel [this=%p status=%" PRIx32 "]\n", this,
118 static_cast<uint32_t>(status)));
119 if (mCanceled) {
120 LOG((" ignoring; already canceled\n"));
121 return NS_OK;
124 mCanceled = true;
125 mStatus = status;
127 nsCOMPtr<nsICancelable> proxyRequest;
129 auto req = mProxyRequest.Lock();
130 proxyRequest.swap(*req);
133 if (proxyRequest) {
134 NS_DispatchToMainThread(
135 NS_NewRunnableFunction(
136 "CancelProxyRequest",
137 [proxyRequest, status]() { proxyRequest->Cancel(status); }),
138 NS_DISPATCH_NORMAL);
141 CancelNetworkRequest(status);
142 return NS_OK;
145 void TRRServiceChannel::CancelNetworkRequest(nsresult aStatus) {
146 if (mTransaction) {
147 nsresult rv = gHttpHandler->CancelTransaction(mTransaction, aStatus);
148 if (NS_FAILED(rv)) {
149 LOG(("failed to cancel the transaction\n"));
152 if (mTransactionPump) mTransactionPump->Cancel(aStatus);
155 NS_IMETHODIMP
156 TRRServiceChannel::Suspend() {
157 LOG(("TRRServiceChannel::SuspendInternal [this=%p]\n", this));
159 if (mTransactionPump) {
160 return mTransactionPump->Suspend();
163 return NS_OK;
166 NS_IMETHODIMP
167 TRRServiceChannel::Resume() {
168 LOG(("TRRServiceChannel::Resume [this=%p]\n", this));
170 if (mTransactionPump) {
171 return mTransactionPump->Resume();
174 return NS_OK;
177 NS_IMETHODIMP
178 TRRServiceChannel::GetSecurityInfo(nsITransportSecurityInfo** securityInfo) {
179 NS_ENSURE_ARG_POINTER(securityInfo);
180 *securityInfo = do_AddRef(mSecurityInfo).take();
181 return NS_OK;
184 NS_IMETHODIMP
185 TRRServiceChannel::AsyncOpen(nsIStreamListener* aListener) {
186 NS_ENSURE_ARG_POINTER(aListener);
187 NS_ENSURE_TRUE(!LoadIsPending(), NS_ERROR_IN_PROGRESS);
188 NS_ENSURE_TRUE(!LoadWasOpened(), NS_ERROR_ALREADY_OPENED);
190 if (mCanceled) {
191 ReleaseListeners();
192 return mStatus;
195 // HttpBaseChannel::MaybeWaitForUploadStreamNormalization can only be used on
196 // main thread, so we can only return an error here.
197 #ifdef NIGHTLY_BUILD
198 MOZ_ASSERT(!LoadPendingUploadStreamNormalization());
199 #endif
200 if (LoadPendingUploadStreamNormalization()) {
201 return NS_ERROR_FAILURE;
204 if (!gHttpHandler->Active()) {
205 LOG((" after HTTP shutdown..."));
206 ReleaseListeners();
207 return NS_ERROR_NOT_AVAILABLE;
210 nsresult rv = NS_CheckPortSafety(mURI);
211 if (NS_FAILED(rv)) {
212 ReleaseListeners();
213 return rv;
216 StoreIsPending(true);
217 StoreWasOpened(true);
219 mListener = aListener;
221 mAsyncOpenTime = TimeStamp::Now();
223 rv = MaybeResolveProxyAndBeginConnect();
224 if (NS_FAILED(rv)) {
225 Unused << AsyncAbort(rv);
228 return NS_OK;
231 nsresult TRRServiceChannel::MaybeResolveProxyAndBeginConnect() {
232 nsresult rv;
234 // The common case for HTTP channels is to begin proxy resolution and return
235 // at this point. The only time we know mProxyInfo already is if we're
236 // proxying a non-http protocol like ftp. We don't need to discover proxy
237 // settings if we are never going to make a network connection.
238 // If mConnectionInfo is already supplied, we don't need to do proxy
239 // resolution again.
240 if (!mProxyInfo && !mConnectionInfo &&
241 !(mLoadFlags & (nsICachingChannel::LOAD_ONLY_FROM_CACHE |
242 nsICachingChannel::LOAD_NO_NETWORK_IO)) &&
243 NS_SUCCEEDED(ResolveProxy())) {
244 return NS_OK;
247 rv = BeginConnect();
248 if (NS_FAILED(rv)) {
249 Unused << AsyncAbort(rv);
252 return NS_OK;
255 nsresult TRRServiceChannel::ResolveProxy() {
256 LOG(("TRRServiceChannel::ResolveProxy [this=%p]\n", this));
257 if (!NS_IsMainThread()) {
258 return NS_DispatchToMainThread(
259 NewRunnableMethod("TRRServiceChannel::ResolveProxy", this,
260 &TRRServiceChannel::ResolveProxy),
261 NS_DISPATCH_NORMAL);
264 MOZ_ASSERT(NS_IsMainThread());
266 // TODO: bug 1625171. Consider moving proxy resolution to socket process.
267 RefPtr<TRRServiceChannel> self = this;
268 nsCOMPtr<nsICancelable> proxyRequest;
269 nsresult rv = ProxyConfigLookup::Create(
270 [self](nsIProxyInfo* aProxyInfo, nsresult aStatus) {
271 self->OnProxyAvailable(nullptr, nullptr, aProxyInfo, aStatus);
273 mURI, mProxyResolveFlags, getter_AddRefs(proxyRequest));
275 if (NS_FAILED(rv)) {
276 if (!mCurrentEventTarget->IsOnCurrentThread()) {
277 return mCurrentEventTarget->Dispatch(
278 NewRunnableMethod<nsresult>("TRRServiceChannel::AsyncAbort", this,
279 &TRRServiceChannel::AsyncAbort, rv),
280 NS_DISPATCH_NORMAL);
285 auto req = mProxyRequest.Lock();
286 // We only set mProxyRequest if the channel hasn't already been cancelled
287 // on another thread.
288 if (!mCanceled) {
289 *req = proxyRequest.forget();
293 // If the channel has been cancelled, we go ahead and cancel the proxy
294 // request right here.
295 if (proxyRequest) {
296 proxyRequest->Cancel(mStatus);
299 return rv;
302 NS_IMETHODIMP
303 TRRServiceChannel::OnProxyAvailable(nsICancelable* request, nsIChannel* channel,
304 nsIProxyInfo* pi, nsresult status) {
305 LOG(("TRRServiceChannel::OnProxyAvailable [this=%p pi=%p status=%" PRIx32
306 " mStatus=%" PRIx32 "]\n",
307 this, pi, static_cast<uint32_t>(status),
308 static_cast<uint32_t>(static_cast<nsresult>(mStatus))));
310 if (!mCurrentEventTarget->IsOnCurrentThread()) {
311 RefPtr<TRRServiceChannel> self = this;
312 nsCOMPtr<nsIProxyInfo> info = pi;
313 return mCurrentEventTarget->Dispatch(
314 NS_NewRunnableFunction("TRRServiceChannel::OnProxyAvailable",
315 [self, info, status]() {
316 self->OnProxyAvailable(nullptr, nullptr, info,
317 status);
319 NS_DISPATCH_NORMAL);
322 MOZ_ASSERT(mCurrentEventTarget->IsOnCurrentThread());
325 auto proxyRequest = mProxyRequest.Lock();
326 *proxyRequest = nullptr;
329 nsresult rv;
331 // If status is a failure code, then it means that we failed to resolve
332 // proxy info. That is a non-fatal error assuming it wasn't because the
333 // request was canceled. We just failover to DIRECT when proxy resolution
334 // fails (failure can mean that the PAC URL could not be loaded).
336 if (NS_SUCCEEDED(status)) mProxyInfo = pi;
338 if (!gHttpHandler->Active()) {
339 LOG(
340 ("nsHttpChannel::OnProxyAvailable [this=%p] "
341 "Handler no longer active.\n",
342 this));
343 rv = NS_ERROR_NOT_AVAILABLE;
344 } else {
345 rv = BeginConnect();
348 if (NS_FAILED(rv)) {
349 Unused << AsyncAbort(rv);
351 return rv;
354 nsresult TRRServiceChannel::BeginConnect() {
355 LOG(("TRRServiceChannel::BeginConnect [this=%p]\n", this));
356 nsresult rv;
358 // Construct connection info object
359 nsAutoCString host;
360 nsAutoCString scheme;
361 int32_t port = -1;
362 bool isHttps = mURI->SchemeIs("https");
364 rv = mURI->GetScheme(scheme);
365 if (NS_SUCCEEDED(rv)) rv = mURI->GetAsciiHost(host);
366 if (NS_SUCCEEDED(rv)) rv = mURI->GetPort(&port);
367 if (NS_SUCCEEDED(rv)) rv = mURI->GetAsciiSpec(mSpec);
368 if (NS_FAILED(rv)) {
369 return rv;
372 // Just a warning here because some nsIURIs do not implement this method.
373 Unused << NS_WARN_IF(NS_FAILED(mURI->GetUsername(mUsername)));
375 // Reject the URL if it doesn't specify a host
376 if (host.IsEmpty()) {
377 rv = NS_ERROR_MALFORMED_URI;
378 return rv;
380 LOG(("host=%s port=%d\n", host.get(), port));
381 LOG(("uri=%s\n", mSpec.get()));
383 nsCOMPtr<nsProxyInfo> proxyInfo;
384 if (mProxyInfo) proxyInfo = do_QueryInterface(mProxyInfo);
386 mRequestHead.SetHTTPS(isHttps);
387 mRequestHead.SetOrigin(scheme, host, port);
389 RefPtr<nsHttpConnectionInfo> connInfo = new nsHttpConnectionInfo(
390 host, port, ""_ns, mUsername, proxyInfo, OriginAttributes(), isHttps);
391 // TODO: Bug 1622778 for using AltService in socket process.
392 StoreAllowAltSvc(XRE_IsParentProcess() && LoadAllowAltSvc());
393 bool http2Allowed = !gHttpHandler->IsHttp2Excluded(connInfo);
394 bool http3Allowed = Http3Allowed();
395 if (!http3Allowed) {
396 mCaps |= NS_HTTP_DISALLOW_HTTP3;
399 RefPtr<AltSvcMapping> mapping;
400 if (!mConnectionInfo && LoadAllowAltSvc() && // per channel
401 (http2Allowed || http3Allowed) && !(mLoadFlags & LOAD_FRESH_CONNECTION) &&
402 AltSvcMapping::AcceptableProxy(proxyInfo) &&
403 (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https")) &&
404 (mapping = gHttpHandler->GetAltServiceMapping(
405 scheme, host, port, mPrivateBrowsing, OriginAttributes(),
406 http2Allowed, http3Allowed))) {
407 LOG(("TRRServiceChannel %p Alt Service Mapping Found %s://%s:%d [%s]\n",
408 this, scheme.get(), mapping->AlternateHost().get(),
409 mapping->AlternatePort(), mapping->HashKey().get()));
411 if (!(mLoadFlags & LOAD_ANONYMOUS) && !mPrivateBrowsing) {
412 nsAutoCString altUsedLine(mapping->AlternateHost());
413 bool defaultPort =
414 mapping->AlternatePort() ==
415 (isHttps ? NS_HTTPS_DEFAULT_PORT : NS_HTTP_DEFAULT_PORT);
416 if (!defaultPort) {
417 altUsedLine.AppendLiteral(":");
418 altUsedLine.AppendInt(mapping->AlternatePort());
420 rv = mRequestHead.SetHeader(nsHttp::Alternate_Service_Used, altUsedLine);
421 MOZ_ASSERT(NS_SUCCEEDED(rv));
424 LOG(("TRRServiceChannel %p Using connection info from altsvc mapping",
425 this));
426 mapping->GetConnectionInfo(getter_AddRefs(mConnectionInfo), proxyInfo,
427 OriginAttributes());
428 Telemetry::Accumulate(Telemetry::HTTP_TRANSACTION_USE_ALTSVC, true);
429 Telemetry::Accumulate(Telemetry::HTTP_TRANSACTION_USE_ALTSVC_OE, !isHttps);
430 } else if (mConnectionInfo) {
431 LOG(("TRRServiceChannel %p Using channel supplied connection info", this));
432 } else {
433 LOG(("TRRServiceChannel %p Using default connection info", this));
435 mConnectionInfo = connInfo;
436 Telemetry::Accumulate(Telemetry::HTTP_TRANSACTION_USE_ALTSVC, false);
439 // Need to re-ask the handler, since mConnectionInfo may not be the connInfo
440 // we used earlier
441 if (gHttpHandler->IsHttp2Excluded(mConnectionInfo)) {
442 StoreAllowSpdy(0);
443 mCaps |= NS_HTTP_DISALLOW_SPDY;
444 mConnectionInfo->SetNoSpdy(true);
447 // If TimingEnabled flag is not set after OnModifyRequest() then
448 // clear the already recorded AsyncOpen value for consistency.
449 if (!LoadTimingEnabled()) mAsyncOpenTime = TimeStamp();
451 // if this somehow fails we can go on without it
452 Unused << gHttpHandler->AddConnectionHeader(&mRequestHead, mCaps);
454 // Adjust mCaps according to our request headers:
455 // - If "Connection: close" is set as a request header, then do not bother
456 // trying to establish a keep-alive connection.
457 if (mRequestHead.HasHeaderValue(nsHttp::Connection, "close")) {
458 mCaps &= ~(NS_HTTP_ALLOW_KEEPALIVE);
461 if (gHttpHandler->CriticalRequestPrioritization()) {
462 if (mClassOfService.Flags() & nsIClassOfService::Leader) {
463 mCaps |= NS_HTTP_LOAD_AS_BLOCKING;
465 if (mClassOfService.Flags() & nsIClassOfService::Unblocked) {
466 mCaps |= NS_HTTP_LOAD_UNBLOCKED;
468 if (mClassOfService.Flags() & nsIClassOfService::UrgentStart &&
469 gHttpHandler->IsUrgentStartEnabled()) {
470 mCaps |= NS_HTTP_URGENT_START;
471 SetPriority(nsISupportsPriority::PRIORITY_HIGHEST);
475 if (mCanceled) {
476 return mStatus;
479 MaybeStartDNSPrefetch();
481 rv = ContinueOnBeforeConnect();
482 if (NS_FAILED(rv)) {
483 return rv;
486 return NS_OK;
489 nsresult TRRServiceChannel::ContinueOnBeforeConnect() {
490 LOG(("TRRServiceChannel::ContinueOnBeforeConnect [this=%p]\n", this));
492 // ensure that we are using a valid hostname
493 if (!net_IsValidHostName(nsDependentCString(mConnectionInfo->Origin()))) {
494 return NS_ERROR_UNKNOWN_HOST;
497 if (LoadIsTRRServiceChannel()) {
498 mCaps |= NS_HTTP_LARGE_KEEPALIVE;
499 mCaps |= NS_HTTP_DISALLOW_HTTPS_RR;
502 mCaps |= NS_HTTP_TRR_FLAGS_FROM_MODE(nsIRequest::GetTRRMode());
504 // Finalize ConnectionInfo flags before SpeculativeConnect
505 mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0);
506 mConnectionInfo->SetPrivate(mPrivateBrowsing);
507 mConnectionInfo->SetNoSpdy(mCaps & NS_HTTP_DISALLOW_SPDY);
508 mConnectionInfo->SetBeConservative((mCaps & NS_HTTP_BE_CONSERVATIVE) ||
509 LoadBeConservative());
510 mConnectionInfo->SetTlsFlags(mTlsFlags);
511 mConnectionInfo->SetIsTrrServiceChannel(LoadIsTRRServiceChannel());
512 mConnectionInfo->SetTRRMode(nsIRequest::GetTRRMode());
513 mConnectionInfo->SetIPv4Disabled(mCaps & NS_HTTP_DISABLE_IPV4);
514 mConnectionInfo->SetIPv6Disabled(mCaps & NS_HTTP_DISABLE_IPV6);
516 if (mLoadFlags & LOAD_FRESH_CONNECTION) {
517 Telemetry::ScalarAdd(
518 Telemetry::ScalarID::NETWORKING_TRR_CONNECTION_CYCLE_COUNT,
519 NS_ConvertUTF8toUTF16(TRRService::ProviderKey()), 1);
520 nsresult rv =
521 gHttpHandler->ConnMgr()->DoSingleConnectionCleanup(mConnectionInfo);
522 LOG(
523 ("TRRServiceChannel::BeginConnect "
524 "DoSingleConnectionCleanup succeeded=%d %08x [this=%p]",
525 NS_SUCCEEDED(rv), static_cast<uint32_t>(rv), this));
528 return Connect();
531 nsresult TRRServiceChannel::Connect() {
532 LOG(("TRRServiceChannel::Connect [this=%p]\n", this));
534 nsresult rv = SetupTransaction();
535 if (NS_FAILED(rv)) {
536 return rv;
539 rv = gHttpHandler->InitiateTransaction(mTransaction, mPriority);
540 if (NS_FAILED(rv)) {
541 return rv;
544 return mTransaction->AsyncRead(this, getter_AddRefs(mTransactionPump));
547 nsresult TRRServiceChannel::SetupTransaction() {
548 LOG((
549 "TRRServiceChannel::SetupTransaction "
550 "[this=%p, cos=%lu, inc=%d, prio=%d]\n",
551 this, mClassOfService.Flags(), mClassOfService.Incremental(), mPriority));
553 NS_ENSURE_TRUE(!mTransaction, NS_ERROR_ALREADY_INITIALIZED);
555 nsresult rv;
557 if (!LoadAllowSpdy()) {
558 mCaps |= NS_HTTP_DISALLOW_SPDY;
560 // Check a proxy info from mConnectionInfo. TRR channel may use a proxy that
561 // is set in mConnectionInfo but acutally the channel do not have mProxyInfo
562 // set. This can happend when network.trr.async_connInfo is true.
563 bool useNonDirectProxy = mConnectionInfo->ProxyInfo()
564 ? !mConnectionInfo->ProxyInfo()->IsDirect()
565 : false;
566 if (!Http3Allowed() || useNonDirectProxy) {
567 mCaps |= NS_HTTP_DISALLOW_HTTP3;
569 if (LoadBeConservative()) {
570 mCaps |= NS_HTTP_BE_CONSERVATIVE;
573 // Use the URI path if not proxying (transparent proxying such as proxy
574 // CONNECT does not count here). Also figure out what HTTP version to use.
575 nsAutoCString buf, path;
576 nsCString* requestURI;
578 // This is the normal e2e H1 path syntax "/index.html"
579 rv = mURI->GetPathQueryRef(path);
580 if (NS_FAILED(rv)) {
581 return rv;
584 // path may contain UTF-8 characters, so ensure that they're escaped.
585 if (NS_EscapeURL(path.get(), path.Length(), esc_OnlyNonASCII | esc_Spaces,
586 buf)) {
587 requestURI = &buf;
588 } else {
589 requestURI = &path;
592 // trim off the #ref portion if any...
593 int32_t ref1 = requestURI->FindChar('#');
594 if (ref1 != kNotFound) {
595 requestURI->SetLength(ref1);
598 if (mConnectionInfo->UsingConnect() || !mConnectionInfo->UsingHttpProxy()) {
599 mRequestHead.SetVersion(gHttpHandler->HttpVersion());
600 } else {
601 mRequestHead.SetPath(*requestURI);
603 // RequestURI should be the absolute uri H1 proxy syntax
604 // "http://foo/index.html" so we will overwrite the relative version in
605 // requestURI
606 rv = mURI->GetUserPass(buf);
607 if (NS_FAILED(rv)) return rv;
608 if (!buf.IsEmpty() && ((strncmp(mSpec.get(), "http:", 5) == 0) ||
609 strncmp(mSpec.get(), "https:", 6) == 0)) {
610 nsCOMPtr<nsIURI> tempURI = nsIOService::CreateExposableURI(mURI);
611 rv = tempURI->GetAsciiSpec(path);
612 if (NS_FAILED(rv)) return rv;
613 requestURI = &path;
614 } else {
615 requestURI = &mSpec;
618 // trim off the #ref portion if any...
619 int32_t ref2 = requestURI->FindChar('#');
620 if (ref2 != kNotFound) {
621 requestURI->SetLength(ref2);
624 mRequestHead.SetVersion(gHttpHandler->ProxyHttpVersion());
627 mRequestHead.SetRequestURI(*requestURI);
629 // Force setting no-cache header for TRRServiceChannel.
630 // We need to send 'Pragma:no-cache' to inhibit proxy caching even if
631 // no proxy is configured since we might be talking with a transparent
632 // proxy, i.e. one that operates at the network level. See bug #14772.
633 rv = mRequestHead.SetHeaderOnce(nsHttp::Pragma, "no-cache", true);
634 MOZ_ASSERT(NS_SUCCEEDED(rv));
635 // If we're configured to speak HTTP/1.1 then also send 'Cache-control:
636 // no-cache'
637 if (mRequestHead.Version() >= HttpVersion::v1_1) {
638 rv = mRequestHead.SetHeaderOnce(nsHttp::Cache_Control, "no-cache", true);
639 MOZ_ASSERT(NS_SUCCEEDED(rv));
642 // create wrapper for this channel's notification callbacks
643 nsCOMPtr<nsIInterfaceRequestor> callbacks;
644 NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
645 getter_AddRefs(callbacks));
647 // create the transaction object
648 mTransaction = new nsHttpTransaction();
649 LOG1(("TRRServiceChannel %p created nsHttpTransaction %p\n", this,
650 mTransaction.get()));
652 // See bug #466080. Transfer LOAD_ANONYMOUS flag to socket-layer.
653 if (mLoadFlags & LOAD_ANONYMOUS) mCaps |= NS_HTTP_LOAD_ANONYMOUS;
655 if (LoadTimingEnabled()) mCaps |= NS_HTTP_TIMING_ENABLED;
657 nsCOMPtr<nsIHttpPushListener> pushListener;
658 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
659 NS_GET_IID(nsIHttpPushListener),
660 getter_AddRefs(pushListener));
661 HttpTransactionShell::OnPushCallback pushCallback = nullptr;
662 if (pushListener) {
663 mCaps |= NS_HTTP_ONPUSH_LISTENER;
664 nsWeakPtr weakPtrThis(
665 do_GetWeakReference(static_cast<nsIHttpChannel*>(this)));
666 pushCallback = [weakPtrThis](uint32_t aPushedStreamId,
667 const nsACString& aUrl,
668 const nsACString& aRequestString,
669 HttpTransactionShell* aTransaction) {
670 if (nsCOMPtr<nsIHttpChannel> channel = do_QueryReferent(weakPtrThis)) {
671 return static_cast<TRRServiceChannel*>(channel.get())
672 ->OnPush(aPushedStreamId, aUrl, aRequestString, aTransaction);
674 return NS_ERROR_NOT_AVAILABLE;
678 EnsureRequestContext();
680 rv = mTransaction->Init(
681 mCaps, mConnectionInfo, &mRequestHead, mUploadStream, mReqContentLength,
682 LoadUploadStreamHasHeaders(), mCurrentEventTarget, callbacks, this,
683 mBrowserId, HttpTrafficCategory::eInvalid, mRequestContext,
684 mClassOfService, mInitialRwin, LoadResponseTimeoutEnabled(), mChannelId,
685 nullptr, std::move(pushCallback), mTransWithPushedStream,
686 mPushedStreamId);
688 mTransWithPushedStream = nullptr;
690 if (NS_FAILED(rv)) {
691 mTransaction = nullptr;
692 return rv;
695 return rv;
698 void TRRServiceChannel::SetPushedStreamTransactionAndId(
699 HttpTransactionShell* aTransWithPushedStream, uint32_t aPushedStreamId) {
700 MOZ_ASSERT(!mTransWithPushedStream);
701 LOG(("TRRServiceChannel::SetPushedStreamTransaction [this=%p] trans=%p", this,
702 aTransWithPushedStream));
704 mTransWithPushedStream = aTransWithPushedStream;
705 mPushedStreamId = aPushedStreamId;
708 nsresult TRRServiceChannel::OnPush(uint32_t aPushedStreamId,
709 const nsACString& aUrl,
710 const nsACString& aRequestString,
711 HttpTransactionShell* aTransaction) {
712 MOZ_ASSERT(aTransaction);
713 LOG(("TRRServiceChannel::OnPush [this=%p, trans=%p]\n", this, aTransaction));
715 MOZ_ASSERT(mCaps & NS_HTTP_ONPUSH_LISTENER);
716 nsCOMPtr<nsIHttpPushListener> pushListener;
717 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
718 NS_GET_IID(nsIHttpPushListener),
719 getter_AddRefs(pushListener));
721 if (!pushListener) {
722 LOG(
723 ("TRRServiceChannel::OnPush [this=%p] notification callbacks do not "
724 "implement nsIHttpPushListener\n",
725 this));
726 return NS_ERROR_NOT_AVAILABLE;
729 nsCOMPtr<nsIURI> pushResource;
730 nsresult rv;
732 // Create a Channel for the Push Resource
733 rv = NS_NewURI(getter_AddRefs(pushResource), aUrl);
734 if (NS_FAILED(rv)) {
735 return NS_ERROR_FAILURE;
738 nsCOMPtr<nsILoadInfo> loadInfo =
739 static_cast<TRRLoadInfo*>(mLoadInfo.get())->Clone();
740 nsCOMPtr<nsIChannel> pushHttpChannel;
741 rv = gHttpHandler->CreateTRRServiceChannel(pushResource, nullptr, 0, nullptr,
742 loadInfo,
743 getter_AddRefs(pushHttpChannel));
744 NS_ENSURE_SUCCESS(rv, rv);
746 rv = pushHttpChannel->SetLoadFlags(mLoadFlags);
747 NS_ENSURE_SUCCESS(rv, rv);
749 RefPtr<TRRServiceChannel> channel;
750 CallQueryInterface(pushHttpChannel, channel.StartAssignment());
751 MOZ_ASSERT(channel);
752 if (!channel) {
753 return NS_ERROR_UNEXPECTED;
756 // new channel needs mrqeuesthead and headers from pushedStream
757 channel->mRequestHead.ParseHeaderSet(aRequestString.BeginReading());
758 channel->mLoadGroup = mLoadGroup;
759 channel->mCallbacks = mCallbacks;
761 // Link the pushed stream with the new channel and call listener
762 channel->SetPushedStreamTransactionAndId(aTransaction, aPushedStreamId);
763 rv = pushListener->OnPush(this, channel);
764 return rv;
767 void TRRServiceChannel::MaybeStartDNSPrefetch() {
768 if (mConnectionInfo->UsingHttpProxy() ||
769 (mLoadFlags & (nsICachingChannel::LOAD_NO_NETWORK_IO |
770 nsICachingChannel::LOAD_ONLY_FROM_CACHE))) {
771 return;
774 LOG(
775 ("TRRServiceChannel::MaybeStartDNSPrefetch [this=%p] "
776 "prefetching%s\n",
777 this, mCaps & NS_HTTP_REFRESH_DNS ? ", refresh requested" : ""));
779 OriginAttributes originAttributes;
780 mDNSPrefetch =
781 new nsDNSPrefetch(mURI, originAttributes, nsIRequest::GetTRRMode(), this,
782 LoadTimingEnabled());
783 nsIDNSService::DNSFlags dnsFlags = nsIDNSService::RESOLVE_DEFAULT_FLAGS;
784 if (mCaps & NS_HTTP_REFRESH_DNS) {
785 dnsFlags |= nsIDNSService::RESOLVE_BYPASS_CACHE;
787 nsresult rv = mDNSPrefetch->PrefetchHigh(dnsFlags);
788 NS_ENSURE_SUCCESS_VOID(rv);
791 NS_IMETHODIMP
792 TRRServiceChannel::OnTransportStatus(nsITransport* trans, nsresult status,
793 int64_t progress, int64_t progressMax) {
794 return NS_OK;
797 nsresult TRRServiceChannel::CallOnStartRequest() {
798 LOG(("TRRServiceChannel::CallOnStartRequest [this=%p]", this));
800 if (LoadOnStartRequestCalled()) {
801 LOG(("CallOnStartRequest already invoked before"));
802 return mStatus;
805 nsresult rv = NS_OK;
806 StoreTracingEnabled(false);
808 // Ensure mListener->OnStartRequest will be invoked before exiting
809 // this function.
810 auto onStartGuard = MakeScopeExit([&] {
811 LOG(
812 (" calling mListener->OnStartRequest by ScopeExit [this=%p, "
813 "listener=%p]\n",
814 this, mListener.get()));
815 MOZ_ASSERT(!LoadOnStartRequestCalled());
817 if (mListener) {
818 nsCOMPtr<nsIStreamListener> deleteProtector(mListener);
819 StoreOnStartRequestCalled(true);
820 deleteProtector->OnStartRequest(this);
822 StoreOnStartRequestCalled(true);
825 if (mResponseHead && !mResponseHead->HasContentCharset()) {
826 mResponseHead->SetContentCharset(mContentCharsetHint);
829 LOG((" calling mListener->OnStartRequest [this=%p, listener=%p]\n", this,
830 mListener.get()));
832 // About to call OnStartRequest, dismiss the guard object.
833 onStartGuard.release();
835 if (mListener) {
836 MOZ_ASSERT(!LoadOnStartRequestCalled(),
837 "We should not call OsStartRequest twice");
838 nsCOMPtr<nsIStreamListener> deleteProtector(mListener);
839 StoreOnStartRequestCalled(true);
840 rv = deleteProtector->OnStartRequest(this);
841 if (NS_FAILED(rv)) return rv;
842 } else {
843 NS_WARNING("OnStartRequest skipped because of null listener");
844 StoreOnStartRequestCalled(true);
847 if (!mResponseHead) {
848 return NS_OK;
851 nsAutoCString contentEncoding;
852 rv = mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding);
853 if (NS_FAILED(rv) || contentEncoding.IsEmpty()) {
854 return NS_OK;
857 // DoApplyContentConversions can only be called on the main thread.
858 if (NS_IsMainThread()) {
859 nsCOMPtr<nsIStreamListener> listener;
860 rv =
861 DoApplyContentConversions(mListener, getter_AddRefs(listener), nullptr);
862 if (NS_FAILED(rv)) {
863 return rv;
866 AfterApplyContentConversions(rv, listener);
867 return NS_OK;
870 Suspend();
872 RefPtr<TRRServiceChannel> self = this;
873 rv = NS_DispatchToMainThread(
874 NS_NewRunnableFunction("TRRServiceChannel::DoApplyContentConversions",
875 [self]() {
876 nsCOMPtr<nsIStreamListener> listener;
877 nsresult rv = self->DoApplyContentConversions(
878 self->mListener, getter_AddRefs(listener),
879 nullptr);
880 self->AfterApplyContentConversions(rv, listener);
882 NS_DISPATCH_NORMAL);
883 if (NS_FAILED(rv)) {
884 Resume();
885 return rv;
888 return NS_OK;
891 void TRRServiceChannel::AfterApplyContentConversions(
892 nsresult aResult, nsIStreamListener* aListener) {
893 LOG(("TRRServiceChannel::AfterApplyContentConversions [this=%p]", this));
894 if (!mCurrentEventTarget->IsOnCurrentThread()) {
895 RefPtr<TRRServiceChannel> self = this;
896 nsCOMPtr<nsIStreamListener> listener = aListener;
897 self->mCurrentEventTarget->Dispatch(
898 NS_NewRunnableFunction(
899 "TRRServiceChannel::AfterApplyContentConversions",
900 [self, aResult, listener]() {
901 self->Resume();
902 self->AfterApplyContentConversions(aResult, listener);
904 NS_DISPATCH_NORMAL);
905 return;
908 if (mCanceled) {
909 return;
912 if (NS_FAILED(aResult)) {
913 Unused << AsyncAbort(aResult);
914 return;
917 if (aListener) {
918 mListener = aListener;
919 mCompressListener = aListener;
920 StoreHasAppliedConversion(true);
924 void TRRServiceChannel::ProcessAltService() {
925 // e.g. Alt-Svc: h2=":443"; ma=60
926 // e.g. Alt-Svc: h2="otherhost:443"
927 // Alt-Svc = 1#( alternative *( OWS ";" OWS parameter ) )
928 // alternative = protocol-id "=" alt-authority
929 // protocol-id = token ; percent-encoded ALPN protocol identifier
930 // alt-authority = quoted-string ; containing [ uri-host ] ":" port
932 if (!LoadAllowAltSvc()) { // per channel opt out
933 return;
936 if (!gHttpHandler->AllowAltSvc() || (mCaps & NS_HTTP_DISALLOW_SPDY)) {
937 return;
940 nsCString scheme;
941 mURI->GetScheme(scheme);
942 bool isHttp = scheme.EqualsLiteral("http");
943 if (!isHttp && !scheme.EqualsLiteral("https")) {
944 return;
947 nsCString altSvc;
948 Unused << mResponseHead->GetHeader(nsHttp::Alternate_Service, altSvc);
949 if (altSvc.IsEmpty()) {
950 return;
953 if (!nsHttp::IsReasonableHeaderValue(altSvc)) {
954 LOG(("Alt-Svc Response Header seems unreasonable - skipping\n"));
955 return;
958 nsCString originHost;
959 int32_t originPort = 80;
960 mURI->GetPort(&originPort);
961 if (NS_FAILED(mURI->GetAsciiHost(originHost))) {
962 return;
965 nsCOMPtr<nsIInterfaceRequestor> callbacks;
966 nsCOMPtr<nsProxyInfo> proxyInfo;
967 NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
968 getter_AddRefs(callbacks));
969 if (mProxyInfo) {
970 proxyInfo = do_QueryInterface(mProxyInfo);
973 auto processHeaderTask = [altSvc, scheme, originHost, originPort,
974 userName(mUsername),
975 privateBrowsing(mPrivateBrowsing), callbacks,
976 proxyInfo, caps(mCaps)]() {
977 if (XRE_IsSocketProcess()) {
978 AltServiceChild::ProcessHeader(altSvc, scheme, originHost, originPort,
979 userName, privateBrowsing, callbacks,
980 proxyInfo, caps & NS_HTTP_DISALLOW_SPDY,
981 OriginAttributes());
982 return;
985 AltSvcMapping::ProcessHeader(
986 altSvc, scheme, originHost, originPort, userName, privateBrowsing,
987 callbacks, proxyInfo, caps & NS_HTTP_DISALLOW_SPDY, OriginAttributes());
990 if (NS_IsMainThread()) {
991 processHeaderTask();
992 return;
995 NS_DispatchToMainThread(NS_NewRunnableFunction(
996 "TRRServiceChannel::ProcessAltService", std::move(processHeaderTask)));
999 NS_IMETHODIMP
1000 TRRServiceChannel::OnStartRequest(nsIRequest* request) {
1001 LOG(("TRRServiceChannel::OnStartRequest [this=%p request=%p status=%" PRIx32
1002 "]\n",
1003 this, request, static_cast<uint32_t>(static_cast<nsresult>(mStatus))));
1005 if (!(mCanceled || NS_FAILED(mStatus))) {
1006 // capture the request's status, so our consumers will know ASAP of any
1007 // connection failures, etc - bug 93581
1008 nsresult status;
1009 request->GetStatus(&status);
1010 mStatus = status;
1013 MOZ_ASSERT(request == mTransactionPump, "Unexpected request");
1015 StoreAfterOnStartRequestBegun(true);
1016 if (mTransaction) {
1017 if (!mSecurityInfo) {
1018 // grab the security info from the connection object; the transaction
1019 // is guaranteed to own a reference to the connection.
1020 mSecurityInfo = mTransaction->SecurityInfo();
1024 if (NS_SUCCEEDED(mStatus) && mTransaction) {
1025 // mTransactionPump doesn't hit OnInputStreamReady and call this until
1026 // all of the response headers have been acquired, so we can take
1027 // ownership of them from the transaction.
1028 mResponseHead = mTransaction->TakeResponseHead();
1029 if (mResponseHead) {
1030 uint32_t httpStatus = mResponseHead->Status();
1031 if (mTransaction->ProxyConnectFailed()) {
1032 LOG(("TRRServiceChannel proxy connect failed httpStatus: %d",
1033 httpStatus));
1034 MOZ_ASSERT(mConnectionInfo->UsingConnect(),
1035 "proxy connect failed but not using CONNECT?");
1036 nsresult rv = HttpProxyResponseToErrorCode(httpStatus);
1037 mTransaction->DontReuseConnection();
1038 Cancel(rv);
1039 return CallOnStartRequest();
1042 if ((httpStatus < 500) && (httpStatus != 421) && (httpStatus != 407)) {
1043 ProcessAltService();
1046 if (httpStatus == 300 || httpStatus == 301 || httpStatus == 302 ||
1047 httpStatus == 303 || httpStatus == 307 || httpStatus == 308) {
1048 nsresult rv = SyncProcessRedirection(httpStatus);
1049 if (NS_SUCCEEDED(rv)) {
1050 return rv;
1053 mStatus = rv;
1054 DoNotifyListener();
1055 return rv;
1057 } else {
1058 NS_WARNING("No response head in OnStartRequest");
1062 // avoid crashing if mListener happens to be null...
1063 if (!mListener) {
1064 MOZ_ASSERT_UNREACHABLE("mListener is null");
1065 return NS_OK;
1068 return CallOnStartRequest();
1071 nsresult TRRServiceChannel::SyncProcessRedirection(uint32_t aHttpStatus) {
1072 nsAutoCString location;
1074 // if a location header was not given, then we can't perform the redirect,
1075 // so just carry on as though this were a normal response.
1076 if (NS_FAILED(mResponseHead->GetHeader(nsHttp::Location, location))) {
1077 return NS_ERROR_FAILURE;
1080 // make sure non-ASCII characters in the location header are escaped.
1081 nsAutoCString locationBuf;
1082 if (NS_EscapeURL(location.get(), -1, esc_OnlyNonASCII | esc_Spaces,
1083 locationBuf)) {
1084 location = locationBuf;
1087 LOG(("redirecting to: %s [redirection-limit=%u]\n", location.get(),
1088 uint32_t(mRedirectionLimit)));
1090 nsCOMPtr<nsIURI> redirectURI;
1091 nsresult rv = NS_NewURI(getter_AddRefs(redirectURI), location);
1093 if (NS_FAILED(rv)) {
1094 LOG(("Invalid URI for redirect: Location: %s\n", location.get()));
1095 return NS_ERROR_CORRUPTED_CONTENT;
1098 // move the reference of the old location to the new one if the new
1099 // one has none.
1100 PropagateReferenceIfNeeded(mURI, redirectURI);
1102 bool rewriteToGET =
1103 ShouldRewriteRedirectToGET(aHttpStatus, mRequestHead.ParsedMethod());
1105 // Let's not rewrite the method to GET for TRR requests.
1106 if (rewriteToGET) {
1107 return NS_ERROR_FAILURE;
1110 // If the method is not safe (such as POST, PUT, DELETE, ...)
1111 if (!mRequestHead.IsSafeMethod()) {
1112 LOG(("TRRServiceChannel: unsafe redirect to:%s\n", location.get()));
1115 uint32_t redirectFlags;
1116 if (nsHttp::IsPermanentRedirect(aHttpStatus)) {
1117 redirectFlags = nsIChannelEventSink::REDIRECT_PERMANENT;
1118 } else {
1119 redirectFlags = nsIChannelEventSink::REDIRECT_TEMPORARY;
1122 nsCOMPtr<nsIChannel> newChannel;
1123 nsCOMPtr<nsILoadInfo> redirectLoadInfo =
1124 static_cast<TRRLoadInfo*>(mLoadInfo.get())->Clone();
1125 rv = gHttpHandler->CreateTRRServiceChannel(redirectURI, nullptr, 0, nullptr,
1126 redirectLoadInfo,
1127 getter_AddRefs(newChannel));
1128 if (NS_FAILED(rv)) {
1129 return rv;
1132 rv = SetupReplacementChannel(redirectURI, newChannel, !rewriteToGET,
1133 redirectFlags);
1134 if (NS_FAILED(rv)) {
1135 return rv;
1138 // Make sure to do this after we received redirect veto answer,
1139 // i.e. after all sinks had been notified
1140 newChannel->SetOriginalURI(mOriginalURI);
1142 rv = newChannel->AsyncOpen(mListener);
1143 LOG((" new channel AsyncOpen returned %" PRIX32, static_cast<uint32_t>(rv)));
1145 // close down this channel
1146 Cancel(NS_BINDING_REDIRECTED);
1148 ReleaseListeners();
1150 return NS_OK;
1153 nsresult TRRServiceChannel::SetupReplacementChannel(nsIURI* aNewURI,
1154 nsIChannel* aNewChannel,
1155 bool aPreserveMethod,
1156 uint32_t aRedirectFlags) {
1157 LOG(
1158 ("TRRServiceChannel::SetupReplacementChannel "
1159 "[this=%p newChannel=%p preserveMethod=%d]",
1160 this, aNewChannel, aPreserveMethod));
1162 nsresult rv = HttpBaseChannel::SetupReplacementChannel(
1163 aNewURI, aNewChannel, aPreserveMethod, aRedirectFlags);
1164 if (NS_FAILED(rv)) {
1165 return rv;
1168 rv = CheckRedirectLimit(aRedirectFlags);
1169 NS_ENSURE_SUCCESS(rv, rv);
1171 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel);
1172 if (!httpChannel) {
1173 MOZ_ASSERT(false);
1174 return NS_ERROR_FAILURE;
1177 // convey the ApplyConversion flag (bug 91862)
1178 nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(httpChannel);
1179 if (encodedChannel) {
1180 encodedChannel->SetApplyConversion(LoadApplyConversion());
1183 // mContentTypeHint is empty when this channel is used to download
1184 // ODoHConfigs.
1185 if (mContentTypeHint.IsEmpty()) {
1186 return NS_OK;
1189 // Make sure we set content-type on the old channel properly.
1190 MOZ_ASSERT(mContentTypeHint.Equals("application/dns-message") ||
1191 mContentTypeHint.Equals("application/oblivious-dns-message"));
1193 // Apply TRR specific settings. Note that we already know mContentTypeHint is
1194 // "application/dns-message" or "application/oblivious-dns-message" here.
1195 return TRR::SetupTRRServiceChannelInternal(
1196 httpChannel,
1197 mRequestHead.ParsedMethod() == nsHttpRequestHead::kMethod_Get,
1198 mContentTypeHint);
1201 NS_IMETHODIMP
1202 TRRServiceChannel::OnDataAvailable(nsIRequest* request, nsIInputStream* input,
1203 uint64_t offset, uint32_t count) {
1204 LOG(("TRRServiceChannel::OnDataAvailable [this=%p request=%p offset=%" PRIu64
1205 " count=%" PRIu32 "]\n",
1206 this, request, offset, count));
1208 // don't send out OnDataAvailable notifications if we've been canceled.
1209 if (mCanceled) return mStatus;
1211 MOZ_ASSERT(mResponseHead, "No response head in ODA!!");
1213 if (mListener) {
1214 return mListener->OnDataAvailable(this, input, offset, count);
1217 return NS_ERROR_ABORT;
1220 NS_IMETHODIMP
1221 TRRServiceChannel::OnStopRequest(nsIRequest* request, nsresult status) {
1222 LOG(("TRRServiceChannel::OnStopRequest [this=%p request=%p status=%" PRIx32
1223 "]\n",
1224 this, request, static_cast<uint32_t>(status)));
1226 if (mCanceled || NS_FAILED(mStatus)) status = mStatus;
1228 mTransactionTimings = mTransaction->Timings();
1229 mTransaction = nullptr;
1230 mTransactionPump = nullptr;
1232 if (mListener) {
1233 LOG(("TRRServiceChannel %p calling OnStopRequest\n", this));
1234 MOZ_ASSERT(LoadOnStartRequestCalled(),
1235 "OnStartRequest should be called before OnStopRequest");
1236 MOZ_ASSERT(!LoadOnStopRequestCalled(),
1237 "We should not call OnStopRequest twice");
1238 StoreOnStopRequestCalled(true);
1239 mListener->OnStopRequest(this, status);
1241 StoreOnStopRequestCalled(true);
1243 mDNSPrefetch = nullptr;
1245 if (mLoadGroup) {
1246 mLoadGroup->RemoveRequest(this, nullptr, status);
1249 ReleaseListeners();
1250 return NS_OK;
1253 NS_IMETHODIMP
1254 TRRServiceChannel::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec,
1255 nsresult status) {
1256 LOG(
1257 ("TRRServiceChannel::OnLookupComplete [this=%p] prefetch complete%s: "
1258 "%s status[0x%" PRIx32 "]\n",
1259 this, mCaps & NS_HTTP_REFRESH_DNS ? ", refresh requested" : "",
1260 NS_SUCCEEDED(status) ? "success" : "failure",
1261 static_cast<uint32_t>(status)));
1263 // We no longer need the dns prefetch object. Note: mDNSPrefetch could be
1264 // validly null if OnStopRequest has already been called.
1265 // We only need the domainLookup timestamps when not loading from cache
1266 if (mDNSPrefetch && mDNSPrefetch->TimingsValid() && mTransaction) {
1267 TimeStamp connectStart = mTransaction->GetConnectStart();
1268 TimeStamp requestStart = mTransaction->GetRequestStart();
1269 // We only set the domainLookup timestamps if we're not using a
1270 // persistent connection.
1271 if (requestStart.IsNull() && connectStart.IsNull()) {
1272 mTransaction->SetDomainLookupStart(mDNSPrefetch->StartTimestamp());
1273 mTransaction->SetDomainLookupEnd(mDNSPrefetch->EndTimestamp());
1276 mDNSPrefetch = nullptr;
1278 // Unset DNS cache refresh if it was requested,
1279 if (mCaps & NS_HTTP_REFRESH_DNS) {
1280 mCaps &= ~NS_HTTP_REFRESH_DNS;
1281 if (mTransaction) {
1282 mTransaction->SetDNSWasRefreshed();
1286 return NS_OK;
1289 NS_IMETHODIMP
1290 TRRServiceChannel::LogBlockedCORSRequest(const nsAString& aMessage,
1291 const nsACString& aCategory,
1292 bool aIsWarning) {
1293 return NS_ERROR_NOT_IMPLEMENTED;
1296 NS_IMETHODIMP
1297 TRRServiceChannel::LogMimeTypeMismatch(const nsACString& aMessageName,
1298 bool aWarning, const nsAString& aURL,
1299 const nsAString& aContentType) {
1300 return NS_ERROR_NOT_IMPLEMENTED;
1303 NS_IMETHODIMP
1304 TRRServiceChannel::GetIsAuthChannel(bool* aIsAuthChannel) {
1305 return NS_ERROR_NOT_IMPLEMENTED;
1308 NS_IMETHODIMP
1309 TRRServiceChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) {
1310 mCallbacks = aCallbacks;
1311 return NS_OK;
1314 NS_IMETHODIMP
1315 TRRServiceChannel::SetPriority(int32_t value) {
1316 return NS_ERROR_NOT_IMPLEMENTED;
1319 void TRRServiceChannel::OnClassOfServiceUpdated() {
1320 LOG(("TRRServiceChannel::OnClassOfServiceUpdated this=%p, cos=%lu inc=%d",
1321 this, mClassOfService.Flags(), mClassOfService.Incremental()));
1323 if (mTransaction) {
1324 gHttpHandler->UpdateClassOfServiceOnTransaction(mTransaction,
1325 mClassOfService);
1329 NS_IMETHODIMP
1330 TRRServiceChannel::SetClassFlags(uint32_t inFlags) {
1331 uint32_t previous = mClassOfService.Flags();
1332 mClassOfService.SetFlags(inFlags);
1333 if (previous != mClassOfService.Flags()) {
1334 OnClassOfServiceUpdated();
1336 return NS_OK;
1339 NS_IMETHODIMP
1340 TRRServiceChannel::SetIncremental(bool inFlag) {
1341 bool previous = mClassOfService.Incremental();
1342 mClassOfService.SetIncremental(inFlag);
1343 if (previous != mClassOfService.Incremental()) {
1344 OnClassOfServiceUpdated();
1346 return NS_OK;
1349 NS_IMETHODIMP
1350 TRRServiceChannel::SetClassOfService(ClassOfService cos) {
1351 ClassOfService previous = mClassOfService;
1352 mClassOfService = cos;
1353 if (previous != mClassOfService) {
1354 OnClassOfServiceUpdated();
1356 return NS_OK;
1359 NS_IMETHODIMP
1360 TRRServiceChannel::AddClassFlags(uint32_t inFlags) {
1361 uint32_t previous = mClassOfService.Flags();
1362 mClassOfService.SetFlags(inFlags | mClassOfService.Flags());
1363 if (previous != mClassOfService.Flags()) {
1364 OnClassOfServiceUpdated();
1366 return NS_OK;
1369 NS_IMETHODIMP
1370 TRRServiceChannel::ClearClassFlags(uint32_t inFlags) {
1371 uint32_t previous = mClassOfService.Flags();
1372 mClassOfService.SetFlags(~inFlags & mClassOfService.Flags());
1373 if (previous != mClassOfService.Flags()) {
1374 OnClassOfServiceUpdated();
1376 return NS_OK;
1379 NS_IMETHODIMP
1380 TRRServiceChannel::ResumeAt(uint64_t aStartPos, const nsACString& aEntityID) {
1381 return NS_ERROR_NOT_IMPLEMENTED;
1384 void TRRServiceChannel::DoAsyncAbort(nsresult aStatus) {
1385 Unused << AsyncAbort(aStatus);
1388 NS_IMETHODIMP
1389 TRRServiceChannel::GetProxyInfo(nsIProxyInfo** result) {
1390 if (!mConnectionInfo) {
1391 *result = do_AddRef(mProxyInfo).take();
1392 } else {
1393 *result = do_AddRef(mConnectionInfo->ProxyInfo()).take();
1395 return NS_OK;
1398 NS_IMETHODIMP TRRServiceChannel::GetHttpProxyConnectResponseCode(
1399 int32_t* aResponseCode) {
1400 NS_ENSURE_ARG_POINTER(aResponseCode);
1402 *aResponseCode = -1;
1403 return NS_OK;
1406 NS_IMETHODIMP
1407 TRRServiceChannel::GetLoadFlags(nsLoadFlags* aLoadFlags) {
1408 return HttpBaseChannel::GetLoadFlags(aLoadFlags);
1411 NS_IMETHODIMP
1412 TRRServiceChannel::SetLoadFlags(nsLoadFlags aLoadFlags) {
1413 if (aLoadFlags & (nsICachingChannel::LOAD_ONLY_FROM_CACHE | LOAD_FROM_CACHE |
1414 nsICachingChannel::LOAD_NO_NETWORK_IO)) {
1415 MOZ_ASSERT(false, "Wrong load flags!");
1416 return NS_ERROR_FAILURE;
1419 return HttpBaseChannel::SetLoadFlags(aLoadFlags);
1422 NS_IMETHODIMP
1423 TRRServiceChannel::GetURI(nsIURI** aURI) {
1424 return HttpBaseChannel::GetURI(aURI);
1427 NS_IMETHODIMP
1428 TRRServiceChannel::GetNotificationCallbacks(
1429 nsIInterfaceRequestor** aCallbacks) {
1430 return HttpBaseChannel::GetNotificationCallbacks(aCallbacks);
1433 NS_IMETHODIMP
1434 TRRServiceChannel::GetLoadGroup(nsILoadGroup** aLoadGroup) {
1435 return HttpBaseChannel::GetLoadGroup(aLoadGroup);
1438 NS_IMETHODIMP
1439 TRRServiceChannel::GetRequestMethod(nsACString& aMethod) {
1440 return HttpBaseChannel::GetRequestMethod(aMethod);
1443 void TRRServiceChannel::DoNotifyListener() {
1444 LOG(("TRRServiceChannel::DoNotifyListener this=%p", this));
1446 // In case nsHttpChannel::OnStartRequest wasn't called (e.g. due to flag
1447 // LOAD_ONLY_IF_MODIFIED) we want to set AfterOnStartRequestBegun to true
1448 // before notifying listener.
1449 if (!LoadAfterOnStartRequestBegun()) {
1450 StoreAfterOnStartRequestBegun(true);
1453 if (mListener && !LoadOnStartRequestCalled()) {
1454 nsCOMPtr<nsIStreamListener> listener = mListener;
1455 StoreOnStartRequestCalled(true);
1456 listener->OnStartRequest(this);
1458 StoreOnStartRequestCalled(true);
1460 // Make sure IsPending is set to false. At this moment we are done from
1461 // the point of view of our consumer and we have to report our self
1462 // as not-pending.
1463 StoreIsPending(false);
1465 if (mListener && !LoadOnStopRequestCalled()) {
1466 nsCOMPtr<nsIStreamListener> listener = mListener;
1467 StoreOnStopRequestCalled(true);
1468 listener->OnStopRequest(this, mStatus);
1470 StoreOnStopRequestCalled(true);
1472 // We have to make sure to drop the references to listeners and callbacks
1473 // no longer needed.
1474 ReleaseListeners();
1476 DoNotifyListenerCleanup();
1479 void TRRServiceChannel::DoNotifyListenerCleanup() {}
1481 NS_IMETHODIMP
1482 TRRServiceChannel::GetDomainLookupStart(TimeStamp* _retval) {
1483 if (mTransaction) {
1484 *_retval = mTransaction->GetDomainLookupStart();
1485 } else {
1486 *_retval = mTransactionTimings.domainLookupStart;
1488 return NS_OK;
1491 NS_IMETHODIMP
1492 TRRServiceChannel::GetDomainLookupEnd(TimeStamp* _retval) {
1493 if (mTransaction) {
1494 *_retval = mTransaction->GetDomainLookupEnd();
1495 } else {
1496 *_retval = mTransactionTimings.domainLookupEnd;
1498 return NS_OK;
1501 NS_IMETHODIMP
1502 TRRServiceChannel::GetConnectStart(TimeStamp* _retval) {
1503 if (mTransaction) {
1504 *_retval = mTransaction->GetConnectStart();
1505 } else {
1506 *_retval = mTransactionTimings.connectStart;
1508 return NS_OK;
1511 NS_IMETHODIMP
1512 TRRServiceChannel::GetTcpConnectEnd(TimeStamp* _retval) {
1513 if (mTransaction) {
1514 *_retval = mTransaction->GetTcpConnectEnd();
1515 } else {
1516 *_retval = mTransactionTimings.tcpConnectEnd;
1518 return NS_OK;
1521 NS_IMETHODIMP
1522 TRRServiceChannel::GetSecureConnectionStart(TimeStamp* _retval) {
1523 if (mTransaction) {
1524 *_retval = mTransaction->GetSecureConnectionStart();
1525 } else {
1526 *_retval = mTransactionTimings.secureConnectionStart;
1528 return NS_OK;
1531 NS_IMETHODIMP
1532 TRRServiceChannel::GetConnectEnd(TimeStamp* _retval) {
1533 if (mTransaction) {
1534 *_retval = mTransaction->GetConnectEnd();
1535 } else {
1536 *_retval = mTransactionTimings.connectEnd;
1538 return NS_OK;
1541 NS_IMETHODIMP
1542 TRRServiceChannel::GetRequestStart(TimeStamp* _retval) {
1543 if (mTransaction) {
1544 *_retval = mTransaction->GetRequestStart();
1545 } else {
1546 *_retval = mTransactionTimings.requestStart;
1548 return NS_OK;
1551 NS_IMETHODIMP
1552 TRRServiceChannel::GetResponseStart(TimeStamp* _retval) {
1553 if (mTransaction) {
1554 *_retval = mTransaction->GetResponseStart();
1555 } else {
1556 *_retval = mTransactionTimings.responseStart;
1558 return NS_OK;
1561 NS_IMETHODIMP
1562 TRRServiceChannel::GetResponseEnd(TimeStamp* _retval) {
1563 if (mTransaction) {
1564 *_retval = mTransaction->GetResponseEnd();
1565 } else {
1566 *_retval = mTransactionTimings.responseEnd;
1568 return NS_OK;
1571 NS_IMETHODIMP TRRServiceChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) {
1572 return NS_OK;
1575 NS_IMETHODIMP
1576 TRRServiceChannel::TimingAllowCheck(nsIPrincipal* aOrigin, bool* aResult) {
1577 NS_ENSURE_ARG_POINTER(aResult);
1578 *aResult = true;
1579 return NS_OK;
1582 bool TRRServiceChannel::SameOriginWithOriginalUri(nsIURI* aURI) { return true; }
1584 } // namespace mozilla::net