Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp
Warning:line 10357, column 12
Value stored to 'rv' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_protocol_http4.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/netwerk/protocol/http -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/netwerk/protocol/http -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/netwerk/protocol/http -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/base -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/cookie -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/dns -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/ipc -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/socket/neqo_glue -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/url-classifier -I /var/lib/jenkins/workspace/firefox-scan-build/extensions/auth -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/x86_64-linux-gnu/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-16-034744-15991-1 -x c++ Unified_cpp_protocol_http4.cpp
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim:set expandtab ts=4 sw=2 sts=2 cin: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7// HttpLog.h should generally be included first
8#include "HttpLog.h"
9
10#include <inttypes.h>
11
12#include "mozilla/ScopeExit.h"
13#include "mozilla/Sprintf.h"
14#include "mozilla/dom/nsCSPContext.h"
15#include "mozilla/glean/GleanMetrics.h"
16#include "mozilla/StoragePrincipalHelper.h"
17
18#include "nsCOMPtr.h"
19#include "nsContentSecurityUtils.h"
20#include "nsHttp.h"
21#include "nsHttpChannel.h"
22#include "nsHttpChannelAuthProvider.h"
23#include "nsHttpHandler.h"
24#include "nsIStreamConverter.h"
25#include "nsString.h"
26#include "nsICacheStorageService.h"
27#include "nsICacheStorage.h"
28#include "nsICacheEntry.h"
29#include "nsICryptoHash.h"
30#include "nsIEffectiveTLDService.h"
31#include "nsIHttpHeaderVisitor.h"
32#include "nsINetworkInterceptController.h"
33#include "nsIStringBundle.h"
34#include "nsIStreamListenerTee.h"
35#include "nsISeekableStream.h"
36#include "nsIProtocolProxyService2.h"
37#include "nsIURLQueryStringStripper.h"
38#include "nsIWebTransport.h"
39#include "nsCRT.h"
40#include "nsMimeTypes.h"
41#include "nsNetCID.h"
42#include "nsNetUtil.h"
43#include "nsIStreamTransportService.h"
44#include "prnetdb.h"
45#include "nsEscape.h"
46#include "nsComponentManagerUtils.h"
47#include "nsStreamUtils.h"
48#include "nsIOService.h"
49#include "nsDNSPrefetch.h"
50#include "nsChannelClassifier.h"
51#include "nsIRedirectResultListener.h"
52#include "mozilla/TimeStamp.h"
53#include "nsError.h"
54#include "nsPrintfCString.h"
55#include "nsAlgorithm.h"
56#include "nsQueryObject.h"
57#include "nsThreadUtils.h"
58#include "nsIConsoleService.h"
59#include "mozilla/AntiTrackingRedirectHeuristic.h"
60#include "mozilla/AntiTrackingUtils.h"
61#include "mozilla/Attributes.h"
62#include "mozilla/BasePrincipal.h"
63#include "mozilla/DebugOnly.h"
64#include "mozilla/PerfStats.h"
65#include "mozilla/ProfilerLabels.h"
66#include "mozilla/Components.h"
67#include "mozilla/StaticPrefs_network.h"
68#include "mozilla/StaticPrefs_privacy.h"
69#include "mozilla/StaticPrefs_security.h"
70#include "sslt.h"
71#include "nsCharSeparatedTokenizer.h"
72#include "nsContentUtils.h"
73#include "nsContentSecurityManager.h"
74#include "nsIClassOfService.h"
75#include "nsIPrincipal.h"
76#include "nsIScriptError.h"
77#include "nsIScriptSecurityManager.h"
78#include "nsITransportSecurityInfo.h"
79#include "nsIWebProgressListener.h"
80#include "LoadContextInfo.h"
81#include "netCore.h"
82#include "nsHttpTransaction.h"
83#include "nsICancelable.h"
84#include "nsIHttpChannelInternal.h"
85#include "nsIPrompt.h"
86#include "nsInputStreamPump.h"
87#include "nsURLHelper.h"
88#include "nsISocketTransport.h"
89#include "nsIStreamConverterService.h"
90#include "nsISiteSecurityService.h"
91#include "nsString.h"
92#include "mozilla/dom/PerformanceStorage.h"
93#include "mozilla/dom/ReferrerInfo.h"
94#include "mozilla/Telemetry.h"
95#include "AlternateServices.h"
96#include "NetworkMarker.h"
97#include "nsIHttpPushListener.h"
98#include "nsIDNSRecord.h"
99#include "mozilla/dom/Document.h"
100#include "nsICompressConvStats.h"
101#include "nsCORSListenerProxy.h"
102#include "nsISocketProvider.h"
103#include "mozilla/extensions/StreamFilterParent.h"
104#include "mozilla/net/Predictor.h"
105#include "mozilla/MathAlgorithms.h"
106#include "mozilla/NullPrincipal.h"
107#include "CacheControlParser.h"
108#include "nsMixedContentBlocker.h"
109#include "CacheStorageService.h"
110#include "HttpChannelParent.h"
111#include "HttpTransactionParent.h"
112#include "ThirdPartyUtil.h"
113#include "InterceptedHttpChannel.h"
114#include "../../cache2/CacheFileUtils.h"
115#include "nsINetworkLinkService.h"
116#include "mozilla/ContentBlockingAllowList.h"
117#include "mozilla/dom/ServiceWorkerUtils.h"
118#include "mozilla/dom/nsHTTPSOnlyStreamListener.h"
119#include "mozilla/dom/nsHTTPSOnlyUtils.h"
120#include "mozilla/net/AsyncUrlChannelClassifier.h"
121#include "mozilla/net/CookieJarSettings.h"
122#include "mozilla/net/NeckoChannelParams.h"
123#include "mozilla/net/OpaqueResponseUtils.h"
124#include "mozilla/net/UrlClassifierFeatureFactory.h"
125#include "HttpTrafficAnalyzer.h"
126#include "mozilla/net/SocketProcessParent.h"
127#include "mozilla/dom/SecFetch.h"
128#include "mozilla/net/TRRService.h"
129#include "nsUnknownDecoder.h"
130#ifdef XP_WIN
131# include "HttpWinUtils.h"
132#endif
133#ifdef FUZZING
134# include "mozilla/StaticPrefs_fuzzing.h"
135#endif
136
137namespace mozilla {
138
139using namespace dom;
140
141namespace net {
142
143namespace {
144
145// True if the local cache should be bypassed when processing a request.
146#define BYPASS_LOCAL_CACHE(loadFlags, isPreferCacheLoadOverBypass)((loadFlags) & (nsIRequest::LOAD_BYPASS_CACHE | nsICachingChannel
::LOAD_BYPASS_LOCAL_CACHE) && !(((loadFlags) & nsIRequest
::LOAD_FROM_CACHE) && (isPreferCacheLoadOverBypass)))
\
147 ((loadFlags) & (nsIRequest::LOAD_BYPASS_CACHE | \
148 nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE) && \
149 !(((loadFlags) & nsIRequest::LOAD_FROM_CACHE) && \
150 (isPreferCacheLoadOverBypass)))
151
152#define RECOVER_FROM_CACHE_FILE_ERROR(result)((result) == NS_ERROR_FILE_NOT_FOUND || (result) == NS_ERROR_FILE_CORRUPTED
|| (result) == NS_ERROR_OUT_OF_MEMORY)
\
153 ((result) == NS_ERROR_FILE_NOT_FOUND || \
154 (result) == NS_ERROR_FILE_CORRUPTED || (result) == NS_ERROR_OUT_OF_MEMORY)
155
156#define WRONG_RACING_RESPONSE_SOURCE(req)(mRaceCacheWithNetwork && (((mFirstResponseSource == RESPONSE_FROM_CACHE
) && ((req) != mCachePump)) || ((mFirstResponseSource
== RESPONSE_FROM_NETWORK) && ((req) != mTransactionPump
))))
\
157 (mRaceCacheWithNetwork && \
158 (((mFirstResponseSource == RESPONSE_FROM_CACHE) && \
159 ((req) != mCachePump)) || \
160 ((mFirstResponseSource == RESPONSE_FROM_NETWORK) && \
161 ((req) != mTransactionPump))))
162
163static NS_DEFINE_CID(kStreamListenerTeeCID, NS_STREAMLISTENERTEE_CID)const nsCID kStreamListenerTeeCID = { 0x831f8f13, 0x7aa8, 0x485f
, { 0xb0, 0x2e, 0x77, 0xc8, 0x81, 0xcc, 0x57, 0x73 } }
;
164
165void AccumulateCacheHitTelemetry(CacheDisposition hitOrMiss,
166 nsIChannel* aChannel) {
167 nsCString key("UNKNOWN");
168
169 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
170
171 nsAutoCString contentType;
172 if (NS_SUCCEEDED(aChannel->GetContentType(contentType))((bool)(__builtin_expect(!!(!NS_FAILED_impl(aChannel->GetContentType
(contentType))), 1)))
) {
173 if (nsContentUtils::IsJavascriptMIMEType(
174 NS_ConvertUTF8toUTF16(contentType))) {
175 key.AssignLiteral("JAVASCRIPT");
176 } else if (StringBeginsWith(contentType, "text/css"_ns) ||
177 (loadInfo && loadInfo->GetExternalContentPolicyType() ==
178 ExtContentPolicy::TYPE_STYLESHEET)) {
179 key.AssignLiteral("STYLESHEET");
180 } else if (StringBeginsWith(contentType, "application/wasm"_ns)) {
181 key.AssignLiteral("WASM");
182 } else if (StringBeginsWith(contentType, "image/"_ns)) {
183 key.AssignLiteral("IMAGE");
184 } else if (StringBeginsWith(contentType, "video/"_ns)) {
185 key.AssignLiteral("MEDIA");
186 } else if (StringBeginsWith(contentType, "audio/"_ns)) {
187 key.AssignLiteral("MEDIA");
188 } else if (!StringBeginsWith(contentType,
189 nsLiteralCString(UNKNOWN_CONTENT_TYPE"application/x-unknown-content-type"))) {
190 key.AssignLiteral("OTHER");
191 }
192 }
193
194 Telemetry::LABELS_HTTP_CACHE_DISPOSITION_3 label =
195 Telemetry::LABELS_HTTP_CACHE_DISPOSITION_3::Unresolved;
196 switch (hitOrMiss) {
197 case kCacheUnresolved:
198 label = Telemetry::LABELS_HTTP_CACHE_DISPOSITION_3::Unresolved;
199 break;
200 case kCacheHit:
201 label = Telemetry::LABELS_HTTP_CACHE_DISPOSITION_3::Hit;
202 break;
203 case kCacheHitViaReval:
204 label = Telemetry::LABELS_HTTP_CACHE_DISPOSITION_3::HitViaReval;
205 break;
206 case kCacheMissedViaReval:
207 label = Telemetry::LABELS_HTTP_CACHE_DISPOSITION_3::MissedViaReval;
208 break;
209 case kCacheMissed:
210 label = Telemetry::LABELS_HTTP_CACHE_DISPOSITION_3::Missed;
211 break;
212 case kCacheUnknown:
213 label = Telemetry::LABELS_HTTP_CACHE_DISPOSITION_3::Unknown;
214 break;
215 }
216
217 Telemetry::AccumulateCategoricalKeyed(key, label);
218 Telemetry::AccumulateCategoricalKeyed("ALL"_ns, label);
219}
220
221// Computes and returns a SHA1 hash of the input buffer. The input buffer
222// must be a null-terminated string.
223nsresult Hash(const char* buf, nsACString& hash) {
224 nsresult rv;
225
226 nsCOMPtr<nsICryptoHash> hasher =
227 do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID"@mozilla.org/security/hash;1", &rv);
228 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 228); return rv; } } while (false)
;
229
230 rv = hasher->Init(nsICryptoHash::SHA1);
231 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 231); return rv; } } while (false)
;
232
233 rv = hasher->Update(reinterpret_cast<unsigned const char*>(buf), strlen(buf));
234 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 234); return rv; } } while (false)
;
235
236 rv = hasher->Finish(true, hash);
237 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 237); return rv; } } while (false)
;
238
239 return NS_OK;
240}
241
242} // unnamed namespace
243
244// We only treat 3xx responses as redirects if they have a Location header and
245// the status code is in a whitelist.
246bool nsHttpChannel::WillRedirect(const nsHttpResponseHead& response) {
247 return IsRedirectStatus(response.Status()) &&
248 response.HasHeader(nsHttp::Location);
249}
250
251nsresult StoreAuthorizationMetaData(nsICacheEntry* entry,
252 nsHttpRequestHead* requestHead);
253
254class MOZ_STACK_CLASS AutoRedirectVetoNotifier {
255 public:
256 explicit AutoRedirectVetoNotifier(nsHttpChannel* channel, nsresult& aRv)
257 : mChannel(channel), mRv(aRv) {
258 if (mChannel->LoadHasAutoRedirectVetoNotifier()) {
259 MOZ_CRASH("Nested AutoRedirectVetoNotifier on the stack")do { do { } while (false); MOZ_ReportCrash("" "Nested AutoRedirectVetoNotifier on the stack"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 259); AnnotateMozCrashReason("MOZ_CRASH(" "Nested AutoRedirectVetoNotifier on the stack"
")"); do { *((volatile int*)__null) = 259; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
260 mChannel = nullptr;
261 return;
262 }
263
264 mChannel->StoreHasAutoRedirectVetoNotifier(true);
265 }
266 ~AutoRedirectVetoNotifier() { ReportRedirectResult(mRv); }
267 void RedirectSucceeded() { ReportRedirectResult(NS_OK); }
268
269 private:
270 nsHttpChannel* mChannel;
271 bool mCalledReport = false;
272 nsresult& mRv;
273 void ReportRedirectResult(nsresult aRv);
274};
275
276void AutoRedirectVetoNotifier::ReportRedirectResult(nsresult aRv) {
277 if (!mChannel) return;
278
279 if (mCalledReport) {
280 return;
281 }
282 mCalledReport = true;
283
284 mChannel->mRedirectChannel = nullptr;
285
286 if (NS_SUCCEEDED(aRv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1)))) {
287 mChannel->RemoveAsNonTailRequest();
288 }
289
290 nsCOMPtr<nsIRedirectResultListener> vetoHook;
291 NS_QueryNotificationCallbacks(mChannel, NS_GET_IID(nsIRedirectResultListener)(nsIRedirectResultListener::COMTypeInfo<nsIRedirectResultListener
, void>::kIID)
,
292 getter_AddRefs(vetoHook));
293
294 nsHttpChannel* channel = mChannel;
295 mChannel = nullptr;
296
297 if (vetoHook) vetoHook->OnRedirectResult(aRv);
298
299 // Drop after the notification
300 channel->StoreHasAutoRedirectVetoNotifier(false);
301}
302
303//-----------------------------------------------------------------------------
304// nsHttpChannel <public>
305//-----------------------------------------------------------------------------
306
307nsHttpChannel::nsHttpChannel() : HttpAsyncAborter<nsHttpChannel>(this) {
308 LOG(("Creating nsHttpChannel [this=%p, nsIChannel=%p]\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Creating nsHttpChannel [this=%p, nsIChannel=%p]\n", this, static_cast
<nsIChannel*>(this)); } } while (0)
309 static_cast<nsIChannel*>(this)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Creating nsHttpChannel [this=%p, nsIChannel=%p]\n", this, static_cast
<nsIChannel*>(this)); } } while (0)
;
310 mChannelCreationTime = PR_Now();
311 mChannelCreationTimestamp = TimeStamp::Now();
312}
313
314nsHttpChannel::~nsHttpChannel() {
315 LOG(("Destroying nsHttpChannel [this=%p, nsIChannel=%p]\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Destroying nsHttpChannel [this=%p, nsIChannel=%p]\n", this
, static_cast<nsIChannel*>(this)); } } while (0)
316 static_cast<nsIChannel*>(this)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Destroying nsHttpChannel [this=%p, nsIChannel=%p]\n", this
, static_cast<nsIChannel*>(this)); } } while (0)
;
317
318 if (LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(mozilla::net::
gHttpLog, mozilla::LogLevel::Verbose)), 0))
) {
319 nsCString webExtension;
320 this->GetPropertyAsACString(u"cancelledByExtension"_ns, webExtension);
321 if (!webExtension.IsEmpty()) {
322 LOG(("channel [%p] cancelled by extension [id=%s]", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "channel [%p] cancelled by extension [id=%s]", this, webExtension
.get()); } } while (0)
323 webExtension.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "channel [%p] cancelled by extension [id=%s]", this, webExtension
.get()); } } while (0)
;
324 }
325 }
326
327 if (mAuthProvider) {
328 DebugOnly<nsresult> rv = mAuthProvider->Disconnect(NS_ERROR_ABORT);
329 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 329; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
330 }
331
332 ReleaseMainThreadOnlyReferences();
333 if (gHttpHandler) {
334 gHttpHandler->RemoveHttpChannel(mChannelId);
335 }
336}
337
338void nsHttpChannel::ReleaseMainThreadOnlyReferences() {
339 if (NS_IsMainThread()) {
340 // Already on main thread, let dtor to
341 // take care of releasing references
342 return;
343 }
344
345 nsTArray<nsCOMPtr<nsISupports>> arrayToRelease;
346 arrayToRelease.AppendElement(mAuthProvider.forget());
347 arrayToRelease.AppendElement(mRedirectChannel.forget());
348 arrayToRelease.AppendElement(mPreflightChannel.forget());
349 arrayToRelease.AppendElement(mDNSPrefetch.forget());
350
351 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mEarlyHintObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mEarlyHintObserver))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!mEarlyHintObserver"
" (" "Early hint observer should have been released in ReleaseListeners()"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 353); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mEarlyHintObserver"
") (" "Early hint observer should have been released in ReleaseListeners()"
")"); do { *((volatile int*)__null) = 353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
352 !mEarlyHintObserver,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mEarlyHintObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mEarlyHintObserver))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!mEarlyHintObserver"
" (" "Early hint observer should have been released in ReleaseListeners()"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 353); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mEarlyHintObserver"
") (" "Early hint observer should have been released in ReleaseListeners()"
")"); do { *((volatile int*)__null) = 353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
353 "Early hint observer should have been released in ReleaseListeners()")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mEarlyHintObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mEarlyHintObserver))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!mEarlyHintObserver"
" (" "Early hint observer should have been released in ReleaseListeners()"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 353); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mEarlyHintObserver"
") (" "Early hint observer should have been released in ReleaseListeners()"
")"); do { *((volatile int*)__null) = 353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
354 arrayToRelease.AppendElement(mEarlyHintObserver.forget());
355 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mChannelClassifier)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mChannelClassifier))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!mChannelClassifier"
" (" "Channel classifier should have been released in ReleaseListeners()"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 357); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mChannelClassifier"
") (" "Channel classifier should have been released in ReleaseListeners()"
")"); do { *((volatile int*)__null) = 357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
356 !mChannelClassifier,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mChannelClassifier)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mChannelClassifier))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!mChannelClassifier"
" (" "Channel classifier should have been released in ReleaseListeners()"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 357); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mChannelClassifier"
") (" "Channel classifier should have been released in ReleaseListeners()"
")"); do { *((volatile int*)__null) = 357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
357 "Channel classifier should have been released in ReleaseListeners()")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mChannelClassifier)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mChannelClassifier))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!mChannelClassifier"
" (" "Channel classifier should have been released in ReleaseListeners()"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 357); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mChannelClassifier"
") (" "Channel classifier should have been released in ReleaseListeners()"
")"); do { *((volatile int*)__null) = 357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
358 arrayToRelease.AppendElement(
359 mChannelClassifier.forget().downcast<nsIURIClassifierCallback>());
360 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mWarningReporter)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mWarningReporter))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mWarningReporter"
" (" "Warning reporter should have been released in ReleaseListeners()"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 362); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mWarningReporter"
") (" "Warning reporter should have been released in ReleaseListeners()"
")"); do { *((volatile int*)__null) = 362; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
361 !mWarningReporter,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mWarningReporter)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mWarningReporter))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mWarningReporter"
" (" "Warning reporter should have been released in ReleaseListeners()"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 362); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mWarningReporter"
") (" "Warning reporter should have been released in ReleaseListeners()"
")"); do { *((volatile int*)__null) = 362; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
362 "Warning reporter should have been released in ReleaseListeners()")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mWarningReporter)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mWarningReporter))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mWarningReporter"
" (" "Warning reporter should have been released in ReleaseListeners()"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 362); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mWarningReporter"
") (" "Warning reporter should have been released in ReleaseListeners()"
")"); do { *((volatile int*)__null) = 362; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
363 arrayToRelease.AppendElement(mWarningReporter.forget());
364
365 NS_DispatchToMainThread(new ProxyReleaseRunnable(std::move(arrayToRelease)));
366}
367
368nsresult nsHttpChannel::Init(nsIURI* uri, uint32_t caps, nsProxyInfo* proxyInfo,
369 uint32_t proxyResolveFlags, nsIURI* proxyURI,
370 uint64_t channelId,
371 ExtContentPolicyType aContentPolicyType,
372 nsILoadInfo* aLoadInfo) {
373 nsresult rv =
374 HttpBaseChannel::Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI,
375 channelId, aContentPolicyType, aLoadInfo);
376 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
377
378 LOG1(("nsHttpChannel::Init [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Error)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Error, "nsHttpChannel::Init [this=%p]\n"
, this); } } while (0)
;
379
380 return rv;
381}
382
383nsresult nsHttpChannel::AddSecurityMessage(const nsAString& aMessageTag,
384 const nsAString& aMessageCategory) {
385 if (mWarningReporter) {
386 return mWarningReporter->ReportSecurityMessage(aMessageTag,
387 aMessageCategory);
388 }
389 return HttpBaseChannel::AddSecurityMessage(aMessageTag, aMessageCategory);
390}
391
392NS_IMETHODIMPnsresult
393nsHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage,
394 const nsACString& aCategory,
395 bool aIsWarning) {
396 if (mWarningReporter) {
397 return mWarningReporter->LogBlockedCORSRequest(aMessage, aCategory,
398 aIsWarning);
399 }
400 return NS_ERROR_UNEXPECTED;
401}
402
403NS_IMETHODIMPnsresult
404nsHttpChannel::LogMimeTypeMismatch(const nsACString& aMessageName,
405 bool aWarning, const nsAString& aURL,
406 const nsAString& aContentType) {
407 if (mWarningReporter) {
408 return mWarningReporter->LogMimeTypeMismatch(aMessageName, aWarning, aURL,
409 aContentType);
410 }
411 return NS_ERROR_UNEXPECTED;
412}
413
414//-----------------------------------------------------------------------------
415// nsHttpChannel <private>
416//-----------------------------------------------------------------------------
417
418nsresult nsHttpChannel::PrepareToConnect() {
419 LOG(("nsHttpChannel::PrepareToConnect [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::PrepareToConnect [this=%p]\n", this); } } while
(0)
;
420
421 // notify "http-on-modify-request-before-cookies" observers
422 gHttpHandler->OnModifyRequestBeforeCookies(this);
423
424 AddCookiesToRequest();
425
426#ifdef XP_WIN
427
428 auto prefEnabledForCurrentContainer = [&]() {
429 uint32_t containerId = mLoadInfo->GetOriginAttributes().mUserContextId;
430 // Make sure that the default container ID is 0
431 static_assert(nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID == 0);
432 nsPrintfCString prefName("network.http.windows-sso.container-enabled.%u",
433 containerId);
434
435 bool enabled = false;
436 Preferences::GetBool(prefName.get(), &enabled);
437
438 LOG(("Pref for %s is %d\n", prefName.get(), enabled))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Pref for %s is %d\n", prefName.get(), enabled); } } while (
0)
;
439
440 return enabled;
441 };
442
443 // If Windows 10 SSO is enabled, we potentially add auth information to
444 // secure top level loads (DOCUMENTs) and iframes (SUBDOCUMENTs) that
445 // aren't anonymous or private browsing.
446 if (StaticPrefs::network_http_windows_sso_enabled() &&
447 mURI->SchemeIs("https") && !(mLoadFlags & LOAD_ANONYMOUS) &&
448 !mPrivateBrowsing) {
449 ExtContentPolicyType type = mLoadInfo->GetExternalContentPolicyType();
450 if ((type == ExtContentPolicy::TYPE_DOCUMENT ||
451 type == ExtContentPolicy::TYPE_SUBDOCUMENT) &&
452 prefEnabledForCurrentContainer()) {
453 AddWindowsSSO(this);
454 }
455 }
456#endif
457
458 // notify "http-on-modify-request" observers
459 CallOnModifyRequestObservers();
460
461 return CallOrWaitForResume(
462 [](auto* self) { return self->OnBeforeConnect(); });
463}
464
465void nsHttpChannel::HandleContinueCancellingByURLClassifier(
466 nsresult aErrorCode) {
467 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode
(aErrorCode))>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode
(aErrorCode)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(aErrorCode)"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 468); AnnotateMozCrashReason("MOZ_ASSERT" "(" "UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(aErrorCode)"
")"); do { *((volatile int*)__null) = 468; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
468 UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(aErrorCode))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode
(aErrorCode))>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode
(aErrorCode)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(aErrorCode)"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 468); AnnotateMozCrashReason("MOZ_ASSERT" "(" "UrlClassifierFeatureFactory::IsClassifierBlockingErrorCode(aErrorCode)"
")"); do { *((volatile int*)__null) = 468; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
469 MOZ_ASSERT(!mCallOnResume, "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCallOnResume)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCallOnResume))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mCallOnResume"
" (" "How did that happen?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 469); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCallOnResume"
") (" "How did that happen?" ")"); do { *((volatile int*)__null
) = 469; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
470
471 if (mSuspendCount) {
472 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume HandleContinueCancellingByURLClassifier "
"[this=%p]\n", this); } } while (0)
473 ("Waiting until resume HandleContinueCancellingByURLClassifier "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume HandleContinueCancellingByURLClassifier "
"[this=%p]\n", this); } } while (0)
474 "[this=%p]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume HandleContinueCancellingByURLClassifier "
"[this=%p]\n", this); } } while (0)
475 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume HandleContinueCancellingByURLClassifier "
"[this=%p]\n", this); } } while (0)
;
476 mCallOnResume = [aErrorCode](nsHttpChannel* self) {
477 self->HandleContinueCancellingByURLClassifier(aErrorCode);
478 return NS_OK;
479 };
480 return;
481 }
482
483 LOG(("nsHttpChannel::HandleContinueCancellingByURLClassifier [this=%p]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::HandleContinueCancellingByURLClassifier [this=%p]\n"
, this); } } while (0)
484 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::HandleContinueCancellingByURLClassifier [this=%p]\n"
, this); } } while (0)
;
485 ContinueCancellingByURLClassifier(aErrorCode);
486}
487
488void nsHttpChannel::SetPriorityHeader() {
489 uint8_t urgency = nsHttpHandler::UrgencyFromCoSFlags(mClassOfService.Flags());
490 bool incremental = mClassOfService.Incremental();
491
492 nsPrintfCString value(
493 "%s", urgency != 3 ? nsPrintfCString("u=%d", urgency).get() : "");
494
495 if (incremental) {
496 if (!value.IsEmpty()) {
497 value.Append(", ");
498 }
499 value.Append("i");
500 }
501
502 if (!value.IsEmpty()) {
503 SetRequestHeader("Priority"_ns, value, false);
504 }
505}
506
507nsresult nsHttpChannel::OnBeforeConnect() {
508 nsresult rv = NS_OK;
509
510 // Check if request was cancelled during suspend AFTER on-modify-request
511 if (mCanceled) {
512 return mStatus;
513 }
514
515 // Check to see if we should redirect this channel elsewhere by
516 // nsIHttpChannel.redirectTo API request
517 if (mAPIRedirectToURI) {
518 return AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect);
519 }
520
521 // Note that we are only setting the "Upgrade-Insecure-Requests" request
522 // header for *all* navigational requests instead of all requests as
523 // defined in the spec, see:
524 // https://www.w3.org/TR/upgrade-insecure-requests/#preference
525 ExtContentPolicyType type = mLoadInfo->GetExternalContentPolicyType();
526
527 if (type == ExtContentPolicy::TYPE_DOCUMENT ||
528 type == ExtContentPolicy::TYPE_SUBDOCUMENT) {
529 rv = SetRequestHeader("Upgrade-Insecure-Requests"_ns, "1"_ns, false);
530 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 530); return rv; } } while (false)
;
531 }
532
533 if (LoadAuthRedirectedChannel()) {
534 // This channel is a result of a redirect due to auth retry
535 // We have already checked for HSTS upgarde in the redirecting channel.
536 // We can safely skip those checks
537 return ContinueOnBeforeConnect(false, rv);
538 }
539
540 SecFetch::AddSecFetchHeader(this);
541
542 // Check to see if we should redirect this channel to the unstripped URI. To
543 // revert the query stripping if the loading channel is in the content
544 // blocking allow list.
545 if (ContentBlockingAllowList::Check(this)) {
546 nsCOMPtr<nsIURI> unstrippedURI;
547 mLoadInfo->GetUnstrippedURI(getter_AddRefs(unstrippedURI));
548
549 if (unstrippedURI) {
550 return AsyncCall(&nsHttpChannel::HandleAsyncRedirectToUnstrippedURI);
551 }
552 }
553
554 nsCOMPtr<nsIPrincipal> resultPrincipal;
555 if (!mURI->SchemeIs("https")) {
556 nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
557 this, getter_AddRefs(resultPrincipal));
558 }
559
560 // Check if we already know about the HSTS status of the host
561 nsISiteSecurityService* sss = gHttpHandler->GetSSService();
562 NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY)do { if ((__builtin_expect(!!(!(sss)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "sss" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 562); return NS_ERROR_OUT_OF_MEMORY; } } while (false)
;
563 bool isSecureURI;
564 OriginAttributes originAttributes;
565 if (!StoragePrincipalHelper::GetOriginAttributesForHSTS(this,
566 originAttributes)) {
567 return NS_ERROR_FAILURE;
568 }
569 rv = sss->IsSecureURI(mURI, originAttributes, &isSecureURI);
570 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 570); return rv; } } while (false)
;
571 // Save that on the loadInfo so it can later be consumed by
572 // SecurityInfo.sys.mjs
573 mLoadInfo->SetHstsStatus(isSecureURI);
574
575 RefPtr<mozilla::dom::BrowsingContext> bc;
576 mLoadInfo->GetBrowsingContext(getter_AddRefs(bc));
577 if (bc && bc->Top()->GetForceOffline()) {
578 return NS_ERROR_OFFLINE;
579 }
580
581 // At this point it is no longer possible to call
582 // HttpBaseChannel::UpgradeToSecure.
583 StoreUpgradableToSecure(false);
584 bool shouldUpgrade = LoadUpgradeToSecure();
585 if (mURI->SchemeIs("http")) {
586 OriginAttributes originAttributes;
587 if (!StoragePrincipalHelper::GetOriginAttributesForHSTS(this,
588 originAttributes)) {
589 return NS_ERROR_FAILURE;
590 }
591
592 if (!shouldUpgrade) {
593 // Make sure http channel is released on main thread.
594 // See bug 1539148 for details.
595 nsMainThreadPtrHandle<nsHttpChannel> self(
596 new nsMainThreadPtrHolder<nsHttpChannel>(
597 "nsHttpChannel::OnBeforeConnect::self", this));
598 auto resultCallback = [self(self)](bool aResult, nsresult aStatus) {
599 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 599); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 599; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
600
601 nsresult rv = self->MaybeUseHTTPSRRForUpgrade(aResult, aStatus);
602 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
603 self->CloseCacheEntry(false);
604 Unused << self->AsyncAbort(rv);
605 }
606 };
607
608 bool willCallback = false;
609 rv = NS_ShouldSecureUpgrade(
610 mURI, mLoadInfo, resultPrincipal, LoadAllowSTS(), originAttributes,
611 shouldUpgrade, std::move(resultCallback), willCallback);
612 // If the request gets upgraded because of the HTTPS-Only mode, but no
613 // event listener has been registered so far, we want to do that here.
614 uint32_t httpOnlyStatus = mLoadInfo->GetHttpsOnlyStatus();
615 if (httpOnlyStatus &
616 nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_NOT_REGISTERED) {
617 RefPtr<nsHTTPSOnlyStreamListener> httpsOnlyListener =
618 new nsHTTPSOnlyStreamListener(mListener, mLoadInfo);
619 mListener = httpsOnlyListener;
620
621 httpOnlyStatus ^=
622 nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_NOT_REGISTERED;
623 httpOnlyStatus |= nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_REGISTERED;
624 mLoadInfo->SetHttpsOnlyStatus(httpOnlyStatus);
625 }
626 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OnBeforeConnect " "[this=%p willCallback=%d rv=%"
"x" "]\n", this, willCallback, static_cast<uint32_t>(rv
)); } } while (0)
627 ("nsHttpChannel::OnBeforeConnect "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OnBeforeConnect " "[this=%p willCallback=%d rv=%"
"x" "]\n", this, willCallback, static_cast<uint32_t>(rv
)); } } while (0)
628 "[this=%p willCallback=%d rv=%" PRIx32 "]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OnBeforeConnect " "[this=%p willCallback=%d rv=%"
"x" "]\n", this, willCallback, static_cast<uint32_t>(rv
)); } } while (0)
629 this, willCallback, static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OnBeforeConnect " "[this=%p willCallback=%d rv=%"
"x" "]\n", this, willCallback, static_cast<uint32_t>(rv
)); } } while (0)
;
630
631 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || MOZ_UNLIKELY(willCallback)(__builtin_expect(!!(willCallback), 0))) {
632 return rv;
633 }
634 }
635 }
636
637 return MaybeUseHTTPSRRForUpgrade(shouldUpgrade, NS_OK);
638}
639
640// Returns true if the network connectivity checker indicated
641// that HTTPS records can be resolved on this network - false otherwise.
642// When TRR is enabled, we always return true, as resolving HTTPS
643// records don't depend on the network.
644static bool canUseHTTPSRRonNetwork() {
645 if (nsCOMPtr<nsIDNSService> dns = mozilla::components::DNS::Service()) {
646 nsIDNSService::ResolverMode mode;
647 // If the browser is currently using TRR/DoH, then it can
648 // definitely resolve HTTPS records.
649 if (NS_SUCCEEDED(dns->GetCurrentTrrMode(&mode))((bool)(__builtin_expect(!!(!NS_FAILED_impl(dns->GetCurrentTrrMode
(&mode))), 1)))
&&
650 (mode == nsIDNSService::MODE_TRRFIRST ||
651 mode == nsIDNSService::MODE_TRRONLY)) {
652 return true;
653 }
654 }
655 if (RefPtr<NetworkConnectivityService> ncs =
656 NetworkConnectivityService::GetSingleton()) {
657 nsINetworkConnectivityService::ConnectivityState state;
658 if (NS_SUCCEEDED(ncs->GetDNS_HTTPS(&state))((bool)(__builtin_expect(!!(!NS_FAILED_impl(ncs->GetDNS_HTTPS
(&state))), 1)))
&&
659 state == nsINetworkConnectivityService::NOT_AVAILABLE) {
660 return false;
661 }
662 }
663 return true;
664}
665
666nsresult nsHttpChannel::MaybeUseHTTPSRRForUpgrade(bool aShouldUpgrade,
667 nsresult aStatus) {
668 if (NS_FAILED(aStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(aStatus)), 0)))) {
669 return aStatus;
670 }
671
672 if (mURI->SchemeIs("https") || aShouldUpgrade || !LoadUseHTTPSSVC()) {
673 return ContinueOnBeforeConnect(aShouldUpgrade, aStatus);
674 }
675
676 auto shouldSkipUpgradeWithHTTPSRR = [&]() -> bool {
677 // Skip using HTTPS RR to upgrade when this is not a top-level load and the
678 // loading principal is http.
679 if ((mLoadInfo->GetExternalContentPolicyType() !=
680 ExtContentPolicy::TYPE_DOCUMENT) &&
681 (mLoadInfo->GetLoadingPrincipal() &&
682 mLoadInfo->GetLoadingPrincipal()->SchemeIs("http"))) {
683 return true;
684 }
685
686 // If the network connectivity checker indicates the network is
687 // blocking HTTPS requests, then we should skip them so we don't
688 // needlessly wait for a timeout.
689 if (!canUseHTTPSRRonNetwork()) {
690 return true;
691 }
692
693 nsAutoCString uriHost;
694 mURI->GetAsciiHost(uriHost);
695
696 if (gHttpHandler->IsHostExcludedForHTTPSRR(uriHost)) {
697 return true;
698 }
699
700 if (nsHTTPSOnlyUtils::IsUpgradeDowngradeEndlessLoop(
701 mURI, mLoadInfo,
702 {nsHTTPSOnlyUtils::UpgradeDowngradeEndlessLoopOptions::
703 EnforceForHTTPSRR})) {
704 // Add the host to a excluded list because:
705 // 1. We don't need to do the same check again.
706 // 2. Other subresources in the same host will be also excluded.
707 gHttpHandler->ExcludeHTTPSRRHost(uriHost);
708 LOG(("[%p] skip HTTPS upgrade for host [%s]", this, uriHost.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "[%p] skip HTTPS upgrade for host [%s]", this, uriHost.get(
)); } } while (0)
;
709 return true;
710 }
711
712 return false;
713 };
714
715 if (shouldSkipUpgradeWithHTTPSRR()) {
716 StoreUseHTTPSSVC(false);
717 // If the website does not want to use HTTPS RR, we should set
718 // NS_HTTP_DISALLOW_HTTPS_RR. This is for avoiding HTTPS RR being used by
719 // the transaction.
720 mCaps |= NS_HTTP_DISALLOW_HTTPS_RR(1 << 24);
721 return ContinueOnBeforeConnect(aShouldUpgrade, aStatus);
722 }
723
724 if (mHTTPSSVCRecord.isSome()) {
725 LOG((do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::MaybeUseHTTPSRRForUpgrade [%p] mHTTPSSVCRecord is some"
, this); } } while (0)
726 "nsHttpChannel::MaybeUseHTTPSRRForUpgrade [%p] mHTTPSSVCRecord is some",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::MaybeUseHTTPSRRForUpgrade [%p] mHTTPSSVCRecord is some"
, this); } } while (0)
727 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::MaybeUseHTTPSRRForUpgrade [%p] mHTTPSSVCRecord is some"
, this); } } while (0)
;
728 StoreWaitHTTPSSVCRecord(false);
729 bool hasHTTPSRR = (mHTTPSSVCRecord.ref() != nullptr);
730 return ContinueOnBeforeConnect(hasHTTPSRR, aStatus, hasHTTPSRR);
731 }
732
733 auto dnsStrategy = GetProxyDNSStrategy();
734 if (!(dnsStrategy & DNS_PREFETCH_ORIGIN)) {
735 return ContinueOnBeforeConnect(aShouldUpgrade, aStatus);
736 }
737
738 LOG(("nsHttpChannel::MaybeUseHTTPSRRForUpgrade [%p] wait for HTTPS RR",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::MaybeUseHTTPSRRForUpgrade [%p] wait for HTTPS RR"
, this); } } while (0)
739 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::MaybeUseHTTPSRRForUpgrade [%p] wait for HTTPS RR"
, this); } } while (0)
;
740
741 OriginAttributes originAttributes;
742 StoragePrincipalHelper::GetOriginAttributesForHTTPSRR(this, originAttributes);
743
744 RefPtr<nsDNSPrefetch> resolver =
745 new nsDNSPrefetch(mURI, originAttributes, nsIRequest::GetTRRMode());
746 nsWeakPtr weakPtrThis(
747 do_GetWeakReference(static_cast<nsIHttpChannel*>(this)));
748 nsresult rv = resolver->FetchHTTPSSVC(
749 mCaps & NS_HTTP_REFRESH_DNS(1 << 3), !LoadUseHTTPSSVC(),
750 [weakPtrThis](nsIDNSHTTPSSVCRecord* aRecord) {
751 nsCOMPtr<nsIHttpChannel> channel = do_QueryReferent(weakPtrThis);
752 RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(channel);
753 if (httpChannelImpl) {
754 httpChannelImpl->OnHTTPSRRAvailable(aRecord);
755 }
756 });
757 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
758 LOG((" FetchHTTPSSVC failed with 0x%08" PRIx32,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " FetchHTTPSSVC failed with 0x%08" "x", static_cast<uint32_t
>(rv)); } } while (0)
759 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " FetchHTTPSSVC failed with 0x%08" "x", static_cast<uint32_t
>(rv)); } } while (0)
;
760 return ContinueOnBeforeConnect(aShouldUpgrade, aStatus);
761 }
762
763 StoreWaitHTTPSSVCRecord(true);
764 return NS_OK;
765}
766
767nsresult nsHttpChannel::ContinueOnBeforeConnect(bool aShouldUpgrade,
768 nsresult aStatus,
769 bool aUpgradeWithHTTPSRR) {
770 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueOnBeforeConnect " "[this=%p aShouldUpgrade=%d rv=%"
"x" "]\n", this, aShouldUpgrade, static_cast<uint32_t>
(aStatus)); } } while (0)
771 ("nsHttpChannel::ContinueOnBeforeConnect "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueOnBeforeConnect " "[this=%p aShouldUpgrade=%d rv=%"
"x" "]\n", this, aShouldUpgrade, static_cast<uint32_t>
(aStatus)); } } while (0)
772 "[this=%p aShouldUpgrade=%d rv=%" PRIx32 "]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueOnBeforeConnect " "[this=%p aShouldUpgrade=%d rv=%"
"x" "]\n", this, aShouldUpgrade, static_cast<uint32_t>
(aStatus)); } } while (0)
773 this, aShouldUpgrade, static_cast<uint32_t>(aStatus)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueOnBeforeConnect " "[this=%p aShouldUpgrade=%d rv=%"
"x" "]\n", this, aShouldUpgrade, static_cast<uint32_t>
(aStatus)); } } while (0)
;
774
775 MOZ_ASSERT(!LoadWaitHTTPSSVCRecord())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadWaitHTTPSSVCRecord())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!LoadWaitHTTPSSVCRecord())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!LoadWaitHTTPSSVCRecord()"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 775); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!LoadWaitHTTPSSVCRecord()"
")"); do { *((volatile int*)__null) = 775; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
776
777 if (NS_FAILED(aStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(aStatus)), 0)))) {
778 return aStatus;
779 }
780
781 if (aShouldUpgrade && !mURI->SchemeIs("https")) {
782 mozilla::glean::networking::https_upgrade_with_https_rr
783 .Get(aUpgradeWithHTTPSRR ? "https_rr"_ns : "others"_ns)
784 .Add(1);
785 return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
786 }
787
788 // ensure that we are using a valid hostname
789 if (!net_IsValidHostName(nsDependentCString(mConnectionInfo->Origin()))) {
790 return NS_ERROR_UNKNOWN_HOST;
791 }
792
793 if (mUpgradeProtocolCallback) {
794 // Websockets can run over HTTP/2, but other upgrades can't.
795 if (mUpgradeProtocol.EqualsLiteral("websocket") &&
796 StaticPrefs::network_http_http2_websockets()) {
797 // Need to tell the conn manager that we're ok with http/2 even with
798 // the allow keepalive bit not set. That bit needs to stay off,
799 // though, in case we end up having to fallback to http/1.1 (where
800 // we absolutely do want to disable keepalive).
801 mCaps |= NS_HTTP_ALLOW_SPDY_WITHOUT_KEEPALIVE(1 << 15);
802 } else {
803 mCaps |= NS_HTTP_DISALLOW_SPDY(1 << 7);
804 }
805 // Upgrades cannot use HTTP/3.
806 mCaps |= NS_HTTP_DISALLOW_HTTP3(1 << 21);
807 // Because NS_HTTP_STICKY_CONNECTION breaks HTTPS RR fallabck mecnahism, we
808 // can not use HTTPS RR for upgrade requests.
809 mCaps |= NS_HTTP_DISALLOW_HTTPS_RR(1 << 24);
810 }
811
812 if (LoadIsTRRServiceChannel()) {
813 mCaps |= NS_HTTP_LARGE_KEEPALIVE(1 << 1);
814 mCaps |= NS_HTTP_DISALLOW_HTTPS_RR(1 << 24);
815 }
816
817 if (mTransactionSticky) {
818 MOZ_ASSERT(LoadAuthRedirectedChannel())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(LoadAuthRedirectedChannel())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(LoadAuthRedirectedChannel())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("LoadAuthRedirectedChannel()"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 818); AnnotateMozCrashReason("MOZ_ASSERT" "(" "LoadAuthRedirectedChannel()"
")"); do { *((volatile int*)__null) = 818; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
819 // this means this is a redirected channel channel due to auth retry and a
820 // connection based auth scheme was used
821 // we have a reference to the old-transaction with sticky connection which
822 // we need to use
823 mCaps |= NS_HTTP_STICKY_CONNECTION(1 << 2);
824 }
825
826 mCaps |= NS_HTTP_TRR_FLAGS_FROM_MODE(nsIRequest::GetTRRMode())((static_cast<uint32_t>(nsIRequest::GetTRRMode()) &
3) << 19)
;
827
828 // Finalize ConnectionInfo flags before SpeculativeConnect
829 mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0);
830 mConnectionInfo->SetPrivate(mPrivateBrowsing);
831 mConnectionInfo->SetNoSpdy(mCaps & NS_HTTP_DISALLOW_SPDY(1 << 7));
832 mConnectionInfo->SetBeConservative((mCaps & NS_HTTP_BE_CONSERVATIVE(1 << 11)) ||
833 LoadBeConservative());
834 mConnectionInfo->SetTlsFlags(mTlsFlags);
835 mConnectionInfo->SetIsTrrServiceChannel(LoadIsTRRServiceChannel());
836 mConnectionInfo->SetTRRMode(nsIRequest::GetTRRMode());
837 mConnectionInfo->SetIPv4Disabled(mCaps & NS_HTTP_DISABLE_IPV4(1 << 17));
838 mConnectionInfo->SetIPv6Disabled(mCaps & NS_HTTP_DISABLE_IPV6(1 << 18));
839 mConnectionInfo->SetAnonymousAllowClientCert(
840 (mLoadFlags & LOAD_ANONYMOUS_ALLOW_CLIENT_CERT) != 0);
841
842 if (mWebTransportSessionEventListener) {
843 nsTArray<RefPtr<nsIWebTransportHash>> aServerCertHashes;
844 nsresult rv;
845 nsCOMPtr<WebTransportConnectionSettings> wtconSettings =
846 do_QueryInterface(mWebTransportSessionEventListener, &rv);
847 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 847); return rv; } } while (false)
;
848
849 wtconSettings->GetServerCertificateHashes(aServerCertHashes);
850 gHttpHandler->ConnMgr()->StoreServerCertHashes(
851 mConnectionInfo, gHttpHandler->IsHttp2Excluded(mConnectionInfo),
852 !Http3Allowed(), std::move(aServerCertHashes));
853 }
854
855 // notify "http-on-before-connect" observers
856 gHttpHandler->OnBeforeConnect(this);
857
858 return CallOrWaitForResume([](auto* self) { return self->Connect(); });
859}
860
861nsresult nsHttpChannel::Connect() {
862 LOG(("nsHttpChannel::Connect [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::Connect [this=%p]\n", this); } } while (0)
;
863
864 // Don't allow resuming when cache must be used
865 if (LoadResuming() && (mLoadFlags & LOAD_ONLY_FROM_CACHE)) {
866 LOG(("Resuming from cache is not supported yet"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Resuming from cache is not supported yet"); } } while (0)
;
867 return NS_ERROR_DOCUMENT_NOT_CACHED;
868 }
869
870 if (ShouldIntercept()) {
871 return RedirectToInterceptedChannel();
872 }
873
874 // Step 8.18 of HTTP-network-or-cache fetch
875 // https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
876 nsAutoCString rangeVal;
877 if (NS_SUCCEEDED(GetRequestHeader("Range"_ns, rangeVal))((bool)(__builtin_expect(!!(!NS_FAILED_impl(GetRequestHeader(
"Range"_ns, rangeVal))), 1)))
) {
878 SetRequestHeader("Accept-Encoding"_ns, "identity"_ns, true);
879 }
880
881 bool isTrackingResource = IsThirdPartyTrackingResource();
882 LOG(("nsHttpChannel %p tracking resource=%d, cos=%lu, inc=%d", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel %p tracking resource=%d, cos=%lu, inc=%d", this
, isTrackingResource, mClassOfService.Flags(), mClassOfService
.Incremental()); } } while (0)
883 isTrackingResource, mClassOfService.Flags(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel %p tracking resource=%d, cos=%lu, inc=%d", this
, isTrackingResource, mClassOfService.Flags(), mClassOfService
.Incremental()); } } while (0)
884 mClassOfService.Incremental()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel %p tracking resource=%d, cos=%lu, inc=%d", this
, isTrackingResource, mClassOfService.Flags(), mClassOfService
.Incremental()); } } while (0)
;
885
886 if (isTrackingResource) {
887 AddClassFlags(nsIClassOfService::Tail);
888 }
889
890 if (WaitingForTailUnblock()) {
891 MOZ_DIAGNOSTIC_ASSERT(!mOnTailUnblock)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mOnTailUnblock)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mOnTailUnblock))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mOnTailUnblock"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 891); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mOnTailUnblock"
")"); do { *((volatile int*)__null) = 891; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
892 mOnTailUnblock = &nsHttpChannel::ConnectOnTailUnblock;
893 return NS_OK;
894 }
895
896 return ConnectOnTailUnblock();
897}
898
899nsresult nsHttpChannel::ConnectOnTailUnblock() {
900 nsresult rv;
901
902 LOG(("nsHttpChannel::ConnectOnTailUnblock [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ConnectOnTailUnblock [this=%p]\n", this); }
} while (0)
;
903
904 // Consider opening a TCP connection right away.
905 SpeculativeConnect();
906
907 // open a cache entry for this channel...
908 rv = OpenCacheEntry(mURI->SchemeIs("https"));
909
910 // do not continue if asyncOpenCacheEntry is in progress
911 if (AwaitingCacheCallbacks()) {
912 LOG(("nsHttpChannel::Connect %p AwaitingCacheCallbacks forces async\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::Connect %p AwaitingCacheCallbacks forces async\n"
, this); } } while (0)
913 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::Connect %p AwaitingCacheCallbacks forces async\n"
, this); } } while (0)
;
914 MOZ_ASSERT(NS_SUCCEEDED(rv), "Unexpected state")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " ("
"Unexpected state" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 914); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "Unexpected state" ")"); do { *((volatile int*)__null)
= 914; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
915
916 if (mNetworkTriggered && mWaitingForProxy) {
917 // Someone has called TriggerNetwork(), meaning we are racing the
918 // network with the cache.
919 mWaitingForProxy = false;
920 return ContinueConnect();
921 }
922
923 return NS_OK;
924 }
925
926 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
927 LOG(("OpenCacheEntry failed [rv=%" PRIx32 "]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "OpenCacheEntry failed [rv=%" "x" "]\n", static_cast<uint32_t
>(rv)); } } while (0)
928 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "OpenCacheEntry failed [rv=%" "x" "]\n", static_cast<uint32_t
>(rv)); } } while (0)
;
929 // if this channel is only allowed to pull from the cache, then
930 // we must fail if we were unable to open a cache entry.
931 if (mLoadFlags & LOAD_ONLY_FROM_CACHE) {
932 return NS_ERROR_DOCUMENT_NOT_CACHED;
933 }
934 // otherwise, let's just proceed without using the cache.
935 }
936
937 if (mRaceCacheWithNetwork && ((mCacheEntry && !mCachedContentIsValid &&
938 (mDidReval || LoadCachedContentIsPartial())) ||
939 mIgnoreCacheEntry)) {
940 // We won't send the conditional request because the unconditional
941 // request was already sent (see bug 1377223).
942 AccumulateCategorical(
943 Telemetry::LABELS_NETWORK_RACE_CACHE_VALIDATION::NotSent);
944 }
945
946 // When racing, if OnCacheEntryAvailable is called before AsyncOpenURI
947 // returns, then we may not have started reading from the cache.
948 // If the content is valid, we should attempt to do so, as technically the
949 // cache has won the race.
950 if (mRaceCacheWithNetwork && mCachedContentIsValid) {
951 Unused << ReadFromCache(true);
952 }
953
954 return TriggerNetwork();
955}
956
957nsresult nsHttpChannel::ContinueConnect() {
958 // If we need to start a CORS preflight, do it now!
959 // Note that it is important to do this before the early returns below.
960 if (!LoadIsCorsPreflightDone() && LoadRequireCORSPreflight()) {
961 MOZ_ASSERT(!mPreflightChannel)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPreflightChannel)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mPreflightChannel))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mPreflightChannel"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 961); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mPreflightChannel"
")"); do { *((volatile int*)__null) = 961; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
962 nsresult rv = nsCORSListenerProxy::StartCORSPreflight(
963 this, this, mUnsafeHeaders, getter_AddRefs(mPreflightChannel));
964 return rv;
965 }
966
967 MOZ_RELEASE_ASSERT(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()" " ("
"CORS preflight must have been finished by the time we " "do the rest of ContinueConnect"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 969); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()"
") (" "CORS preflight must have been finished by the time we "
"do the rest of ContinueConnect" ")"); do { *((volatile int*
)__null) = 969; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
968 "CORS preflight must have been finished by the time we "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()" " ("
"CORS preflight must have been finished by the time we " "do the rest of ContinueConnect"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 969); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()"
") (" "CORS preflight must have been finished by the time we "
"do the rest of ContinueConnect" ")"); do { *((volatile int*
)__null) = 969; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
969 "do the rest of ContinueConnect")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()" " ("
"CORS preflight must have been finished by the time we " "do the rest of ContinueConnect"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 969); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()"
") (" "CORS preflight must have been finished by the time we "
"do the rest of ContinueConnect" ")"); do { *((volatile int*
)__null) = 969; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
970
971 // we may or may not have a cache entry at this point
972 if (mCacheEntry) {
973 // read straight from the cache if possible...
974 if (mCachedContentIsValid) {
975 nsRunnableMethod<nsHttpChannel>* event = nullptr;
976 nsresult rv;
977 if (!LoadCachedContentIsPartial()) {
978 rv = AsyncCall(&nsHttpChannel::AsyncOnExamineCachedResponse, &event);
979 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
980 LOG((" AsyncCall failed (%08x)", static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " AsyncCall failed (%08x)", static_cast<uint32_t>(rv
)); } } while (0)
;
981 }
982 }
983 rv = ReadFromCache(true);
984 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && event) {
985 event->Revoke();
986 }
987
988 AccumulateCacheHitTelemetry(kCacheHit, this);
989 mCacheDisposition = kCacheHit;
990
991 return rv;
992 }
993 if (mLoadFlags & LOAD_ONLY_FROM_CACHE) {
994 // the cache contains the requested resource, but it must be
995 // validated before we can reuse it. since we are not allowed
996 // to hit the net, there's nothing more to do. the document
997 // is effectively not in the cache.
998 LOG((" !mCachedContentIsValid && mLoadFlags & LOAD_ONLY_FROM_CACHE"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " !mCachedContentIsValid && mLoadFlags & LOAD_ONLY_FROM_CACHE"
); } } while (0)
;
999 return NS_ERROR_DOCUMENT_NOT_CACHED;
1000 }
1001 } else if (mLoadFlags & LOAD_ONLY_FROM_CACHE) {
1002 LOG((" !mCacheEntry && mLoadFlags & LOAD_ONLY_FROM_CACHE"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " !mCacheEntry && mLoadFlags & LOAD_ONLY_FROM_CACHE"
); } } while (0)
;
1003 return NS_ERROR_DOCUMENT_NOT_CACHED;
1004 }
1005
1006 if (mLoadFlags & LOAD_NO_NETWORK_IO) {
1007 LOG((" mLoadFlags & LOAD_NO_NETWORK_IO"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " mLoadFlags & LOAD_NO_NETWORK_IO"); } } while (0)
;
1008 return NS_ERROR_DOCUMENT_NOT_CACHED;
1009 }
1010
1011 // hit the net...
1012 nsresult rv = DoConnect(mTransactionSticky);
1013 mTransactionSticky = nullptr;
1014 return rv;
1015}
1016
1017nsresult nsHttpChannel::DoConnect(HttpTransactionShell* aTransWithStickyConn) {
1018 LOG(("nsHttpChannel::DoConnect [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::DoConnect [this=%p]\n", this); } } while (0
)
;
1019
1020 if (!mDNSBlockingPromise.IsEmpty()) {
1021 LOG((" waiting for DNS prefetch"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " waiting for DNS prefetch"); } } while (0)
;
1022
1023 // Transaction is passed only from auth retry for which we will definitely
1024 // not block on DNS to alter the origin server name for IP; it has already
1025 // been done.
1026 MOZ_ASSERT(!aTransWithStickyConn)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aTransWithStickyConn)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aTransWithStickyConn))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!aTransWithStickyConn"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1026); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aTransWithStickyConn"
")"); do { *((volatile int*)__null) = 1026; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1027 MOZ_ASSERT(mDNSBlockingThenable)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDNSBlockingThenable)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDNSBlockingThenable))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("mDNSBlockingThenable"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1027); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDNSBlockingThenable"
")"); do { *((volatile int*)__null) = 1027; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1028
1029 nsCOMPtr<nsISerialEventTarget> target(do_GetMainThread());
1030 RefPtr<nsHttpChannel> self(this);
1031 mDNSBlockingThenable->Then(
1032 target, __func__,
1033 [self](const nsCOMPtr<nsIDNSRecord>& aRec) {
1034 nsresult rv = self->DoConnectActual(nullptr);
1035 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1036 self->CloseCacheEntry(false);
1037 Unused << self->AsyncAbort(rv);
1038 }
1039 },
1040 [self](nsresult err) {
1041 self->CloseCacheEntry(false);
1042 Unused << self->AsyncAbort(err);
1043 });
1044
1045 // The connection will continue when the promise is resolved in
1046 // OnLookupComplete.
1047 return NS_OK;
1048 }
1049
1050 return DoConnectActual(aTransWithStickyConn);
1051}
1052
1053nsresult nsHttpChannel::DoConnectActual(
1054 HttpTransactionShell* aTransWithStickyConn) {
1055 LOG(("nsHttpChannel::DoConnectActual [this=%p, aTransWithStickyConn=%p]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::DoConnectActual [this=%p, aTransWithStickyConn=%p]\n"
, this, aTransWithStickyConn); } } while (0)
1056 this, aTransWithStickyConn))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::DoConnectActual [this=%p, aTransWithStickyConn=%p]\n"
, this, aTransWithStickyConn); } } while (0)
;
1057
1058 nsresult rv = SetupChannelForTransaction();
1059 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1060 return rv;
1061 }
1062
1063 return DispatchTransaction(aTransWithStickyConn);
1064}
1065
1066nsresult nsHttpChannel::DispatchTransaction(
1067 HttpTransactionShell* aTransWithStickyConn) {
1068 LOG(("nsHttpChannel::DispatchTransaction [this=%p, aTransWithStickyConn=%p]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::DispatchTransaction [this=%p, aTransWithStickyConn=%p]"
, this, aTransWithStickyConn); } } while (0)
1069 this, aTransWithStickyConn))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::DispatchTransaction [this=%p, aTransWithStickyConn=%p]"
, this, aTransWithStickyConn); } } while (0)
;
1070 nsresult rv = InitTransaction();
1071 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1072 return rv;
1073 }
1074 if (aTransWithStickyConn) {
1075 rv = gHttpHandler->InitiateTransactionWithStickyConn(
1076 mTransaction, mPriority, aTransWithStickyConn);
1077 } else {
1078 rv = gHttpHandler->InitiateTransaction(mTransaction, mPriority);
1079 }
1080
1081 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1082 return rv;
1083 }
1084
1085 rv = mTransaction->AsyncRead(this, getter_AddRefs(mTransactionPump));
1086 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1087 return rv;
1088 }
1089
1090 uint32_t suspendCount = mSuspendCount;
1091 if (LoadAsyncResumePending()) {
1092 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " Suspend()'ing transaction pump once because of async resume pending"
", sc=%u, pump=%p, this=%p", suspendCount, mTransactionPump.
get(), this); } } while (0)
1093 (" Suspend()'ing transaction pump once because of async resume pending"do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " Suspend()'ing transaction pump once because of async resume pending"
", sc=%u, pump=%p, this=%p", suspendCount, mTransactionPump.
get(), this); } } while (0)
1094 ", sc=%u, pump=%p, this=%p",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " Suspend()'ing transaction pump once because of async resume pending"
", sc=%u, pump=%p, this=%p", suspendCount, mTransactionPump.
get(), this); } } while (0)
1095 suspendCount, mTransactionPump.get(), this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " Suspend()'ing transaction pump once because of async resume pending"
", sc=%u, pump=%p, this=%p", suspendCount, mTransactionPump.
get(), this); } } while (0)
;
1096 ++suspendCount;
1097 }
1098 while (suspendCount--) {
1099 mTransactionPump->Suspend();
1100 }
1101
1102 return NS_OK;
1103}
1104
1105void nsHttpChannel::SpeculativeConnect() {
1106 // Before we take the latency hit of dealing with the cache, try and
1107 // get the TCP (and SSL) handshakes going so they can overlap.
1108
1109 // don't speculate if we are offline, when doing http upgrade (i.e.
1110 // websockets bootstrap), or if we can't do keep-alive (because then we
1111 // couldn't reuse the speculative connection anyhow).
1112 RefPtr<mozilla::dom::BrowsingContext> bc;
1113 mLoadInfo->GetBrowsingContext(getter_AddRefs(bc));
1114
1115 if (gIOService->IsOffline() || mUpgradeProtocolCallback ||
1116 !(mCaps & NS_HTTP_ALLOW_KEEPALIVE(1 << 0)) ||
1117 (bc && bc->Top()->GetForceOffline())) {
1118 return;
1119 }
1120
1121 // LOAD_ONLY_FROM_CACHE and LOAD_NO_NETWORK_IO must not hit network.
1122 // LOAD_FROM_CACHE is unlikely to hit network, so skip preconnects for it.
1123 if (mLoadFlags &
1124 (LOAD_ONLY_FROM_CACHE | LOAD_FROM_CACHE | LOAD_NO_NETWORK_IO)) {
1125 return;
1126 }
1127
1128 if (LoadAllowStaleCacheContent()) {
1129 return;
1130 }
1131
1132 nsCOMPtr<nsIInterfaceRequestor> callbacks;
1133 NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
1134 getter_AddRefs(callbacks));
1135 if (!callbacks) return;
1136
1137 Unused << gHttpHandler->SpeculativeConnect(
1138 mConnectionInfo, callbacks,
1139 mCaps & (NS_HTTP_DISALLOW_SPDY(1 << 7) | NS_HTTP_TRR_MODE_MASK((1 << 19) | (1 << 20)) |
1140 NS_HTTP_DISABLE_IPV4(1 << 17) | NS_HTTP_DISABLE_IPV6(1 << 18) |
1141 NS_HTTP_DISALLOW_HTTP3(1 << 21) | NS_HTTP_REFRESH_DNS(1 << 3)),
1142 gHttpHandler->EchConfigEnabled());
1143}
1144
1145void nsHttpChannel::DoNotifyListenerCleanup() {
1146 // We don't need this info anymore
1147 CleanRedirectCacheChainIfNecessary();
1148}
1149
1150void nsHttpChannel::ReleaseListeners() {
1151 HttpBaseChannel::ReleaseListeners();
1152 mChannelClassifier = nullptr;
1153 mWarningReporter = nullptr;
1154 mEarlyHintObserver = nullptr;
1155 mWebTransportSessionEventListener = nullptr;
1156
1157 for (StreamFilterRequest& request : mStreamFilterRequests) {
1158 request.mPromise->Reject(false, __func__);
1159 }
1160 mStreamFilterRequests.Clear();
1161}
1162
1163void nsHttpChannel::DoAsyncAbort(nsresult aStatus) {
1164 Unused << AsyncAbort(aStatus);
1165}
1166
1167void nsHttpChannel::HandleAsyncRedirect() {
1168 MOZ_ASSERT(!mCallOnResume, "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCallOnResume)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCallOnResume))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mCallOnResume"
" (" "How did that happen?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1168); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCallOnResume"
") (" "How did that happen?" ")"); do { *((volatile int*)__null
) = 1168; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
1169
1170 if (mSuspendCount) {
1171 LOG(("Waiting until resume to do async redirect [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume to do async redirect [this=%p]\n", this
); } } while (0)
;
1172 mCallOnResume = [](nsHttpChannel* self) {
1173 self->HandleAsyncRedirect();
1174 return NS_OK;
1175 };
1176 return;
1177 }
1178
1179 nsresult rv = NS_OK;
1180
1181 LOG(("nsHttpChannel::HandleAsyncRedirect [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::HandleAsyncRedirect [this=%p]\n", this); } }
while (0)
;
1182
1183 // since this event is handled asynchronously, it is possible that this
1184 // channel could have been canceled, in which case there would be no point
1185 // in processing the redirect.
1186 if (NS_SUCCEEDED(mStatus)((bool)(__builtin_expect(!!(!NS_FAILED_impl(mStatus)), 1)))) {
1187 PushRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncRedirect);
1188 rv = AsyncProcessRedirection(mResponseHead->Status());
1189 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1190 PopRedirectAsyncFunc(&nsHttpChannel::ContinueHandleAsyncRedirect);
1191 // TODO: if !DoNotRender3xxBody(), render redirect body instead.
1192 // But first we need to cache 3xx bodies (bug 748510)
1193 rv = ContinueHandleAsyncRedirect(rv);
1194 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1194); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 1194; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1195 }
1196 } else {
1197 rv = ContinueHandleAsyncRedirect(mStatus);
1198 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1198); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 1198; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1199 }
1200}
1201
1202nsresult nsHttpChannel::ContinueHandleAsyncRedirect(nsresult rv) {
1203 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1204 // If AsyncProcessRedirection fails, then we have to send out the
1205 // OnStart/OnStop notifications.
1206 LOG(("ContinueHandleAsyncRedirect got failure result [rv=%" PRIx32 "]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueHandleAsyncRedirect got failure result [rv=%" "x" "]\n"
, static_cast<uint32_t>(rv)); } } while (0)
1207 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueHandleAsyncRedirect got failure result [rv=%" "x" "]\n"
, static_cast<uint32_t>(rv)); } } while (0)
;
1208
1209 bool redirectsEnabled = !mLoadInfo->GetDontFollowRedirects();
1210
1211 if (redirectsEnabled) {
1212 // TODO: stop failing original channel if redirect vetoed?
1213 mStatus = rv;
1214
1215 DoNotifyListener();
1216
1217 // Blow away cache entry if we couldn't process the redirect
1218 // for some reason (the cache entry might be corrupt).
1219 if (mCacheEntry) {
1220 mCacheEntry->AsyncDoom(nullptr);
1221 }
1222 } else {
1223 DoNotifyListener();
1224 }
1225 }
1226
1227 CloseCacheEntry(true);
1228
1229 StoreIsPending(false);
1230
1231 if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
1232
1233 return NS_OK;
1234}
1235
1236void nsHttpChannel::HandleAsyncNotModified() {
1237 MOZ_ASSERT(!mCallOnResume, "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCallOnResume)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCallOnResume))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mCallOnResume"
" (" "How did that happen?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCallOnResume"
") (" "How did that happen?" ")"); do { *((volatile int*)__null
) = 1237; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
1238
1239 if (mSuspendCount) {
1240 LOG(("Waiting until resume to do async not-modified [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume to do async not-modified [this=%p]\n"
, this); } } while (0)
;
1241 mCallOnResume = [](nsHttpChannel* self) {
1242 self->HandleAsyncNotModified();
1243 return NS_OK;
1244 };
1245 return;
1246 }
1247
1248 LOG(("nsHttpChannel::HandleAsyncNotModified [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::HandleAsyncNotModified [this=%p]\n", this);
} } while (0)
;
1249
1250 DoNotifyListener();
1251
1252 CloseCacheEntry(false);
1253
1254 StoreIsPending(false);
1255
1256 if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
1257}
1258
1259nsresult nsHttpChannel::SetupChannelForTransaction() {
1260 LOG((do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::SetupChannelForTransaction [this=%p, cos=%lu, inc=%d "
"prio=%d]\n", this, mClassOfService.Flags(), mClassOfService
.Incremental(), mPriority); } } while (0)
1261 "nsHttpChannel::SetupChannelForTransaction [this=%p, cos=%lu, inc=%d "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::SetupChannelForTransaction [this=%p, cos=%lu, inc=%d "
"prio=%d]\n", this, mClassOfService.Flags(), mClassOfService
.Incremental(), mPriority); } } while (0)
1262 "prio=%d]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::SetupChannelForTransaction [this=%p, cos=%lu, inc=%d "
"prio=%d]\n", this, mClassOfService.Flags(), mClassOfService
.Incremental(), mPriority); } } while (0)
1263 this, mClassOfService.Flags(), mClassOfService.Incremental(), mPriority))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::SetupChannelForTransaction [this=%p, cos=%lu, inc=%d "
"prio=%d]\n", this, mClassOfService.Flags(), mClassOfService
.Incremental(), mPriority); } } while (0)
;
1264
1265 NS_ENSURE_TRUE(!mTransaction, NS_ERROR_ALREADY_INITIALIZED)do { if ((__builtin_expect(!!(!(!mTransaction)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!mTransaction" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1265); return NS_ERROR_ALREADY_INITIALIZED; } } while (false
)
;
1266
1267 nsresult rv;
1268
1269 mozilla::MutexAutoLock lock(mRCWNLock);
1270
1271 if (StaticPrefs::network_http_priority_header_enabled()) {
1272 SetPriorityHeader();
1273 }
1274
1275 // If we're racing cache with network, conditional or byte range header
1276 // could be added in OnCacheEntryCheck. We cannot send conditional request
1277 // without having the entry, so we need to remove the headers here and
1278 // ignore the cache entry in OnCacheEntryAvailable.
1279 if (mRaceCacheWithNetwork && AwaitingCacheCallbacks()) {
1280 if (mDidReval) {
1281 LOG((" Removing conditional request headers"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " Removing conditional request headers"); } } while (0)
;
1282 UntieValidationRequest();
1283 mDidReval = false;
1284 mIgnoreCacheEntry = true;
1285 }
1286
1287 if (LoadCachedContentIsPartial()) {
1288 LOG((" Removing byte range request headers"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " Removing byte range request headers"); } } while (0)
;
1289 UntieByteRangeRequest();
1290 StoreCachedContentIsPartial(false);
1291 mIgnoreCacheEntry = true;
1292 }
1293
1294 if (mIgnoreCacheEntry) {
1295 mAvailableCachedAltDataType.Truncate();
1296 StoreDeliveringAltData(false);
1297 mAltDataLength = -1;
1298 mCacheInputStream.CloseAndRelease();
1299 }
1300 }
1301
1302 StoreUsedNetwork(1);
1303
1304 if (!LoadAllowSpdy()) {
1305 mCaps |= NS_HTTP_DISALLOW_SPDY(1 << 7);
1306 }
1307 if (!LoadAllowHttp3()) {
1308 mCaps |= NS_HTTP_DISALLOW_HTTP3(1 << 21);
1309 }
1310 if (LoadBeConservative()) {
1311 mCaps |= NS_HTTP_BE_CONSERVATIVE(1 << 11);
1312 }
1313
1314 if (mLoadFlags & LOAD_ANONYMOUS_ALLOW_CLIENT_CERT) {
1315 mCaps |= NS_HTTP_LOAD_ANONYMOUS_CONNECT_ALLOW_CLIENT_CERT(1 << 23);
1316 }
1317
1318 if (nsContentUtils::ShouldResistFingerprinting(this,
1319 RFPTarget::HttpUserAgent)) {
1320 mCaps |= NS_HTTP_USE_RFP(1 << 26);
1321 }
1322
1323 // Use the URI path if not proxying (transparent proxying such as proxy
1324 // CONNECT does not count here). Also figure out what HTTP version to use.
1325 nsAutoCString buf, path;
1326 nsCString* requestURI;
1327
1328 // This is the normal e2e H1 path syntax "/index.html"
1329 rv = mURI->GetPathQueryRef(path);
1330 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1331 return rv;
1332 }
1333
1334 // path may contain UTF-8 characters, so ensure that they're escaped.
1335 if (NS_EscapeURL(path.get(), path.Length(), esc_OnlyNonASCII | esc_Spaces,
1336 buf)) {
1337 requestURI = &buf;
1338 } else {
1339 requestURI = &path;
1340 }
1341
1342 // trim off the #ref portion if any...
1343 int32_t ref1 = requestURI->FindChar('#');
1344 if (ref1 != kNotFound) {
1345 requestURI->SetLength(ref1);
1346 }
1347
1348 if (mConnectionInfo->UsingConnect() || !mConnectionInfo->UsingHttpProxy()) {
1349 mRequestHead.SetVersion(gHttpHandler->HttpVersion());
1350 } else {
1351 mRequestHead.SetPath(*requestURI);
1352
1353 // RequestURI should be the absolute uri H1 proxy syntax
1354 // "http://foo/index.html" so we will overwrite the relative version in
1355 // requestURI
1356 rv = mURI->GetUserPass(buf);
1357 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
1358 if (!buf.IsEmpty() && ((strncmp(mSpec.get(), "http:", 5) == 0) ||
1359 strncmp(mSpec.get(), "https:", 6) == 0)) {
1360 nsCOMPtr<nsIURI> tempURI = nsIOService::CreateExposableURI(mURI);
1361 rv = tempURI->GetAsciiSpec(path);
1362 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
1363 requestURI = &path;
1364 } else {
1365 requestURI = &mSpec;
1366 }
1367
1368 // trim off the #ref portion if any...
1369 int32_t ref2 = requestURI->FindChar('#');
1370 if (ref2 != kNotFound) {
1371 requestURI->SetLength(ref2);
1372 }
1373
1374 mRequestHead.SetVersion(gHttpHandler->ProxyHttpVersion());
1375 }
1376
1377 mRequestHead.SetRequestURI(*requestURI);
1378
1379 // set the request time for cache expiration calculations
1380 mRequestTime = NowInSeconds()PRTimeToSeconds(PR_Now());
1381 StoreRequestTimeInitialized(true);
1382
1383 // if doing a reload, force end-to-end
1384 if (mLoadFlags & LOAD_BYPASS_CACHE) {
1385 // We need to send 'Pragma:no-cache' to inhibit proxy caching even if
1386 // no proxy is configured since we might be talking with a transparent
1387 // proxy, i.e. one that operates at the network level. See bug #14772.
1388 // But we should not touch Pragma if Cache-Control is already set
1389 // (https://fetch.spec.whatwg.org/#ref-for-concept-request-cache-mode%E2%91%A3)
1390 if (!mRequestHead.HasHeader(nsHttp::Pragma)) {
1391 rv = mRequestHead.SetHeaderOnce(nsHttp::Pragma, "no-cache", true);
1392 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1392); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 1392; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1393 }
1394 // If we're configured to speak HTTP/1.1 then also send 'Cache-control:
1395 // no-cache'. But likewise don't touch Cache-Control if it's already set.
1396 if (mRequestHead.Version() >= HttpVersion::v1_1 &&
1397 !mRequestHead.HasHeader(nsHttp::Cache_Control)) {
1398 rv = mRequestHead.SetHeaderOnce(nsHttp::Cache_Control, "no-cache", true);
1399 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1399); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 1399; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1400 }
1401 } else if (mLoadFlags & VALIDATE_ALWAYS) {
1402 // We need to send 'Cache-Control: max-age=0' to force each cache along
1403 // the path to the origin server to revalidate its own entry, if any,
1404 // with the next cache or server. See bug #84847.
1405 //
1406 // If we're configured to speak HTTP/1.0 then just send 'Pragma: no-cache'
1407 //
1408 // But don't send the headers if they're already set:
1409 // https://fetch.spec.whatwg.org/#ref-for-concept-request-cache-mode%E2%91%A2
1410 if (mRequestHead.Version() >= HttpVersion::v1_1) {
1411 if (!mRequestHead.HasHeader(nsHttp::Cache_Control)) {
1412 rv = mRequestHead.SetHeaderOnce(nsHttp::Cache_Control, "max-age=0",
1413 true);
1414 }
1415 } else {
1416 if (!mRequestHead.HasHeader(nsHttp::Pragma)) {
1417 rv = mRequestHead.SetHeaderOnce(nsHttp::Pragma, "no-cache", true);
1418 }
1419 }
1420 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1420); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 1420; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1421 }
1422
1423 if (LoadResuming()) {
1424 char byteRange[32];
1425 SprintfLiteral(byteRange, "bytes=%" PRIu64"l" "u" "-", mStartPos);
1426 rv = mRequestHead.SetHeader(nsHttp::Range, nsDependentCString(byteRange));
1427 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1427); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 1427; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1428
1429 if (!mEntityID.IsEmpty()) {
1430 // Also, we want an error if this resource changed in the meantime
1431 // Format of the entity id is: escaped_etag/size/lastmod
1432 nsCString::const_iterator start, end, slash;
1433 mEntityID.BeginReading(start);
1434 mEntityID.EndReading(end);
1435 mEntityID.BeginReading(slash);
1436
1437 if (FindCharInReadable('/', slash, end)) {
1438 nsAutoCString ifMatch;
1439 rv = mRequestHead.SetHeader(
1440 nsHttp::If_Match,
1441 NS_UnescapeURL(Substring(start, slash), 0, ifMatch));
1442 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1442); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 1442; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1443
1444 ++slash; // Incrementing, so that searching for '/' won't find
1445 // the same slash again
1446 }
1447
1448 if (FindCharInReadable('/', slash, end)) {
1449 rv = mRequestHead.SetHeader(nsHttp::If_Unmodified_Since,
1450 Substring(++slash, end));
1451 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1451); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 1451; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1452 }
1453 }
1454 }
1455
1456 // See bug #466080. Transfer LOAD_ANONYMOUS flag to socket-layer.
1457 if (mLoadFlags & LOAD_ANONYMOUS) mCaps |= NS_HTTP_LOAD_ANONYMOUS(1 << 4);
1458
1459 if (LoadTimingEnabled()) mCaps |= NS_HTTP_TIMING_ENABLED(1 << 5);
1460
1461 if (mUpgradeProtocolCallback) {
1462 rv = mRequestHead.SetHeader(nsHttp::Upgrade, mUpgradeProtocol, false);
1463 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1463); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 1463; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1464 rv = mRequestHead.SetHeaderOnce(nsHttp::Connection, nsHttp::Upgrade.get(),
1465 true);
1466 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1466); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 1466; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1467 mCaps |= NS_HTTP_STICKY_CONNECTION(1 << 2);
1468 mCaps &= ~NS_HTTP_ALLOW_KEEPALIVE(1 << 0);
1469 }
1470
1471 if (mWebTransportSessionEventListener) {
1472 mCaps |= NS_HTTP_STICKY_CONNECTION(1 << 2);
1473 }
1474
1475 return NS_OK;
1476}
1477
1478nsresult nsHttpChannel::InitTransaction() {
1479 nsresult rv;
1480 // create wrapper for this channel's notification callbacks
1481 nsCOMPtr<nsIInterfaceRequestor> callbacks;
1482 NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
1483 getter_AddRefs(callbacks));
1484
1485 // create the transaction object
1486 if (nsIOService::UseSocketProcess()) {
1487 if (NS_WARN_IF(!gIOService->SocketProcessReady())NS_warn_if_impl(!gIOService->SocketProcessReady(), "!gIOService->SocketProcessReady()"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1487)
) {
1488 return NS_ERROR_NOT_AVAILABLE;
1489 }
1490 SocketProcessParent* socketProcess = SocketProcessParent::GetSingleton();
1491 if (!socketProcess->CanSend()) {
1492 return NS_ERROR_NOT_AVAILABLE;
1493 }
1494
1495 nsCOMPtr<nsIParentChannel> parentChannel;
1496 NS_QueryNotificationCallbacks(this, parentChannel);
1497 RefPtr<DocumentLoadListener> documentChannelParent =
1498 do_QueryObject(parentChannel);
1499 // See HttpTransactionChild::CanSendODAToContentProcessDirectly() and
1500 // nsHttpChannel::CallOnStartRequest() for the reason why we need to know if
1501 // this is a document load. We only send ODA directly to child process for
1502 // non document loads.
1503 RefPtr<HttpTransactionParent> transParent =
1504 new HttpTransactionParent(!!documentChannelParent);
1505 LOG1(("nsHttpChannel %p created HttpTransactionParent %p\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Error)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Error, "nsHttpChannel %p created HttpTransactionParent %p\n"
, this, transParent.get()); } } while (0)
1506 transParent.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Error)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Error, "nsHttpChannel %p created HttpTransactionParent %p\n"
, this, transParent.get()); } } while (0)
;
1507
1508 // Since OnStopRequest could be sent to child process from socket process
1509 // directly, we need to store these two values in HttpTransactionChild and
1510 // forward to child process until HttpTransactionChild::OnStopRequest is
1511 // called.
1512 transParent->SetRedirectTimestamp(mRedirectStartTimeStamp,
1513 mRedirectEndTimeStamp);
1514
1515 if (socketProcess) {
1516 MOZ_ALWAYS_TRUE(do { if ((__builtin_expect(!!(socketProcess->SendPHttpTransactionConstructor
(transParent)), 1))) { } else { do { static_assert( mozilla::
detail::AssertionConditionType<decltype(false)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(false))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("false" " (" "socketProcess->SendPHttpTransactionConstructor(transParent)"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1517); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "socketProcess->SendPHttpTransactionConstructor(transParent)"
")"); do { *((volatile int*)__null) = 1517; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1517 socketProcess->SendPHttpTransactionConstructor(transParent))do { if ((__builtin_expect(!!(socketProcess->SendPHttpTransactionConstructor
(transParent)), 1))) { } else { do { static_assert( mozilla::
detail::AssertionConditionType<decltype(false)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(false))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("false" " (" "socketProcess->SendPHttpTransactionConstructor(transParent)"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1517); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "socketProcess->SendPHttpTransactionConstructor(transParent)"
")"); do { *((volatile int*)__null) = 1517; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1518 }
1519 mTransaction = transParent;
1520 } else {
1521 mTransaction = new nsHttpTransaction();
1522 LOG1(("nsHttpChannel %p created nsHttpTransaction %p\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Error)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Error, "nsHttpChannel %p created nsHttpTransaction %p\n"
, this, mTransaction.get()); } } while (0)
1523 mTransaction.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Error)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Error, "nsHttpChannel %p created nsHttpTransaction %p\n"
, this, mTransaction.get()); } } while (0)
;
1524 }
1525
1526 // Save the mapping of channel id and the channel. We need this mapping for
1527 // nsIHttpActivityObserver.
1528 gHttpHandler->AddHttpChannel(mChannelId, ToSupports(this));
1529
1530 nsCOMPtr<nsIHttpPushListener> pushListener;
1531 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
1532 NS_GET_IID(nsIHttpPushListener)(nsIHttpPushListener::COMTypeInfo<nsIHttpPushListener, void
>::kIID)
,
1533 getter_AddRefs(pushListener));
1534 HttpTransactionShell::OnPushCallback pushCallback = nullptr;
1535 if (pushListener) {
1536 mCaps |= NS_HTTP_ONPUSH_LISTENER(1 << 9);
1537 nsWeakPtr weakPtrThis(
1538 do_GetWeakReference(static_cast<nsIHttpChannel*>(this)));
1539 pushCallback = [weakPtrThis](uint32_t aPushedStreamId,
1540 const nsACString& aUrl,
1541 const nsACString& aRequestString,
1542 HttpTransactionShell* aTransaction) {
1543 if (nsCOMPtr<nsIHttpChannel> channel = do_QueryReferent(weakPtrThis)) {
1544 return static_cast<nsHttpChannel*>(channel.get())
1545 ->OnPush(aPushedStreamId, aUrl, aRequestString, aTransaction);
1546 }
1547 return NS_ERROR_NOT_AVAILABLE;
1548 };
1549 }
1550
1551 EnsureBrowserId();
1552 EnsureRequestContext();
1553
1554 HttpTrafficCategory category = CreateTrafficCategory();
1555 std::function<void(TransactionObserverResult&&)> observer;
1556 if (mTransactionObserver) {
1557 observer = [transactionObserver{std::move(mTransactionObserver)}](
1558 TransactionObserverResult&& aResult) {
1559 transactionObserver->Complete(aResult.versionOk(), aResult.authOk(),
1560 aResult.closeReason());
1561 };
1562 }
1563 mTransaction->SetIsForWebTransport(!!mWebTransportSessionEventListener);
1564 rv = mTransaction->Init(
1565 mCaps, mConnectionInfo, &mRequestHead, mUploadStream, mReqContentLength,
1566 LoadUploadStreamHasHeaders(), GetCurrentSerialEventTarget(), callbacks,
1567 this, mBrowserId, category, mRequestContext, mClassOfService,
1568 mInitialRwin, LoadResponseTimeoutEnabled(), mChannelId,
1569 std::move(observer), std::move(pushCallback), mTransWithPushedStream,
1570 mPushedStreamId);
1571 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1572 mTransaction = nullptr;
1573 return rv;
1574 }
1575
1576 return rv;
1577}
1578
1579HttpTrafficCategory nsHttpChannel::CreateTrafficCategory() {
1580 MOZ_ASSERT(!mFirstPartyClassificationFlags ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mFirstPartyClassificationFlags || !mThirdPartyClassificationFlags
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mFirstPartyClassificationFlags || !mThirdPartyClassificationFlags
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mFirstPartyClassificationFlags || !mThirdPartyClassificationFlags"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1581); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mFirstPartyClassificationFlags || !mThirdPartyClassificationFlags"
")"); do { *((volatile int*)__null) = 1581; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1581 !mThirdPartyClassificationFlags)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mFirstPartyClassificationFlags || !mThirdPartyClassificationFlags
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mFirstPartyClassificationFlags || !mThirdPartyClassificationFlags
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mFirstPartyClassificationFlags || !mThirdPartyClassificationFlags"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1581); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mFirstPartyClassificationFlags || !mThirdPartyClassificationFlags"
")"); do { *((volatile int*)__null) = 1581; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1582
1583 if (!StaticPrefs::network_traffic_analyzer_enabled()) {
1584 return HttpTrafficCategory::eInvalid;
1585 }
1586
1587 HttpTrafficAnalyzer::ClassOfService cos;
1588 {
1589 if ((mClassOfService.Flags() & nsIClassOfService::Leader) &&
1590 mLoadInfo->GetExternalContentPolicyType() ==
1591 ExtContentPolicy::TYPE_SCRIPT) {
1592 cos = HttpTrafficAnalyzer::ClassOfService::eLeader;
1593 } else if (mLoadFlags & nsIRequest::LOAD_BACKGROUND) {
1594 cos = HttpTrafficAnalyzer::ClassOfService::eBackground;
1595 } else {
1596 cos = HttpTrafficAnalyzer::ClassOfService::eOther;
1597 }
1598 }
1599
1600 bool isThirdParty = AntiTrackingUtils::IsThirdPartyChannel(this);
1601
1602 HttpTrafficAnalyzer::TrackingClassification tc;
1603 {
1604 uint32_t flags = isThirdParty ? mThirdPartyClassificationFlags
1605 : mFirstPartyClassificationFlags;
1606
1607 using CF = nsIClassifiedChannel::ClassificationFlags;
1608 using TC = HttpTrafficAnalyzer::TrackingClassification;
1609
1610 if (flags & CF::CLASSIFIED_TRACKING_CONTENT) {
1611 tc = TC::eContent;
1612 } else if (flags & CF::CLASSIFIED_FINGERPRINTING_CONTENT) {
1613 tc = TC::eFingerprinting;
1614 } else if (flags & CF::CLASSIFIED_ANY_BASIC_TRACKING) {
1615 tc = TC::eBasic;
1616 } else {
1617 tc = TC::eNone;
1618 }
1619 }
1620
1621 bool isSystemPrincipal =
1622 mLoadInfo->GetLoadingPrincipal() &&
1623 mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal();
1624 return HttpTrafficAnalyzer::CreateTrafficCategory(
1625 NS_UsePrivateBrowsing(this), isSystemPrincipal, isThirdParty, cos, tc);
1626}
1627
1628void nsHttpChannel::SetCachedContentType() {
1629 if (!mResponseHead) {
1630 return;
1631 }
1632
1633 nsAutoCString contentTypeStr;
1634 mResponseHead->ContentType(contentTypeStr);
1635
1636 uint8_t contentType = nsICacheEntry::CONTENT_TYPE_OTHER;
1637 if (nsContentUtils::IsJavascriptMIMEType(
1638 NS_ConvertUTF8toUTF16(contentTypeStr))) {
1639 contentType = nsICacheEntry::CONTENT_TYPE_JAVASCRIPT;
1640 } else if (StringBeginsWith(contentTypeStr, "text/css"_ns) ||
1641 (mLoadInfo->GetExternalContentPolicyType() ==
1642 ExtContentPolicy::TYPE_STYLESHEET)) {
1643 contentType = nsICacheEntry::CONTENT_TYPE_STYLESHEET;
1644 } else if (StringBeginsWith(contentTypeStr, "application/wasm"_ns)) {
1645 contentType = nsICacheEntry::CONTENT_TYPE_WASM;
1646 } else if (StringBeginsWith(contentTypeStr, "image/"_ns)) {
1647 contentType = nsICacheEntry::CONTENT_TYPE_IMAGE;
1648 } else if (StringBeginsWith(contentTypeStr, "video/"_ns)) {
1649 contentType = nsICacheEntry::CONTENT_TYPE_MEDIA;
1650 } else if (StringBeginsWith(contentTypeStr, "audio/"_ns)) {
1651 contentType = nsICacheEntry::CONTENT_TYPE_MEDIA;
1652 }
1653
1654 mCacheEntry->SetContentType(contentType);
1655}
1656
1657nsresult nsHttpChannel::CallOnStartRequest() {
1658 LOG(("nsHttpChannel::CallOnStartRequest [this=%p]", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::CallOnStartRequest [this=%p]", this); } } while
(0)
;
1659
1660 MOZ_RELEASE_ASSERT(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()" " ("
"CORS preflight must have been finished by the time we " "call OnStartRequest"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1662); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()"
") (" "CORS preflight must have been finished by the time we "
"call OnStartRequest" ")"); do { *((volatile int*)__null) = 1662
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
1661 "CORS preflight must have been finished by the time we "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()" " ("
"CORS preflight must have been finished by the time we " "call OnStartRequest"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1662); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()"
") (" "CORS preflight must have been finished by the time we "
"call OnStartRequest" ")"); do { *((volatile int*)__null) = 1662
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
1662 "call OnStartRequest")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()" " ("
"CORS preflight must have been finished by the time we " "call OnStartRequest"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1662); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!LoadRequireCORSPreflight() || LoadIsCorsPreflightDone()"
") (" "CORS preflight must have been finished by the time we "
"call OnStartRequest" ")"); do { *((volatile int*)__null) = 1662
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
1663
1664 MOZ_RELEASE_ASSERT(mCanceled || LoadProcessCrossOriginSecurityHeadersCalled(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCanceled || LoadProcessCrossOriginSecurityHeadersCalled
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mCanceled || LoadProcessCrossOriginSecurityHeadersCalled
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mCanceled || LoadProcessCrossOriginSecurityHeadersCalled()"
" (" "Security headers need to have been processed before " "calling CallOnStartRequest"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1666); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "mCanceled || LoadProcessCrossOriginSecurityHeadersCalled()"
") (" "Security headers need to have been processed before "
"calling CallOnStartRequest" ")"); do { *((volatile int*)__null
) = 1666; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
1665 "Security headers need to have been processed before "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCanceled || LoadProcessCrossOriginSecurityHeadersCalled
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mCanceled || LoadProcessCrossOriginSecurityHeadersCalled
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mCanceled || LoadProcessCrossOriginSecurityHeadersCalled()"
" (" "Security headers need to have been processed before " "calling CallOnStartRequest"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1666); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "mCanceled || LoadProcessCrossOriginSecurityHeadersCalled()"
") (" "Security headers need to have been processed before "
"calling CallOnStartRequest" ")"); do { *((volatile int*)__null
) = 1666; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
1666 "calling CallOnStartRequest")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCanceled || LoadProcessCrossOriginSecurityHeadersCalled
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mCanceled || LoadProcessCrossOriginSecurityHeadersCalled
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mCanceled || LoadProcessCrossOriginSecurityHeadersCalled()"
" (" "Security headers need to have been processed before " "calling CallOnStartRequest"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1666); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "mCanceled || LoadProcessCrossOriginSecurityHeadersCalled()"
") (" "Security headers need to have been processed before "
"calling CallOnStartRequest" ")"); do { *((volatile int*)__null
) = 1666; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
1667
1668 mEarlyHintObserver = nullptr;
1669
1670 if (LoadOnStartRequestCalled()) {
1671 // This can only happen when a range request loading rest of the data
1672 // after interrupted concurrent cache read asynchronously failed, e.g.
1673 // the response range bytes are not as expected or this channel has
1674 // been externally canceled.
1675 //
1676 // It's legal to bypass CallOnStartRequest for that case since we've
1677 // already called OnStartRequest on our listener and also added all
1678 // content converters before.
1679 MOZ_ASSERT(LoadConcurrentCacheAccess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(LoadConcurrentCacheAccess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(LoadConcurrentCacheAccess())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("LoadConcurrentCacheAccess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1679); AnnotateMozCrashReason("MOZ_ASSERT" "(" "LoadConcurrentCacheAccess()"
")"); do { *((volatile int*)__null) = 1679; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1680 LOG(("CallOnStartRequest already invoked before"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CallOnStartRequest already invoked before"); } } while (0)
;
1681 return mStatus;
1682 }
1683
1684 // Ensure mListener->OnStartRequest will be invoked before exiting
1685 // this function.
1686 auto onStartGuard = MakeScopeExit([&] {
1687 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " calling mListener->OnStartRequest by ScopeExit [this=%p, "
"listener=%p]\n", this, mListener.get()); } } while (0)
1688 (" calling mListener->OnStartRequest by ScopeExit [this=%p, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " calling mListener->OnStartRequest by ScopeExit [this=%p, "
"listener=%p]\n", this, mListener.get()); } } while (0)
1689 "listener=%p]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " calling mListener->OnStartRequest by ScopeExit [this=%p, "
"listener=%p]\n", this, mListener.get()); } } while (0)
1690 this, mListener.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " calling mListener->OnStartRequest by ScopeExit [this=%p, "
"listener=%p]\n", this, mListener.get()); } } while (0)
;
1691 MOZ_ASSERT(!LoadOnStartRequestCalled())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadOnStartRequestCalled())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!LoadOnStartRequestCalled())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!LoadOnStartRequestCalled()"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1691); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!LoadOnStartRequestCalled()"
")"); do { *((volatile int*)__null) = 1691; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1692
1693 if (mListener) {
1694 nsCOMPtr<nsIStreamListener> deleteProtector(mListener);
1695 StoreOnStartRequestCalled(true);
1696 deleteProtector->OnStartRequest(this);
1697 }
1698 StoreOnStartRequestCalled(true);
1699 });
1700
1701 nsresult rv = ValidateMIMEType();
1702 // Since ODA and OnStopRequest could be sent from socket process directly, we
1703 // need to update the channel status before calling mListener->OnStartRequest.
1704 // This is the only way to let child process discard the already received ODA
1705 // messages.
1706 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1707 mStatus = rv;
1708 return mStatus;
1709 }
1710
1711 // EnsureOpaqueResponseIsAllowed and EnsureOpauqeResponseIsAllowedAfterSniff
1712 // are the checks for Opaque Response Blocking to ensure that we block as many
1713 // cross-origin responses with CORS headers as possible that are not either
1714 // Javascript or media to avoid leaking their contents through side channels.
1715 OpaqueResponse opaqueResponse =
1716 PerformOpaqueResponseSafelistCheckBeforeSniff();
1717 if (opaqueResponse == OpaqueResponse::Block) {
1718 SetChannelBlockedByOpaqueResponse();
1719 CancelWithReason(NS_ERROR_FAILURE,
1720 "OpaqueResponseBlocker::BlockResponse"_ns);
1721 return NS_ERROR_FAILURE;
1722 }
1723
1724 // Allow consumers to override our content type
1725 if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) {
1726 // NOTE: We can have both a txn pump and a cache pump when the cache
1727 // content is partial. In that case, we need to read from the cache,
1728 // because that's the one that has the initial contents. If that fails
1729 // then give the transaction pump a shot.
1730
1731 nsIChannel* thisChannel = static_cast<nsIChannel*>(this);
1732
1733 bool typeSniffersCalled = false;
1734 if (mCachePump) {
1735 typeSniffersCalled =
1736 NS_SUCCEEDED(mCachePump->PeekStream(CallTypeSniffers, thisChannel))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mCachePump->PeekStream
(CallTypeSniffers, thisChannel))), 1)))
;
1737 }
1738
1739 if (!typeSniffersCalled && mTransactionPump) {
1740 RefPtr<nsInputStreamPump> pump = do_QueryObject(mTransactionPump);
1741 if (pump) {
1742 pump->PeekStream(CallTypeSniffers, thisChannel);
1743 } else {
1744 MOZ_ASSERT(nsIOService::UseSocketProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nsIOService::UseSocketProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsIOService::UseSocketProcess
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nsIOService::UseSocketProcess()", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1744); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsIOService::UseSocketProcess()"
")"); do { *((volatile int*)__null) = 1744; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1745 RefPtr<HttpTransactionParent> trans = do_QueryObject(mTransactionPump);
1746 MOZ_ASSERT(trans)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(trans)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(trans))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("trans", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1746); AnnotateMozCrashReason("MOZ_ASSERT" "(" "trans" ")")
; do { *((volatile int*)__null) = 1746; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1747 trans->SetSniffedTypeToChannel(CallTypeSniffers, thisChannel);
1748 }
1749 }
1750 }
1751
1752 // Note that the code below should be synced with the code in
1753 // HttpTransactionChild::CanSendODAToContentProcessDirectly(). We MUST make
1754 // sure HttpTransactionChild::CanSendODAToContentProcessDirectly() returns
1755 // false when a stream converter is applied.
1756 bool unknownDecoderStarted = false;
1757 if (mResponseHead && !mResponseHead->HasContentType()) {
1758 MOZ_ASSERT(mConnectionInfo, "Should have connection info here")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mConnectionInfo)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mConnectionInfo))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mConnectionInfo"
" (" "Should have connection info here" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1758); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mConnectionInfo"
") (" "Should have connection info here" ")"); do { *((volatile
int*)__null) = 1758; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1759 if (!mContentTypeHint.IsEmpty()) {
1760 mResponseHead->SetContentType(mContentTypeHint);
1761 } else if (mResponseHead->Version() == HttpVersion::v0_9 &&
1762 mConnectionInfo->OriginPort() !=
1763 mConnectionInfo->DefaultPort()) {
1764 mResponseHead->SetContentType(nsLiteralCString(TEXT_PLAIN"text/plain"));
1765 } else {
1766 // Uh-oh. We had better find out what type we are!
1767 mListener = new nsUnknownDecoder(mListener);
1768 unknownDecoderStarted = true;
1769 }
1770 }
1771
1772 // If unknownDecoder is not going to be launched, call
1773 // EnsureOpaqueResponseIsAllowedAfterSniff immediately.
1774 if (!unknownDecoderStarted) {
1775 if (opaqueResponse == OpaqueResponse::SniffCompressed) {
1776 mListener = new nsCompressedAudioVideoImageDetector(
1777 mListener, &HttpBaseChannel::CallTypeSniffers);
1778 } else if (opaqueResponse == OpaqueResponse::Sniff) {
1779 MOZ_DIAGNOSTIC_ASSERT(mORB)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mORB)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(mORB))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mORB", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1779); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mORB"
")"); do { *((volatile int*)__null) = 1779; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1780 nsresult rv = mORB->EnsureOpaqueResponseIsAllowedAfterSniff(this);
1781
1782 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1783 return rv;
1784 }
1785 }
1786 }
1787
1788 // If the content is multipart/x-mixed-replace, we'll insert a MIME decoder
1789 // in the pipeline to handle the content and pass it along to our
1790 // original listener. nsUnknownDecoder doesn't support detecting this type,
1791 // so we only need to insert this using the response header's mime type.
1792 //
1793 // We only do this for unwrapped document loads, since we might want to send
1794 // parts to the external protocol handler without leaving the parent process.
1795 bool mustRunStreamFilterInParent = false;
1796 nsCOMPtr<nsIParentChannel> parentChannel;
1797 NS_QueryNotificationCallbacks(this, parentChannel);
1798 RefPtr<DocumentLoadListener> docListener = do_QueryObject(parentChannel);
1799 if (mResponseHead && docListener && docListener->GetChannel() == this) {
1800 nsAutoCString contentType;
1801 mResponseHead->ContentType(contentType);
1802
1803 if (contentType.Equals("multipart/x-mixed-replace"_ns)) {
1804 nsCOMPtr<nsIStreamConverterService> convServ(
1805 do_GetService("@mozilla.org/streamConverters;1", &rv));
1806 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1807 nsCOMPtr<nsIStreamListener> toListener(mListener);
1808 nsCOMPtr<nsIStreamListener> fromListener;
1809
1810 rv = convServ->AsyncConvertData("multipart/x-mixed-replace", "*/*",
1811 toListener, nullptr,
1812 getter_AddRefs(fromListener));
1813 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1814 mListener = fromListener;
1815 mustRunStreamFilterInParent = true;
1816 }
1817 }
1818 }
1819 }
1820
1821 // If we installed a multipart converter, then we need to add StreamFilter
1822 // object before it, so that extensions see the un-parsed original stream.
1823 // We may want to add an option for extensions to opt-in to proper multipart
1824 // handling.
1825 // If not, then pass the StreamFilter promise on to DocumentLoadListener,
1826 // where it'll be added in the content process.
1827 for (StreamFilterRequest& request : mStreamFilterRequests) {
1828 if (mustRunStreamFilterInParent) {
1829 mozilla::ipc::Endpoint<extensions::PStreamFilterParent> parent;
1830 mozilla::ipc::Endpoint<extensions::PStreamFilterChild> child;
1831 nsresult rv = extensions::PStreamFilter::CreateEndpoints(&parent, &child);
1832 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1833 request.mPromise->Reject(false, __func__);
1834 } else {
1835 extensions::StreamFilterParent::Attach(this, std::move(parent));
1836 request.mPromise->Resolve(std::move(child), __func__);
1837 }
1838 } else {
1839 if (docListener) {
1840 docListener->AttachStreamFilter()->ChainTo(request.mPromise.forget(),
1841 __func__);
1842 } else {
1843 request.mPromise->Reject(false, __func__);
1844 }
1845 }
1846 request.mPromise = nullptr;
1847 }
1848 mStreamFilterRequests.Clear();
1849 StoreTracingEnabled(false);
1850
1851 if (mResponseHead && !mResponseHead->HasContentCharset()) {
1852 mResponseHead->SetContentCharset(mContentCharsetHint);
1853 }
1854
1855 if (mCacheEntry && LoadCacheEntryIsWriteOnly()) {
1856 SetCachedContentType();
1857 }
1858
1859 LOG((" calling mListener->OnStartRequest [this=%p, listener=%p]\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " calling mListener->OnStartRequest [this=%p, listener=%p]\n"
, this, mListener.get()); } } while (0)
1860 mListener.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " calling mListener->OnStartRequest [this=%p, listener=%p]\n"
, this, mListener.get()); } } while (0)
;
1861
1862 // About to call OnStartRequest, dismiss the guard object.
1863 onStartGuard.release();
1864
1865 if (mListener) {
1866 MOZ_ASSERT(!LoadOnStartRequestCalled(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadOnStartRequestCalled())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!LoadOnStartRequestCalled())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!LoadOnStartRequestCalled()"
" (" "We should not call OsStartRequest twice" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1867); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!LoadOnStartRequestCalled()"
") (" "We should not call OsStartRequest twice" ")"); do { *
((volatile int*)__null) = 1867; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
1867 "We should not call OsStartRequest twice")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadOnStartRequestCalled())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!LoadOnStartRequestCalled())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!LoadOnStartRequestCalled()"
" (" "We should not call OsStartRequest twice" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1867); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!LoadOnStartRequestCalled()"
") (" "We should not call OsStartRequest twice" ")"); do { *
((volatile int*)__null) = 1867; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
1868 nsCOMPtr<nsIStreamListener> deleteProtector(mListener);
1869 StoreOnStartRequestCalled(true);
1870 rv = deleteProtector->OnStartRequest(this);
1871 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
1872 } else {
1873 NS_WARNING("OnStartRequest skipped because of null listener")NS_DebugBreak(NS_DEBUG_WARNING, "OnStartRequest skipped because of null listener"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1873)
;
1874 StoreOnStartRequestCalled(true);
1875 }
1876
1877 // Install stream converter if required.
1878 // Normally, we expect the listener to disable content conversion during
1879 // OnStartRequest if it wants to handle it itself (which is common case with
1880 // HttpChannelParent, disabling so that it can be done in the content
1881 // process). If we've installed an nsUnknownDecoder, then we won't yet have
1882 // called OnStartRequest on the final listener (that happens after we send
1883 // OnDataAvailable to the nsUnknownDecoder), so it can't yet have disabled
1884 // content conversion.
1885 // In that case, assume that the listener will disable content conversion,
1886 // unless it's specifically told us that it won't.
1887 if (!unknownDecoderStarted || LoadListenerRequiresContentConversion()) {
1888 nsCOMPtr<nsIStreamListener> listener;
1889 rv =
1890 DoApplyContentConversions(mListener, getter_AddRefs(listener), nullptr);
1891 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1892 return rv;
1893 }
1894 if (listener) {
1895 MOZ_ASSERT(!LoadDataSentToChildProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadDataSentToChildProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!LoadDataSentToChildProcess(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!LoadDataSentToChildProcess()" " (" "DataSentToChildProcess being true means ODAs are sent to "
"the child process directly. We MUST NOT apply content " "converter in this case."
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!LoadDataSentToChildProcess()"
") (" "DataSentToChildProcess being true means ODAs are sent to "
"the child process directly. We MUST NOT apply content " "converter in this case."
")"); do { *((volatile int*)__null) = 1898; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1896 "DataSentToChildProcess being true means ODAs are sent to "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadDataSentToChildProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!LoadDataSentToChildProcess(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!LoadDataSentToChildProcess()" " (" "DataSentToChildProcess being true means ODAs are sent to "
"the child process directly. We MUST NOT apply content " "converter in this case."
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!LoadDataSentToChildProcess()"
") (" "DataSentToChildProcess being true means ODAs are sent to "
"the child process directly. We MUST NOT apply content " "converter in this case."
")"); do { *((volatile int*)__null) = 1898; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1897 "the child process directly. We MUST NOT apply content "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadDataSentToChildProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!LoadDataSentToChildProcess(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!LoadDataSentToChildProcess()" " (" "DataSentToChildProcess being true means ODAs are sent to "
"the child process directly. We MUST NOT apply content " "converter in this case."
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!LoadDataSentToChildProcess()"
") (" "DataSentToChildProcess being true means ODAs are sent to "
"the child process directly. We MUST NOT apply content " "converter in this case."
")"); do { *((volatile int*)__null) = 1898; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1898 "converter in this case.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadDataSentToChildProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!LoadDataSentToChildProcess(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!LoadDataSentToChildProcess()" " (" "DataSentToChildProcess being true means ODAs are sent to "
"the child process directly. We MUST NOT apply content " "converter in this case."
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!LoadDataSentToChildProcess()"
") (" "DataSentToChildProcess being true means ODAs are sent to "
"the child process directly. We MUST NOT apply content " "converter in this case."
")"); do { *((volatile int*)__null) = 1898; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1899 mListener = listener;
1900 mCompressListener = listener;
1901
1902 StoreHasAppliedConversion(true);
1903 }
1904 }
1905
1906 // if this channel is for a download, close off access to the cache.
1907 if (mCacheEntry && LoadChannelIsForDownload()) {
1908 mCacheEntry->AsyncDoom(nullptr);
1909
1910 // We must keep the cache entry in case of partial request.
1911 // Concurrent access is the same, we need the entry in
1912 // OnStopRequest.
1913 // We also need the cache entry when racing cache with network to find
1914 // out what is the source of the data.
1915 if (!LoadCachedContentIsPartial() && !LoadConcurrentCacheAccess() &&
1916 !(mRaceCacheWithNetwork &&
1917 mFirstResponseSource == RESPONSE_FROM_CACHE)) {
1918 CloseCacheEntry(false);
1919 }
1920 }
1921
1922 return NS_OK;
1923}
1924
1925NS_IMETHODIMPnsresult nsHttpChannel::GetHttpProxyConnectResponseCode(
1926 int32_t* aResponseCode) {
1927 NS_ENSURE_ARG_POINTER(aResponseCode)do { if ((__builtin_expect(!!(!(aResponseCode)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aResponseCode" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1927); return NS_ERROR_INVALID_POINTER; } } while (false)
;
1928
1929 if (mConnectionInfo && mConnectionInfo->UsingConnect()) {
1930 *aResponseCode = mProxyConnectResponseCode;
1931 } else {
1932 *aResponseCode = -1;
1933 }
1934 return NS_OK;
1935}
1936
1937nsresult nsHttpChannel::ProcessFailedProxyConnect(uint32_t httpStatus) {
1938 // Failure to set up a proxy tunnel via CONNECT means one of the following:
1939 // 1) Proxy wants authorization, or forbids.
1940 // 2) DNS at proxy couldn't resolve target URL.
1941 // 3) Proxy connection to target failed or timed out.
1942 // 4) Eve intercepted our CONNECT, and is replying with malicious HTML.
1943 //
1944 // Our current architecture would parse the proxy's response content with
1945 // the permission of the target URL. Given #4, we must avoid rendering the
1946 // body of the reply, and instead give the user a (hopefully helpful)
1947 // boilerplate error page, based on just the HTTP status of the reply.
1948
1949 MOZ_ASSERT(mConnectionInfo->UsingConnect(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mConnectionInfo->UsingConnect())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mConnectionInfo->UsingConnect
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mConnectionInfo->UsingConnect()" " (" "proxy connect failed but not using CONNECT?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1950); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mConnectionInfo->UsingConnect()"
") (" "proxy connect failed but not using CONNECT?" ")"); do
{ *((volatile int*)__null) = 1950; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
1950 "proxy connect failed but not using CONNECT?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mConnectionInfo->UsingConnect())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mConnectionInfo->UsingConnect
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mConnectionInfo->UsingConnect()" " (" "proxy connect failed but not using CONNECT?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1950); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mConnectionInfo->UsingConnect()"
") (" "proxy connect failed but not using CONNECT?" ")"); do
{ *((volatile int*)__null) = 1950; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1951 nsresult rv = HttpProxyResponseToErrorCode(httpStatus);
1952 LOG(("Cancelling failed proxy CONNECT [this=%p httpStatus=%u]\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Cancelling failed proxy CONNECT [this=%p httpStatus=%u]\n"
, this, httpStatus); } } while (0)
1953 httpStatus))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Cancelling failed proxy CONNECT [this=%p httpStatus=%u]\n"
, this, httpStatus); } } while (0)
;
1954
1955 // Make sure the connection is thrown away as it can be in a bad state
1956 // and the proxy may just hang on the next request.
1957 MOZ_ASSERT(mTransaction)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTransaction)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTransaction))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mTransaction", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 1957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTransaction"
")"); do { *((volatile int*)__null) = 1957; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1958 mTransaction->DontReuseConnection();
1959
1960 Cancel(rv);
1961 {
1962 nsresult rv = CallOnStartRequest();
1963 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1964 LOG(("CallOnStartRequest failed [this=%p httpStatus=%u rv=%08x]\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CallOnStartRequest failed [this=%p httpStatus=%u rv=%08x]\n"
, this, httpStatus, static_cast<uint32_t>(rv)); } } while
(0)
1965 httpStatus, static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CallOnStartRequest failed [this=%p httpStatus=%u rv=%08x]\n"
, this, httpStatus, static_cast<uint32_t>(rv)); } } while
(0)
;
1966 }
1967 }
1968 return rv;
1969}
1970
1971static void GetSTSConsoleErrorTag(uint32_t failureResult,
1972 nsAString& consoleErrorTag) {
1973 switch (failureResult) {
1974 case nsISiteSecurityService::ERROR_COULD_NOT_PARSE_HEADER:
1975 consoleErrorTag = u"STSCouldNotParseHeader"_ns;
1976 break;
1977 case nsISiteSecurityService::ERROR_NO_MAX_AGE:
1978 consoleErrorTag = u"STSNoMaxAge"_ns;
1979 break;
1980 case nsISiteSecurityService::ERROR_MULTIPLE_MAX_AGES:
1981 consoleErrorTag = u"STSMultipleMaxAges"_ns;
1982 break;
1983 case nsISiteSecurityService::ERROR_INVALID_MAX_AGE:
1984 consoleErrorTag = u"STSInvalidMaxAge"_ns;
1985 break;
1986 case nsISiteSecurityService::ERROR_MULTIPLE_INCLUDE_SUBDOMAINS:
1987 consoleErrorTag = u"STSMultipleIncludeSubdomains"_ns;
1988 break;
1989 case nsISiteSecurityService::ERROR_INVALID_INCLUDE_SUBDOMAINS:
1990 consoleErrorTag = u"STSInvalidIncludeSubdomains"_ns;
1991 break;
1992 case nsISiteSecurityService::ERROR_COULD_NOT_SAVE_STATE:
1993 consoleErrorTag = u"STSCouldNotSaveState"_ns;
1994 break;
1995 default:
1996 consoleErrorTag = u"STSUnknownError"_ns;
1997 break;
1998 }
1999}
2000
2001/**
2002 * Process an HTTP Strict Transport Security (HSTS) header.
2003 */
2004nsresult nsHttpChannel::ProcessHSTSHeader(nsITransportSecurityInfo* aSecInfo) {
2005 nsHttpAtom atom(nsHttp::ResolveAtom("Strict-Transport-Security"_ns));
2006
2007 nsAutoCString securityHeader;
2008 nsresult rv = mResponseHead->GetHeader(atom, securityHeader);
2009 if (rv == NS_ERROR_NOT_AVAILABLE) {
2010 LOG(("nsHttpChannel: No %s header, continuing load.\n", atom.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel: No %s header, continuing load.\n", atom.get
()); } } while (0)
;
2011 return NS_OK;
2012 }
2013 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2013)
) {
2014 return rv;
2015 }
2016
2017 if (!aSecInfo) {
2018 LOG(("nsHttpChannel::ProcessHSTSHeader: no securityInfo?"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessHSTSHeader: no securityInfo?"); } } while
(0)
;
2019 return NS_ERROR_INVALID_ARG;
2020 }
2021 nsITransportSecurityInfo::OverridableErrorCategory overridableErrorCategory;
2022 rv = aSecInfo->GetOverridableErrorCategory(&overridableErrorCategory);
2023 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2023)
) {
2024 return rv;
2025 }
2026 if (overridableErrorCategory !=
2027 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET) {
2028 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessHSTSHeader: untrustworthy connection - not "
"processing header"); } } while (0)
2029 ("nsHttpChannel::ProcessHSTSHeader: untrustworthy connection - not "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessHSTSHeader: untrustworthy connection - not "
"processing header"); } } while (0)
2030 "processing header"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessHSTSHeader: untrustworthy connection - not "
"processing header"); } } while (0)
;
2031 return NS_ERROR_FAILURE;
2032 }
2033
2034 nsISiteSecurityService* sss = gHttpHandler->GetSSService();
2035 NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY)do { if ((__builtin_expect(!!(!(sss)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "sss" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2035); return NS_ERROR_OUT_OF_MEMORY; } } while (false)
;
2036
2037 OriginAttributes originAttributes;
2038 if (NS_WARN_IF(!StoragePrincipalHelper::GetOriginAttributesForHSTS(NS_warn_if_impl(!StoragePrincipalHelper::GetOriginAttributesForHSTS
( this, originAttributes), "!StoragePrincipalHelper::GetOriginAttributesForHSTS( this, originAttributes)"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2039)
2039 this, originAttributes))NS_warn_if_impl(!StoragePrincipalHelper::GetOriginAttributesForHSTS
( this, originAttributes), "!StoragePrincipalHelper::GetOriginAttributesForHSTS( this, originAttributes)"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2039)
) {
2040 return NS_ERROR_FAILURE;
2041 }
2042
2043 uint32_t failureResult;
2044 rv = sss->ProcessHeader(mURI, securityHeader, originAttributes, nullptr,
2045 nullptr, &failureResult);
2046 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2047 nsAutoString consoleErrorCategory(u"Invalid HSTS Headers"_ns);
2048 nsAutoString consoleErrorTag;
2049 GetSTSConsoleErrorTag(failureResult, consoleErrorTag);
2050 Unused << AddSecurityMessage(consoleErrorTag, consoleErrorCategory);
2051 LOG(("nsHttpChannel: Failed to parse %s header, continuing load.\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel: Failed to parse %s header, continuing load.\n"
, atom.get()); } } while (0)
2052 atom.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel: Failed to parse %s header, continuing load.\n"
, atom.get()); } } while (0)
;
2053 }
2054 return NS_OK;
2055}
2056
2057/**
2058 * Decide whether or not to remember Strict-Transport-Security, and whether
2059 * or not to enforce channel integrity.
2060 *
2061 * @return NS_ERROR_FAILURE if there's security information missing even though
2062 * it's an HTTPS connection.
2063 */
2064nsresult nsHttpChannel::ProcessSecurityHeaders() {
2065 // If this channel is not loading securely, STS or PKP doesn't do anything.
2066 // In the case of HSTS, the upgrade to HTTPS takes place earlier in the
2067 // channel load process.
2068 if (!mURI->SchemeIs("https")) {
2069 return NS_OK;
2070 }
2071
2072 if (IsBrowsingContextDiscarded()) {
2073 return NS_OK;
2074 }
2075
2076 nsAutoCString asciiHost;
2077 nsresult rv = mURI->GetAsciiHost(asciiHost);
2078 NS_ENSURE_SUCCESS(rv, NS_OK)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "NS_OK", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2078); return NS_OK; } } while (false)
;
2079
2080 // If the channel is not a hostname, but rather an IP, do not process STS
2081 // or PKP headers
2082 if (HostIsIPLiteral(asciiHost)) {
2083 return NS_OK;
2084 }
2085
2086 // mSecurityInfo may not always be present, and if it's not then it is okay
2087 // to just disregard any security headers since we know nothing about the
2088 // security of the connection.
2089 NS_ENSURE_TRUE(mSecurityInfo, NS_OK)do { if ((__builtin_expect(!!(!(mSecurityInfo)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mSecurityInfo" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2089); return NS_OK; } } while (false)
;
2090
2091 // Only process HSTS headers for first-party loads. This prevents a
2092 // proliferation of useless HSTS state for partitioned third parties.
2093 if (!mLoadInfo->GetIsThirdPartyContextToTopWindow()) {
2094 rv = ProcessHSTSHeader(mSecurityInfo);
2095 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2095); return rv; } } while (false)
;
2096 }
2097
2098 return NS_OK;
2099}
2100
2101bool nsHttpChannel::IsHTTPS() { return mURI->SchemeIs("https"); }
2102
2103void nsHttpChannel::ProcessSSLInformation() {
2104 // If this is HTTPS, record any use of RSA so that Key Exchange Algorithm
2105 // can be whitelisted for TLS False Start in future sessions. We could
2106 // do the same for DH but its rarity doesn't justify the lookup.
2107
2108 if (mCanceled || NS_FAILED(mStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(mStatus)), 0))) || !mSecurityInfo || !IsHTTPS() ||
2109 mPrivateBrowsing) {
2110 return;
2111 }
2112
2113 if (!mSecurityInfo) {
2114 return;
2115 }
2116
2117 uint32_t state;
2118 if (NS_SUCCEEDED(mSecurityInfo->GetSecurityState(&state))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mSecurityInfo->
GetSecurityState(&state))), 1)))
&&
2119 (state & nsIWebProgressListener::STATE_IS_BROKEN)) {
2120 // Send weak crypto warnings to the web console
2121 if (state & nsIWebProgressListener::STATE_USES_WEAK_CRYPTO) {
2122 nsString consoleErrorTag = u"WeakCipherSuiteWarning"_ns;
2123 nsString consoleErrorCategory = u"SSL"_ns;
2124 Unused << AddSecurityMessage(consoleErrorTag, consoleErrorCategory);
2125 }
2126 }
2127
2128 uint16_t tlsVersion;
2129 nsresult rv = mSecurityInfo->GetProtocolVersion(&tlsVersion);
2130 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) &&
2131 tlsVersion != nsITransportSecurityInfo::TLS_VERSION_1_2 &&
2132 tlsVersion != nsITransportSecurityInfo::TLS_VERSION_1_3) {
2133 nsString consoleErrorTag = u"DeprecatedTLSVersion2"_ns;
2134 nsString consoleErrorCategory = u"TLS"_ns;
2135 Unused << AddSecurityMessage(consoleErrorTag, consoleErrorCategory);
2136 }
2137}
2138
2139void nsHttpChannel::ProcessAltService() {
2140 // e.g. Alt-Svc: h2=":443"; ma=60
2141 // e.g. Alt-Svc: h2="otherhost:443"
2142 // Alt-Svc = 1#( alternative *( OWS ";" OWS parameter ) )
2143 // alternative = protocol-id "=" alt-authority
2144 // protocol-id = token ; percent-encoded ALPN protocol identifier
2145 // alt-authority = quoted-string ; containing [ uri-host ] ":" port
2146
2147 if (!LoadAllowAltSvc()) { // per channel opt out
2148 return;
2149 }
2150
2151 if (mWebTransportSessionEventListener) {
2152 return;
2153 }
2154
2155 if (!gHttpHandler->AllowAltSvc() || (mCaps & NS_HTTP_DISALLOW_SPDY(1 << 7))) {
2156 return;
2157 }
2158
2159 if (IsBrowsingContextDiscarded()) {
2160 return;
2161 }
2162
2163 nsAutoCString scheme;
2164 mURI->GetScheme(scheme);
2165 bool isHttp = scheme.EqualsLiteral("http");
2166 if (!isHttp && !scheme.EqualsLiteral("https")) {
2167 return;
2168 }
2169
2170 nsAutoCString altSvc;
2171 Unused << mResponseHead->GetHeader(nsHttp::Alternate_Service, altSvc);
2172 if (altSvc.IsEmpty()) {
2173 return;
2174 }
2175
2176 if (!nsHttp::IsReasonableHeaderValue(altSvc)) {
2177 LOG(("Alt-Svc Response Header seems unreasonable - skipping\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Alt-Svc Response Header seems unreasonable - skipping\n");
} } while (0)
;
2178 return;
2179 }
2180
2181 nsAutoCString originHost;
2182 int32_t originPort = 80;
2183 mURI->GetPort(&originPort);
2184 if (NS_FAILED(mURI->GetAsciiHost(originHost))((bool)(__builtin_expect(!!(NS_FAILED_impl(mURI->GetAsciiHost
(originHost))), 0)))
) {
2185 return;
2186 }
2187
2188 nsCOMPtr<nsIInterfaceRequestor> callbacks;
2189 nsCOMPtr<nsProxyInfo> proxyInfo;
2190 NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
2191 getter_AddRefs(callbacks));
2192
2193 if (mProxyInfo) {
2194 proxyInfo = do_QueryInterface(mProxyInfo);
2195 }
2196
2197 OriginAttributes originAttributes;
2198 // Regular principal in case we have a proxy.
2199 if (proxyInfo &&
2200 !StaticPrefs::privacy_partition_network_state_connection_with_proxy()) {
2201 StoragePrincipalHelper::GetOriginAttributes(
2202 this, originAttributes, StoragePrincipalHelper::eRegularPrincipal);
2203 } else {
2204 StoragePrincipalHelper::GetOriginAttributesForNetworkState(
2205 this, originAttributes);
2206 }
2207
2208 AltSvcMapping::ProcessHeader(
2209 altSvc, scheme, originHost, originPort, mUsername, mPrivateBrowsing,
2210 callbacks, proxyInfo, mCaps & NS_HTTP_DISALLOW_SPDY(1 << 7), originAttributes);
2211}
2212
2213nsresult nsHttpChannel::ProcessResponse() {
2214 uint32_t httpStatus = mResponseHead->Status();
2215
2216 LOG(("nsHttpChannel::ProcessResponse [this=%p httpStatus=%u]\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessResponse [this=%p httpStatus=%u]\n",
this, httpStatus); } } while (0)
2217 httpStatus))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessResponse [this=%p httpStatus=%u]\n",
this, httpStatus); } } while (0)
;
2218
2219 // Gather data on whether the transaction and page (if this is
2220 // the initial page load) is being loaded with SSL.
2221 Telemetry::Accumulate(Telemetry::HTTP_TRANSACTION_IS_SSL,
2222 mConnectionInfo->EndToEndSSL());
2223 if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI) {
2224 Telemetry::Accumulate(Telemetry::HTTP_PAGELOAD_IS_SSL,
2225 mConnectionInfo->EndToEndSSL());
2226 }
2227
2228 if (Telemetry::CanRecordPrereleaseData()) {
2229 // how often do we see something like Alt-Svc: "443:quic,p=1"
2230 // and Alt-Svc: "h3-****"
2231 nsAutoCString alt_service;
2232 Unused << mResponseHead->GetHeader(nsHttp::Alternate_Service, alt_service);
2233 uint32_t saw_quic = 0;
2234 if (!alt_service.IsEmpty()) {
2235 if (strstr(alt_service.get(), "h3-")) {
2236 saw_quic = 1;
2237 } else if (strstr(alt_service.get(), "quic")) {
2238 saw_quic = 2;
2239 }
2240 }
2241 Telemetry::Accumulate(Telemetry::HTTP_SAW_QUIC_ALT_PROTOCOL_2, saw_quic);
2242
2243 // Gather data on how many URLS get redirected
2244 switch (httpStatus) {
2245 case 200:
2246 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 0);
2247 break;
2248 case 301:
2249 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 1);
2250 break;
2251 case 302:
2252 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 2);
2253 break;
2254 case 304:
2255 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 3);
2256 break;
2257 case 307:
2258 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 4);
2259 break;
2260 case 308:
2261 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 5);
2262 break;
2263 case 400:
2264 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 6);
2265 break;
2266 case 401:
2267 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 7);
2268 break;
2269 case 403:
2270 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 8);
2271 break;
2272 case 404:
2273 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 9);
2274 break;
2275 case 500:
2276 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 10);
2277 break;
2278 default:
2279 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_STATUS_CODE, 11);
2280 break;
2281 }
2282 }
2283
2284 // Let the predictor know whether this was a cacheable response or not so
2285 // that it knows whether or not to possibly prefetch this resource in the
2286 // future.
2287 // We use GetReferringPage because mReferrerInfo may not be set at all(this is
2288 // especially useful in xpcshell tests, where we don't have an actual pageload
2289 // to get a referrer from).
2290 nsCOMPtr<nsIURI> referrer = GetReferringPage();
2291 if (!referrer && mReferrerInfo) {
2292 referrer = mReferrerInfo->GetOriginalReferrer();
2293 }
2294
2295 if (referrer) {
2296 nsCOMPtr<nsILoadContextInfo> lci = GetLoadContextInfo(this);
2297 mozilla::net::Predictor::UpdateCacheability(
2298 referrer, mURI, httpStatus, mRequestHead, mResponseHead.get(), lci,
2299 IsThirdPartyTrackingResource());
2300 }
2301
2302 // Only allow 407 (authentication required) to continue
2303 if (mTransaction && mTransaction->ProxyConnectFailed() && httpStatus != 407) {
2304 return ProcessFailedProxyConnect(httpStatus);
2305 }
2306
2307 MOZ_ASSERT(!mCachedContentIsValid || mRaceCacheWithNetwork,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCachedContentIsValid || mRaceCacheWithNetwork)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mCachedContentIsValid || mRaceCacheWithNetwork))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!mCachedContentIsValid || mRaceCacheWithNetwork"
" (" "We should not be hitting the network if we have valid cached "
"content unless we are racing the network and cache" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2309); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCachedContentIsValid || mRaceCacheWithNetwork"
") (" "We should not be hitting the network if we have valid cached "
"content unless we are racing the network and cache" ")"); do
{ *((volatile int*)__null) = 2309; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2308 "We should not be hitting the network if we have valid cached "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCachedContentIsValid || mRaceCacheWithNetwork)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mCachedContentIsValid || mRaceCacheWithNetwork))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!mCachedContentIsValid || mRaceCacheWithNetwork"
" (" "We should not be hitting the network if we have valid cached "
"content unless we are racing the network and cache" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2309); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCachedContentIsValid || mRaceCacheWithNetwork"
") (" "We should not be hitting the network if we have valid cached "
"content unless we are racing the network and cache" ")"); do
{ *((volatile int*)__null) = 2309; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2309 "content unless we are racing the network and cache")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCachedContentIsValid || mRaceCacheWithNetwork)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mCachedContentIsValid || mRaceCacheWithNetwork))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!mCachedContentIsValid || mRaceCacheWithNetwork"
" (" "We should not be hitting the network if we have valid cached "
"content unless we are racing the network and cache" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2309); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCachedContentIsValid || mRaceCacheWithNetwork"
") (" "We should not be hitting the network if we have valid cached "
"content unless we are racing the network and cache" ")"); do
{ *((volatile int*)__null) = 2309; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2310
2311 ProcessSSLInformation();
2312
2313 // notify "http-on-examine-response" observers
2314 gHttpHandler->OnExamineResponse(this);
2315
2316 return ContinueProcessResponse1();
2317}
2318
2319void nsHttpChannel::AsyncContinueProcessResponse() {
2320 nsresult rv;
2321 rv = ContinueProcessResponse1();
2322 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2323 // A synchronous failure here would normally be passed as the return
2324 // value from OnStartRequest, which would in turn cancel the request.
2325 // If we're continuing asynchronously, we need to cancel the request
2326 // ourselves.
2327 Unused << Cancel(rv);
2328 }
2329}
2330
2331nsresult nsHttpChannel::ContinueProcessResponse1() {
2332 MOZ_ASSERT(!mCallOnResume, "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCallOnResume)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCallOnResume))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mCallOnResume"
" (" "How did that happen?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2332); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCallOnResume"
") (" "How did that happen?" ")"); do { *((volatile int*)__null
) = 2332; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
2333 nsresult rv = NS_OK;
2334
2335 if (mSuspendCount) {
2336 LOG(("Waiting until resume to finish processing response [this=%p]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume to finish processing response [this=%p]\n"
, this); } } while (0)
2337 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume to finish processing response [this=%p]\n"
, this); } } while (0)
;
2338 mCallOnResume = [](nsHttpChannel* self) {
2339 self->AsyncContinueProcessResponse();
2340 return NS_OK;
2341 };
2342 return NS_OK;
2343 }
2344
2345 // Check if request was cancelled during http-on-examine-response.
2346 if (mCanceled) {
2347 return CallOnStartRequest();
2348 }
2349
2350 uint32_t httpStatus = mResponseHead->Status();
2351
2352 // STS, Cookies and Alt-Service should not be handled on proxy failure.
2353 // If proxy CONNECT response needs to complete, wait to process connection
2354 // for Strict-Transport-Security.
2355 if (!(mTransaction && mTransaction->ProxyConnectFailed()) &&
2356 (httpStatus != 407)) {
2357 if (nsAutoCString cookie;
2358 NS_SUCCEEDED(mResponseHead->GetHeader(nsHttp::Set_Cookie, cookie))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mResponseHead->
GetHeader(nsHttp::Set_Cookie, cookie))), 1)))
) {
2359 SetCookie(cookie);
2360 nsCOMPtr<nsIParentChannel> parentChannel;
2361 NS_QueryNotificationCallbacks(this, parentChannel);
2362 if (RefPtr<HttpChannelParent> httpParent =
2363 do_QueryObject(parentChannel)) {
2364 httpParent->SetCookie(std::move(cookie));
2365 }
2366 }
2367
2368 // Given a successful connection, process any STS or PKP data that's
2369 // relevant.
2370 nsresult rv = ProcessSecurityHeaders();
2371 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2372 NS_WARNING("ProcessSTSHeader failed, continuing load.")NS_DebugBreak(NS_DEBUG_WARNING, "ProcessSTSHeader failed, continuing load."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2372)
;
2373 }
2374
2375 if ((httpStatus < 500) && (httpStatus != 421)) {
2376 ProcessAltService();
2377 }
2378 }
2379
2380 if (LoadConcurrentCacheAccess() && LoadCachedContentIsPartial() &&
2381 httpStatus != 206) {
2382 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " only expecting 206 when doing partial request during " "interrupted cache concurrent read"
); } } while (0)
2383 (" only expecting 206 when doing partial request during "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " only expecting 206 when doing partial request during " "interrupted cache concurrent read"
); } } while (0)
2384 "interrupted cache concurrent read"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " only expecting 206 when doing partial request during " "interrupted cache concurrent read"
); } } while (0)
;
2385 return NS_ERROR_CORRUPTED_CONTENT;
2386 }
2387
2388 // handle unused username and password in url (see bug 232567)
2389 if (httpStatus != 401 && httpStatus != 407) {
2390 if (!mAuthRetryPending) {
2391 rv = mAuthProvider->CheckForSuperfluousAuth();
2392 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2393 mStatus = rv;
2394 LOG((" CheckForSuperfluousAuth failed (%08x)",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " CheckForSuperfluousAuth failed (%08x)", static_cast<uint32_t
>(rv)); } } while (0)
2395 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " CheckForSuperfluousAuth failed (%08x)", static_cast<uint32_t
>(rv)); } } while (0)
;
2396 }
2397 }
2398 if (mCanceled) return CallOnStartRequest();
2399
2400 // reset the authentication's current continuation state because ourvr
2401 // last authentication attempt has been completed successfully
2402 rv = mAuthProvider->Disconnect(NS_ERROR_ABORT);
2403 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2404 LOG((" Disconnect failed (%08x)", static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " Disconnect failed (%08x)", static_cast<uint32_t>(rv
)); } } while (0)
;
2405 }
2406 mAuthProvider = nullptr;
2407 LOG((" continuation state has been reset"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " continuation state has been reset"); } } while (0)
;
2408 }
2409
2410 // No process switch needed, continue as normal.
2411 return ContinueProcessResponse2(rv);
2412}
2413
2414nsresult nsHttpChannel::ContinueProcessResponse2(nsresult rv) {
2415 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && !mCanceled) {
2416 // The process switch failed, cancel this channel.
2417 Cancel(rv);
2418 return CallOnStartRequest();
2419 }
2420
2421 if (mAPIRedirectToURI && !mCanceled) {
2422 MOZ_ASSERT(!LoadOnStartRequestCalled())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!LoadOnStartRequestCalled())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!LoadOnStartRequestCalled())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!LoadOnStartRequestCalled()"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2422); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!LoadOnStartRequestCalled()"
")"); do { *((volatile int*)__null) = 2422; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2423 nsCOMPtr<nsIURI> redirectTo;
2424 mAPIRedirectToURI.swap(redirectTo);
2425
2426 PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessResponse3);
2427 rv = StartRedirectChannelToURI(redirectTo,
2428 nsIChannelEventSink::REDIRECT_TEMPORARY);
2429 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2430 return NS_OK;
2431 }
2432 PopRedirectAsyncFunc(&nsHttpChannel::ContinueProcessResponse3);
2433 }
2434
2435 // Hack: ContinueProcessResponse3 uses NS_OK to detect successful
2436 // redirects, so we distinguish this codepath (a non-redirect that's
2437 // processing normally) by passing in a bogus error code.
2438 return ContinueProcessResponse3(NS_BINDING_FAILED);
2439}
2440
2441nsresult nsHttpChannel::ContinueProcessResponse3(nsresult rv) {
2442 LOG(("nsHttpChannel::ContinueProcessResponse3 [this=%p, rv=%" PRIx32 "]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueProcessResponse3 [this=%p, rv=%" "x"
"]", this, static_cast<uint32_t>(rv)); } } while (0)
2443 this, static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueProcessResponse3 [this=%p, rv=%" "x"
"]", this, static_cast<uint32_t>(rv)); } } while (0)
;
2444
2445 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2446 // redirectTo() has passed through, we don't want to go on with
2447 // this channel. It will now be canceled by the redirect handling
2448 // code that called this function.
2449 return NS_OK;
2450 }
2451
2452 rv = NS_OK;
2453
2454 uint32_t httpStatus = mResponseHead->Status();
2455 bool transactionRestarted = mTransaction->TakeRestartedState();
2456
2457 // handle different server response categories. Note that we handle
2458 // caching or not caching of error pages in
2459 // nsHttpResponseHead::MustValidate; if you change this switch, update that
2460 // one
2461 switch (httpStatus) {
2462 case 200:
2463 case 203:
2464 // Per RFC 2616, 14.35.2, "A server MAY ignore the Range header".
2465 // So if a server does that and sends 200 instead of 206 that we
2466 // expect, notify our caller.
2467 // However, if we wanted to start from the beginning, let it go through
2468 if (LoadResuming() && mStartPos != 0) {
2469 LOG(("Server ignored our Range header, cancelling [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Server ignored our Range header, cancelling [this=%p]\n", this
); } } while (0)
;
2470 Cancel(NS_ERROR_NOT_RESUMABLE);
2471 rv = CallOnStartRequest();
2472 break;
2473 }
2474 // these can normally be cached
2475 rv = ProcessNormal();
2476 MaybeInvalidateCacheEntryForSubsequentGet();
2477 break;
2478 case 206:
2479 if (LoadCachedContentIsPartial()) { // an internal byte range request...
2480 auto func = [](auto* self, nsresult aRv) {
2481 return self->ContinueProcessResponseAfterPartialContent(aRv);
2482 };
2483 rv = ProcessPartialContent(func);
2484 // Directly call ContinueProcessResponseAfterPartialContent if channel
2485 // is not suspended or ProcessPartialContent throws.
2486 if (!mSuspendCount || NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2487 return ContinueProcessResponseAfterPartialContent(rv);
2488 }
2489 return NS_OK;
2490 } else {
2491 mCacheInputStream.CloseAndRelease();
2492 rv = ProcessNormal();
2493 }
2494 break;
2495 case 301:
2496 case 302:
2497 case 307:
2498 case 308:
2499 case 303:
2500#if 0
2501 case 305: // disabled as a security measure (see bug 187996).
2502#endif
2503 // don't store the response body for redirects
2504 MaybeInvalidateCacheEntryForSubsequentGet();
2505 PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessResponse4);
2506 rv = AsyncProcessRedirection(httpStatus);
2507 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2508 PopRedirectAsyncFunc(&nsHttpChannel::ContinueProcessResponse4);
2509 LOG(("AsyncProcessRedirection failed [rv=%" PRIx32 "]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "AsyncProcessRedirection failed [rv=%" "x" "]\n", static_cast
<uint32_t>(rv)); } } while (0)
2510 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "AsyncProcessRedirection failed [rv=%" "x" "]\n", static_cast
<uint32_t>(rv)); } } while (0)
;
2511 // don't cache failed redirect responses.
2512 if (mCacheEntry) mCacheEntry->AsyncDoom(nullptr);
2513 if (DoNotRender3xxBody(rv)) {
2514 mStatus = rv;
2515 DoNotifyListener();
2516 } else {
2517 rv = ContinueProcessResponse4(rv);
2518 }
2519 }
2520 break;
2521 case 304:
2522 if (!ShouldBypassProcessNotModified()) {
2523 auto func = [](auto* self, nsresult aRv) {
2524 return self->ContinueProcessResponseAfterNotModified(aRv);
2525 };
2526 rv = ProcessNotModified(func);
2527 // Directly call ContinueProcessResponseAfterNotModified if channel
2528 // is not suspended or ProcessNotModified throws.
2529 if (!mSuspendCount || NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2530 return ContinueProcessResponseAfterNotModified(rv);
2531 }
2532 return NS_OK;
2533 }
2534
2535 // Don't cache uninformative 304
2536 if (LoadCustomConditionalRequest()) {
2537 CloseCacheEntry(false);
2538 }
2539
2540 if (ShouldBypassProcessNotModified() || NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2541 rv = ProcessNormal();
2542 }
2543 break;
2544 case 401:
2545 case 407:
2546 if (MOZ_UNLIKELY(httpStatus == 407 && transactionRestarted)(__builtin_expect(!!(httpStatus == 407 && transactionRestarted
), 0))
) {
2547 // The transaction has been internally restarted. We want to
2548 // authenticate to the proxy again, so reuse either cached credentials
2549 // or use default credentials for NTLM/Negotiate. This prevents
2550 // considering the previously used credentials as invalid.
2551 mAuthProvider->ClearProxyIdent();
2552 }
2553 if (!LoadAuthRedirectedChannel() &&
2554 MOZ_UNLIKELY(LoadCustomAuthHeader())(__builtin_expect(!!(LoadCustomAuthHeader()), 0)) && httpStatus == 401) {
2555 // When a custom auth header fails, we don't want to try
2556 // any cached credentials, nor we want to ask the user.
2557 // It's up to the consumer to re-try w/o setting a custom
2558 // auth header if cached credentials should be attempted.
2559 rv = NS_ERROR_FAILURE;
2560 } else if (httpStatus == 401 &&
2561 StaticPrefs::
2562 network_auth_supress_auth_prompt_for_XFO_failures() &&
2563 !nsContentSecurityUtils::CheckCSPFrameAncestorAndXFO(this)) {
2564 // CSP Frame Ancestor and X-Frame-Options check has failed
2565 // Do not prompt http auth - Bug 1629307
2566 rv = NS_ERROR_FAILURE;
2567 } else {
2568 rv = mAuthProvider->ProcessAuthentication(
2569 httpStatus, mConnectionInfo->EndToEndSSL() && mTransaction &&
2570 mTransaction->ProxyConnectFailed());
2571 }
2572 if (rv == NS_ERROR_IN_PROGRESS) {
2573 // authentication prompt has been invoked and result
2574 // is expected asynchronously
2575 mIsAuthChannel = true;
2576 mAuthRetryPending = true;
2577 if (httpStatus == 407 ||
2578 (mTransaction && mTransaction->ProxyConnectFailed())) {
2579 StoreProxyAuthPending(true);
2580 }
2581
2582 // suspend the transaction pump to stop receiving the
2583 // unauthenticated content data. We will throw that data
2584 // away when user provides credentials or resume the pump
2585 // when user refuses to authenticate.
2586 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Suspending the transaction, asynchronously prompting for "
"credentials"); } } while (0)
2587 ("Suspending the transaction, asynchronously prompting for "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Suspending the transaction, asynchronously prompting for "
"credentials"); } } while (0)
2588 "credentials"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Suspending the transaction, asynchronously prompting for "
"credentials"); } } while (0)
;
2589 mTransactionPump->Suspend();
2590
2591#ifdef DEBUG1
2592 // This is for test purposes only. See bug 1683176 for details.
2593 gHttpHandler->OnTransactionSuspendedDueToAuthentication(this);
2594#endif
2595 rv = NS_OK;
2596 } else if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2597 LOG(("ProcessAuthentication failed [rv=%" PRIx32 "]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ProcessAuthentication failed [rv=%" "x" "]\n", static_cast
<uint32_t>(rv)); } } while (0)
2598 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ProcessAuthentication failed [rv=%" "x" "]\n", static_cast
<uint32_t>(rv)); } } while (0)
;
2599 if (mTransaction && mTransaction->ProxyConnectFailed()) {
2600 return ProcessFailedProxyConnect(httpStatus);
2601 }
2602 if (!mAuthRetryPending) {
2603 rv = mAuthProvider->CheckForSuperfluousAuth();
2604 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2605 mStatus = rv;
2606 LOG(("CheckForSuperfluousAuth failed [rv=%x]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CheckForSuperfluousAuth failed [rv=%x]\n", static_cast<
uint32_t>(rv)); } } while (0)
2607 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CheckForSuperfluousAuth failed [rv=%x]\n", static_cast<
uint32_t>(rv)); } } while (0)
;
2608 }
2609 }
2610 rv = ProcessNormal();
2611 } else {
2612 mIsAuthChannel = true;
2613 mAuthRetryPending = true;
2614 if (StaticPrefs::network_auth_use_redirect_for_retries()) {
2615 if (NS_SUCCEEDED(RedirectToNewChannelForAuthRetry())((bool)(__builtin_expect(!!(!NS_FAILED_impl(RedirectToNewChannelForAuthRetry
())), 1)))
) {
2616 return NS_OK;
2617 }
2618 mAuthRetryPending = false;
2619 rv = ProcessNormal();
2620 }
2621 }
2622 break;
2623
2624 case 408:
2625 case 425:
2626 case 429:
2627 // Do not cache 408, 425 and 429.
2628 CloseCacheEntry(false);
2629 [[fallthrough]]; // process normally
2630 default:
2631 rv = ProcessNormal();
2632 MaybeInvalidateCacheEntryForSubsequentGet();
2633 break;
2634 }
2635
2636 UpdateCacheDisposition(false, false);
2637 return rv;
2638}
2639
2640nsresult nsHttpChannel::ContinueProcessResponseAfterPartialContent(
2641 nsresult aRv) {
2642 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueProcessResponseAfterPartialContent "
"[this=%p, rv=%" "x" "]", this, static_cast<uint32_t>(
aRv)); } } while (0)
2643 ("nsHttpChannel::ContinueProcessResponseAfterPartialContent "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueProcessResponseAfterPartialContent "
"[this=%p, rv=%" "x" "]", this, static_cast<uint32_t>(
aRv)); } } while (0)
2644 "[this=%p, rv=%" PRIx32 "]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueProcessResponseAfterPartialContent "
"[this=%p, rv=%" "x" "]", this, static_cast<uint32_t>(
aRv)); } } while (0)
2645 this, static_cast<uint32_t>(aRv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueProcessResponseAfterPartialContent "
"[this=%p, rv=%" "x" "]", this, static_cast<uint32_t>(
aRv)); } } while (0)
;
2646
2647 UpdateCacheDisposition(false, NS_SUCCEEDED(aRv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1))));
2648 return aRv;
2649}
2650
2651nsresult nsHttpChannel::ContinueProcessResponseAfterNotModified(nsresult aRv) {
2652 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueProcessResponseAfterNotModified " "[this=%p, rv=%"
"x" "]", this, static_cast<uint32_t>(aRv)); } } while (
0)
2653 ("nsHttpChannel::ContinueProcessResponseAfterNotModified "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueProcessResponseAfterNotModified " "[this=%p, rv=%"
"x" "]", this, static_cast<uint32_t>(aRv)); } } while (
0)
2654 "[this=%p, rv=%" PRIx32 "]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueProcessResponseAfterNotModified " "[this=%p, rv=%"
"x" "]", this, static_cast<uint32_t>(aRv)); } } while (
0)
2655 this, static_cast<uint32_t>(aRv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueProcessResponseAfterNotModified " "[this=%p, rv=%"
"x" "]", this, static_cast<uint32_t>(aRv)); } } while (
0)
;
2656
2657 if (NS_SUCCEEDED(aRv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1)))) {
2658 StoreTransactionReplaced(true);
2659 UpdateCacheDisposition(true, false);
2660 return NS_OK;
2661 }
2662
2663 LOG(("ProcessNotModified failed [rv=%" PRIx32 "]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ProcessNotModified failed [rv=%" "x" "]\n", static_cast<
uint32_t>(aRv)); } } while (0)
2664 static_cast<uint32_t>(aRv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ProcessNotModified failed [rv=%" "x" "]\n", static_cast<
uint32_t>(aRv)); } } while (0)
;
2665
2666 // We cannot read from the cache entry, it might be in an
2667 // incosistent state. Doom it and redirect the channel
2668 // to the same URI to reload from the network.
2669 mCacheInputStream.CloseAndRelease();
2670 if (mCacheEntry) {
2671 mCacheEntry->AsyncDoom(nullptr);
2672 mCacheEntry = nullptr;
2673 }
2674
2675 nsresult rv =
2676 StartRedirectChannelToURI(mURI, nsIChannelEventSink::REDIRECT_INTERNAL);
2677 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2678 return NS_OK;
2679 }
2680
2681 // Don't cache uninformative 304
2682 if (LoadCustomConditionalRequest()) {
2683 CloseCacheEntry(false);
2684 }
2685
2686 if (ShouldBypassProcessNotModified() || NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2687 rv = ProcessNormal();
2688 }
2689
2690 UpdateCacheDisposition(false, false);
2691 return rv;
2692}
2693
2694static void ReportHttpResponseVersion(HttpVersion version) {
2695 if (Telemetry::CanRecordPrereleaseData()) {
2696 Telemetry::Accumulate(Telemetry::HTTP_RESPONSE_VERSION,
2697 static_cast<uint32_t>(version));
2698 }
2699
2700 nsAutoCString versionLabel;
2701 switch (version) {
2702 case HttpVersion::v0_9:
2703 case HttpVersion::v1_0:
2704 case HttpVersion::v1_1:
2705 versionLabel = "http_1"_ns;
2706 break;
2707 case HttpVersion::v2_0:
2708 versionLabel = "http_2"_ns;
2709 break;
2710 case HttpVersion::v3_0:
2711 versionLabel = "http_3"_ns;
2712 break;
2713 default:
2714 versionLabel = "unknown"_ns;
2715 break;
2716 }
2717 mozilla::glean::networking::http_response_version.Get(versionLabel).Add(1);
2718}
2719
2720void nsHttpChannel::UpdateCacheDisposition(bool aSuccessfulReval,
2721 bool aPartialContentUsed) {
2722 if (mRaceDelay && !mRaceCacheWithNetwork &&
2723 (LoadCachedContentIsPartial() || mDidReval)) {
2724 if (aSuccessfulReval || aPartialContentUsed) {
2725 AccumulateCategorical(
2726 Telemetry::LABELS_NETWORK_RACE_CACHE_VALIDATION::CachedContentUsed);
2727 } else {
2728 AccumulateCategorical(Telemetry::LABELS_NETWORK_RACE_CACHE_VALIDATION::
2729 CachedContentNotUsed);
2730 }
2731 }
2732
2733 if (Telemetry::CanRecordPrereleaseData()) {
2734 CacheDisposition cacheDisposition;
2735 if (!mDidReval) {
2736 cacheDisposition = kCacheMissed;
2737 } else if (aSuccessfulReval) {
2738 cacheDisposition = kCacheHitViaReval;
2739 } else {
2740 cacheDisposition = kCacheMissedViaReval;
2741 }
2742 AccumulateCacheHitTelemetry(cacheDisposition, this);
2743 mCacheDisposition = cacheDisposition;
2744
2745 if (mResponseHead->Version() == HttpVersion::v0_9) {
2746 // DefaultPortTopLevel = 0, DefaultPortSubResource = 1,
2747 // NonDefaultPortTopLevel = 2, NonDefaultPortSubResource = 3
2748 uint32_t v09Info = 0;
2749 if (!(mLoadFlags & LOAD_INITIAL_DOCUMENT_URI)) {
2750 v09Info += 1;
2751 }
2752 if (mConnectionInfo->OriginPort() != mConnectionInfo->DefaultPort()) {
2753 v09Info += 2;
2754 }
2755 Telemetry::Accumulate(Telemetry::HTTP_09_INFO, v09Info);
2756 }
2757 }
2758
2759 ReportHttpResponseVersion(mResponseHead->Version());
2760}
2761
2762nsresult nsHttpChannel::ContinueProcessResponse4(nsresult rv) {
2763 bool doNotRender = DoNotRender3xxBody(rv);
2764
2765 if (rv == NS_ERROR_DOM_BAD_URI && mRedirectURI) {
2766 bool isHTTP =
2767 mRedirectURI->SchemeIs("http") || mRedirectURI->SchemeIs("https");
2768 if (!isHTTP) {
2769 // This was a blocked attempt to redirect and subvert the system by
2770 // redirecting to another protocol (perhaps javascript:)
2771 // In that case we want to throw an error instead of displaying the
2772 // non-redirected response body.
2773 LOG(("ContinueProcessResponse4 detected rejected Non-HTTP Redirection"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueProcessResponse4 detected rejected Non-HTTP Redirection"
); } } while (0)
;
2774 doNotRender = true;
2775 rv = NS_ERROR_CORRUPTED_CONTENT;
2776 }
2777 }
2778
2779 if (doNotRender) {
2780 Cancel(rv);
2781 DoNotifyListener();
2782 return rv;
2783 }
2784
2785 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2786 UpdateInhibitPersistentCachingFlag();
2787
2788 MaybeCreateCacheEntryWhenRCWN();
2789
2790 rv = InitCacheEntry();
2791 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2792 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueProcessResponse4 " "failed to init cache entry [rv=%x]\n"
, static_cast<uint32_t>(rv)); } } while (0)
2793 ("ContinueProcessResponse4 "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueProcessResponse4 " "failed to init cache entry [rv=%x]\n"
, static_cast<uint32_t>(rv)); } } while (0)
2794 "failed to init cache entry [rv=%x]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueProcessResponse4 " "failed to init cache entry [rv=%x]\n"
, static_cast<uint32_t>(rv)); } } while (0)
2795 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueProcessResponse4 " "failed to init cache entry [rv=%x]\n"
, static_cast<uint32_t>(rv)); } } while (0)
;
2796 }
2797 CloseCacheEntry(false);
2798 return NS_OK;
2799 }
2800
2801 LOG(("ContinueProcessResponse4 got failure result [rv=%" PRIx32 "]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueProcessResponse4 got failure result [rv=%" "x" "]\n"
, static_cast<uint32_t>(rv)); } } while (0)
2802 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueProcessResponse4 got failure result [rv=%" "x" "]\n"
, static_cast<uint32_t>(rv)); } } while (0)
;
2803 if (mTransaction && mTransaction->ProxyConnectFailed()) {
2804 return ProcessFailedProxyConnect(mRedirectType);
2805 }
2806 return ProcessNormal();
2807}
2808
2809nsresult nsHttpChannel::ProcessNormal() {
2810 LOG(("nsHttpChannel::ProcessNormal [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessNormal [this=%p]\n", this); } } while
(0)
;
2811
2812 return ContinueProcessNormal(NS_OK);
2813}
2814
2815nsresult nsHttpChannel::ContinueProcessNormal(nsresult rv) {
2816 LOG(("nsHttpChannel::ContinueProcessNormal [this=%p]", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueProcessNormal [this=%p]", this); } }
while (0)
;
2817
2818 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2819 // Fill the failure status here, we have failed to fall back, thus we
2820 // have to report our status as failed.
2821 mStatus = rv;
2822 DoNotifyListener();
2823 return rv;
2824 }
2825
2826 rv = ProcessCrossOriginSecurityHeaders();
2827 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2828 mStatus = rv;
2829 HandleAsyncAbort();
2830 return rv;
2831 }
2832
2833 // if we're here, then any byte-range requests failed to result in a partial
2834 // response. we must clear this flag to prevent BufferPartialContent from
2835 // being called inside our OnDataAvailable (see bug 136678).
2836 StoreCachedContentIsPartial(false);
2837
2838 UpdateInhibitPersistentCachingFlag();
2839
2840 MaybeCreateCacheEntryWhenRCWN();
2841
2842 // this must be called before firing OnStartRequest, since http clients,
2843 // such as imagelib, expect our cache entry to already have the correct
2844 // expiration time (bug 87710).
2845 if (mCacheEntry) {
2846 rv = InitCacheEntry();
2847 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) CloseCacheEntry(true);
2848 }
2849
2850 // Check that the server sent us what we were asking for
2851 if (LoadResuming()) {
2852 // Create an entity id from the response
2853 nsAutoCString id;
2854 rv = GetEntityID(id);
2855 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2856 // If creating an entity id is not possible -> error
2857 Cancel(NS_ERROR_NOT_RESUMABLE);
2858 } else if (mResponseHead->Status() != 206 &&
2859 mResponseHead->Status() != 200) {
2860 // Probably 404 Not Found, 412 Precondition Failed or
2861 // 416 Invalid Range -> error
2862 LOG(("Unexpected response status while resuming, aborting [this=%p]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Unexpected response status while resuming, aborting [this=%p]\n"
, this); } } while (0)
2863 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Unexpected response status while resuming, aborting [this=%p]\n"
, this); } } while (0)
;
2864 Cancel(NS_ERROR_ENTITY_CHANGED);
2865 }
2866 // If we were passed an entity id, verify it's equal to the server's
2867 else if (!mEntityID.IsEmpty()) {
2868 if (!mEntityID.Equals(id)) {
2869 LOG(("Entity mismatch, expected '%s', got '%s', aborting [this=%p]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Entity mismatch, expected '%s', got '%s', aborting [this=%p]"
, mEntityID.get(), id.get(), this); } } while (0)
2870 mEntityID.get(), id.get(), this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Entity mismatch, expected '%s', got '%s', aborting [this=%p]"
, mEntityID.get(), id.get(), this); } } while (0)
;
2871 Cancel(NS_ERROR_ENTITY_CHANGED);
2872 }
2873 }
2874 }
2875
2876 rv = CallOnStartRequest();
2877 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
2878
2879 // install cache listener if we still have a cache entry open
2880 if (mCacheEntry && !LoadCacheEntryIsReadOnly()) {
2881 rv = InstallCacheListener();
2882 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
2883 }
2884
2885 return NS_OK;
2886}
2887
2888nsresult nsHttpChannel::PromptTempRedirect() {
2889 if (!gHttpHandler->PromptTempRedirect()) {
2890 return NS_OK;
2891 }
2892 nsresult rv;
2893 nsCOMPtr<nsIStringBundleService> bundleService =
2894 do_GetService(NS_STRINGBUNDLE_CONTRACTID"@mozilla.org/intl/stringbundle;1", &rv);
2895 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
2896
2897 nsCOMPtr<nsIStringBundle> stringBundle;
2898 rv =
2899 bundleService->CreateBundle(NECKO_MSGS_URL"chrome://necko/locale/necko.properties", getter_AddRefs(stringBundle));
2900 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
2901
2902 nsAutoString messageString;
2903 rv = stringBundle->GetStringFromName("RepostFormData", messageString);
2904 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2905 bool repost = false;
2906
2907 nsCOMPtr<nsIPrompt> prompt;
2908 GetCallback(prompt);
2909 if (!prompt) return NS_ERROR_NO_INTERFACE;
2910
2911 prompt->Confirm(nullptr, messageString.get(), &repost);
2912 if (!repost) return NS_ERROR_FAILURE;
2913 }
2914
2915 return rv;
2916}
2917
2918nsresult nsHttpChannel::ProxyFailover() {
2919 LOG(("nsHttpChannel::ProxyFailover [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProxyFailover [this=%p]\n", this); } } while
(0)
;
2920
2921 nsresult rv;
2922
2923 nsCOMPtr<nsIProtocolProxyService> pps =
2924 do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID"@mozilla.org/network/protocol-proxy-service;1", &rv);
2925 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
2926
2927 nsCOMPtr<nsIProxyInfo> pi;
2928 rv = pps->GetFailoverForProxy(mConnectionInfo->ProxyInfo(), mURI, mStatus,
2929 getter_AddRefs(pi));
2930#ifdef MOZ_PROXY_DIRECT_FAILOVER1
2931 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2932 if (!StaticPrefs::network_proxy_failover_direct()) {
2933 return rv;
2934 }
2935 // If this request used a failed proxy and there is no failover available,
2936 // fallback to DIRECT connections for conservative requests.
2937 if (LoadBeConservative()) {
2938 rv = pps->NewProxyInfo("direct"_ns, ""_ns, 0, ""_ns, ""_ns, 0, UINT32_MAX(4294967295U),
2939 nullptr, getter_AddRefs(pi));
2940 }
2941#endif
2942 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2943 return rv;
2944 }
2945#ifdef MOZ_PROXY_DIRECT_FAILOVER1
2946 }
2947#endif
2948
2949 // XXXbz so where does this codepath remove us from the loadgroup,
2950 // exactly?
2951 return AsyncDoReplaceWithProxy(pi);
2952}
2953
2954void nsHttpChannel::SetHTTPSSVCRecord(
2955 already_AddRefed<nsIDNSHTTPSSVCRecord>&& aRecord) {
2956 LOG(("nsHttpChannel::SetHTTPSSVCRecord [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::SetHTTPSSVCRecord [this=%p]\n", this); } } while
(0)
;
2957 nsCOMPtr<nsIDNSHTTPSSVCRecord> record = aRecord;
2958 MOZ_ASSERT(!mHTTPSSVCRecord)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mHTTPSSVCRecord)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mHTTPSSVCRecord))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mHTTPSSVCRecord"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2958); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mHTTPSSVCRecord"
")"); do { *((volatile int*)__null) = 2958; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2959 mHTTPSSVCRecord.emplace(std::move(record));
2960}
2961
2962void nsHttpChannel::HandleAsyncRedirectChannelToHttps() {
2963 MOZ_ASSERT(!mCallOnResume, "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCallOnResume)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCallOnResume))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mCallOnResume"
" (" "How did that happen?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2963); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCallOnResume"
") (" "How did that happen?" ")"); do { *((volatile int*)__null
) = 2963; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
2964
2965 if (mSuspendCount) {
2966 LOG(("Waiting until resume to do async redirect to https [this=%p]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume to do async redirect to https [this=%p]\n"
, this); } } while (0)
2967 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume to do async redirect to https [this=%p]\n"
, this); } } while (0)
;
2968 mCallOnResume = [](nsHttpChannel* self) {
2969 self->HandleAsyncRedirectChannelToHttps();
2970 return NS_OK;
2971 };
2972 return;
2973 }
2974
2975 nsresult rv = StartRedirectChannelToHttps();
2976 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2977 rv = ContinueAsyncRedirectChannelToURI(rv);
2978 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2979 LOG(("ContinueAsyncRedirectChannelToURI failed (%08x) [this=%p]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueAsyncRedirectChannelToURI failed (%08x) [this=%p]\n"
, static_cast<uint32_t>(rv), this); } } while (0)
2980 static_cast<uint32_t>(rv), this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueAsyncRedirectChannelToURI failed (%08x) [this=%p]\n"
, static_cast<uint32_t>(rv), this); } } while (0)
;
2981 }
2982 }
2983}
2984
2985nsresult nsHttpChannel::StartRedirectChannelToHttps() {
2986 LOG(("nsHttpChannel::HandleAsyncRedirectChannelToHttps() [STS]\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::HandleAsyncRedirectChannelToHttps() [STS]\n"
); } } while (0)
;
2987
2988 nsCOMPtr<nsIURI> upgradedURI;
2989 nsresult rv = NS_GetSecureUpgradedURI(mURI, getter_AddRefs(upgradedURI));
2990 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2990); return rv; } } while (false)
;
2991
2992 return StartRedirectChannelToURI(
2993 upgradedURI, nsIChannelEventSink::REDIRECT_PERMANENT |
2994 nsIChannelEventSink::REDIRECT_STS_UPGRADE);
2995}
2996
2997void nsHttpChannel::HandleAsyncAPIRedirect() {
2998 MOZ_ASSERT(!mCallOnResume, "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCallOnResume)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCallOnResume))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mCallOnResume"
" (" "How did that happen?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2998); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCallOnResume"
") (" "How did that happen?" ")"); do { *((volatile int*)__null
) = 2998; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
2999 MOZ_ASSERT(mAPIRedirectToURI, "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mAPIRedirectToURI)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mAPIRedirectToURI))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mAPIRedirectToURI"
" (" "How did that happen?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 2999); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAPIRedirectToURI"
") (" "How did that happen?" ")"); do { *((volatile int*)__null
) = 2999; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
3000
3001 if (mSuspendCount) {
3002 LOG(("Waiting until resume to do async API redirect [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume to do async API redirect [this=%p]\n"
, this); } } while (0)
;
3003 mCallOnResume = [](nsHttpChannel* self) {
3004 self->HandleAsyncAPIRedirect();
3005 return NS_OK;
3006 };
3007 return;
3008 }
3009
3010 nsresult rv = StartRedirectChannelToURI(
3011 mAPIRedirectToURI, nsIChannelEventSink::REDIRECT_PERMANENT);
3012 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3013 rv = ContinueAsyncRedirectChannelToURI(rv);
3014 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3015 LOG(("ContinueAsyncRedirectChannelToURI failed (%08x) [this=%p]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueAsyncRedirectChannelToURI failed (%08x) [this=%p]\n"
, static_cast<uint32_t>(rv), this); } } while (0)
3016 static_cast<uint32_t>(rv), this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueAsyncRedirectChannelToURI failed (%08x) [this=%p]\n"
, static_cast<uint32_t>(rv), this); } } while (0)
;
3017 }
3018 }
3019}
3020
3021void nsHttpChannel::HandleAsyncRedirectToUnstrippedURI() {
3022 MOZ_ASSERT(!mCallOnResume, "How did that happen?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCallOnResume)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCallOnResume))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mCallOnResume"
" (" "How did that happen?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3022); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCallOnResume"
") (" "How did that happen?" ")"); do { *((volatile int*)__null
) = 3022; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
3023
3024 if (mSuspendCount) {
3025 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume to do async redirect to unstripped URI "
"[this=%p]\n", this); } } while (0)
3026 ("Waiting until resume to do async redirect to unstripped URI "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume to do async redirect to unstripped URI "
"[this=%p]\n", this); } } while (0)
3027 "[this=%p]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume to do async redirect to unstripped URI "
"[this=%p]\n", this); } } while (0)
3028 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Waiting until resume to do async redirect to unstripped URI "
"[this=%p]\n", this); } } while (0)
;
3029 mCallOnResume = [](nsHttpChannel* self) {
3030 self->HandleAsyncRedirectToUnstrippedURI();
3031 return NS_OK;
3032 };
3033 return;
3034 }
3035
3036 nsCOMPtr<nsIURI> unstrippedURI;
3037 mLoadInfo->GetUnstrippedURI(getter_AddRefs(unstrippedURI));
3038
3039 // Clear the unstripped URI from the loadInfo before starting redirect in case
3040 // endless redirect.
3041 mLoadInfo->SetUnstrippedURI(nullptr);
3042
3043 nsresult rv = StartRedirectChannelToURI(
3044 unstrippedURI, nsIChannelEventSink::REDIRECT_PERMANENT);
3045
3046 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3047 rv = ContinueAsyncRedirectChannelToURI(rv);
3048 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3049 LOG(("ContinueAsyncRedirectChannelToURI failed (%08x) [this=%p]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueAsyncRedirectChannelToURI failed (%08x) [this=%p]\n"
, static_cast<uint32_t>(rv), this); } } while (0)
3050 static_cast<uint32_t>(rv), this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "ContinueAsyncRedirectChannelToURI failed (%08x) [this=%p]\n"
, static_cast<uint32_t>(rv), this); } } while (0)
;
3051 }
3052 }
3053}
3054nsresult nsHttpChannel::RedirectToNewChannelForAuthRetry() {
3055 LOG(("nsHttpChannel::RedirectToNewChannelForAuthRetry %p", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::RedirectToNewChannelForAuthRetry %p", this)
; } } while (0)
;
3056 nsresult rv = NS_OK;
3057
3058 nsCOMPtr<nsILoadInfo> redirectLoadInfo = CloneLoadInfoForRedirect(
3059 mURI, nsIChannelEventSink::REDIRECT_INTERNAL |
3060 nsIChannelEventSink::REDIRECT_AUTH_RETRY);
3061
3062 nsCOMPtr<nsIIOService> ioService;
3063
3064 rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
3065 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3065); return rv; } } while (false)
;
3066
3067 nsCOMPtr<nsIChannel> newChannel;
3068 rv = gHttpHandler->NewProxiedChannel(mURI, mProxyInfo, mProxyResolveFlags,
3069 mProxyURI, mLoadInfo,
3070 getter_AddRefs(newChannel));
3071
3072 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3072); return rv; } } while (false)
;
3073
3074 rv = SetupReplacementChannel(mURI, newChannel, true,
3075 nsIChannelEventSink::REDIRECT_INTERNAL |
3076 nsIChannelEventSink::REDIRECT_AUTH_RETRY);
3077 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3077); return rv; } } while (false)
;
3078
3079 // rewind the upload stream
3080 if (mUploadStream) {
3081 nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
3082 nsresult rv = NS_ERROR_NO_INTERFACE;
3083 if (seekable) {
3084 rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
3085 }
3086
3087 // This should not normally happen, but it's possible that big memory
3088 // blobs originating in the other process can't be rewinded.
3089 // In that case we just fail the request, otherwise the content length
3090 // will not match and this load will never complete.
3091 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3091); return rv; } } while (false)
;
3092 }
3093
3094 RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(newChannel);
3095
3096 MOZ_ASSERT(mAuthProvider)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mAuthProvider)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mAuthProvider))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mAuthProvider",
"/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3096); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAuthProvider"
")"); do { *((volatile int*)__null) = 3096; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3097 httpChannelImpl->mAuthProvider = std::move(mAuthProvider);
3098
3099 httpChannelImpl->mProxyInfo = mProxyInfo;
3100
3101 if ((mCaps & NS_HTTP_STICKY_CONNECTION(1 << 2)) ||
3102 mTransaction->HasStickyConnection()) {
3103 mConnectionInfo = mTransaction->GetConnInfo();
3104
3105 httpChannelImpl->mTransactionSticky = mTransaction;
3106
3107 if (mTransaction->Http2Disabled()) {
3108 httpChannelImpl->mCaps |= NS_HTTP_DISALLOW_SPDY(1 << 7);
3109 }
3110 if (mTransaction->Http3Disabled()) {
3111 httpChannelImpl->mCaps |= NS_HTTP_DISALLOW_HTTP3(1 << 21);
3112 }
3113 }
3114 httpChannelImpl->mCaps |= NS_HTTP_STICKY_CONNECTION(1 << 2);
3115 if (LoadAuthConnectionRestartable()) {
3116 httpChannelImpl->mCaps |= NS_HTTP_CONNECTION_RESTARTABLE(1 << 13);
3117 } else {
3118 httpChannelImpl->mCaps &= ~NS_HTTP_CONNECTION_RESTARTABLE(1 << 13);
3119 }
3120
3121 MOZ_ASSERT(mConnectionInfo)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mConnectionInfo)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mConnectionInfo))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mConnectionInfo"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3121); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mConnectionInfo"
")"); do { *((volatile int*)__null) = 3121; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3122 httpChannelImpl->mConnectionInfo = mConnectionInfo->Clone();
3123
3124 // we need to store the state to skip unnecessary checks in the new channel
3125 httpChannelImpl->StoreAuthRedirectedChannel(true);
3126
3127 // We must copy proxy and auth header to the new channel.
3128 // Although the new channel can populate auth headers from auth cache, we
3129 // would still like to use the auth headers generated in this channel. The
3130 // main reason for doing this is that certain connection-based/stateful auth
3131 // schemes like NTLM will fail when we try generate the credentials more than
3132 // the number of times the server has presented us the challenge due to the
3133 // usage of nonce in generating the credentials Copying the auth header will
3134 // bypass generation of the credentials
3135 nsAutoCString authVal;
3136 if (NS_SUCCEEDED(GetRequestHeader("Proxy-Authorization"_ns, authVal))((bool)(__builtin_expect(!!(!NS_FAILED_impl(GetRequestHeader(
"Proxy-Authorization"_ns, authVal))), 1)))
) {
3137 httpChannelImpl->SetRequestHeader("Proxy-Authorization"_ns, authVal, false);
3138 }
3139 if (NS_SUCCEEDED(GetRequestHeader("Authorization"_ns, authVal))((bool)(__builtin_expect(!!(!NS_FAILED_impl(GetRequestHeader(
"Authorization"_ns, authVal))), 1)))
) {
3140 httpChannelImpl->SetRequestHeader("Authorization"_ns, authVal, false);
3141 }
3142
3143 httpChannelImpl->SetBlockAuthPrompt(LoadBlockAuthPrompt());
3144 mRedirectChannel = newChannel;
3145
3146 rv = gHttpHandler->AsyncOnChannelRedirect(
3147 this, newChannel,
3148 nsIChannelEventSink::REDIRECT_INTERNAL |
3149 nsIChannelEventSink::REDIRECT_AUTH_RETRY);
3150
3151 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) rv = WaitForRedirectCallback();
3152
3153 // redirected channel will be opened after we receive the OnStopRequest
3154
3155 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3156 AutoRedirectVetoNotifier notifier(this, rv);
3157 mRedirectChannel = nullptr;
3158 }
3159
3160 return rv;
3161}
3162nsresult nsHttpChannel::StartRedirectChannelToURI(nsIURI* upgradedURI,
3163 uint32_t flags) {
3164 nsresult rv = NS_OK;
3165 LOG(("nsHttpChannel::StartRedirectChannelToURI()\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::StartRedirectChannelToURI()\n"); } } while (
0)
;
3166
3167 nsCOMPtr<nsIChannel> newChannel;
3168 nsCOMPtr<nsILoadInfo> redirectLoadInfo =
3169 CloneLoadInfoForRedirect(upgradedURI, flags);
3170
3171 nsCOMPtr<nsIIOService> ioService;
3172 rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
3173 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3173); return rv; } } while (false)
;
3174
3175 rv = NS_NewChannelInternal(getter_AddRefs(newChannel), upgradedURI,
3176 redirectLoadInfo,
3177 nullptr, // PerformanceStorage
3178 nullptr, // aLoadGroup
3179 nullptr, // aCallbacks
3180 nsIRequest::LOAD_NORMAL, ioService);
3181 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3181); return rv; } } while (false)
;
3182
3183 rv = SetupReplacementChannel(upgradedURI, newChannel, true, flags);
3184 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3184); return rv; } } while (false)
;
3185
3186 if (mHTTPSSVCRecord) {
3187 RefPtr<nsHttpChannel> httpChan = do_QueryObject(newChannel);
3188 nsCOMPtr<nsIDNSHTTPSSVCRecord> rec = mHTTPSSVCRecord.ref();
3189 if (httpChan && rec) {
3190 httpChan->SetHTTPSSVCRecord(rec.forget());
3191 }
3192 }
3193
3194 // Inform consumers about this fake redirect
3195 mRedirectChannel = newChannel;
3196
3197 PushRedirectAsyncFunc(&nsHttpChannel::ContinueAsyncRedirectChannelToURI);
3198 rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, flags);
3199
3200 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) rv = WaitForRedirectCallback();
3201
3202 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3203 AutoRedirectVetoNotifier notifier(this, rv);
3204
3205 /* Remove the async call to ContinueAsyncRedirectChannelToURI().
3206 * It is called directly by our callers upon return (to clean up
3207 * the failed redirect). */
3208 PopRedirectAsyncFunc(&nsHttpChannel::ContinueAsyncRedirectChannelToURI);
3209 }
3210
3211 return rv;
3212}
3213
3214nsresult nsHttpChannel::ContinueAsyncRedirectChannelToURI(nsresult rv) {
3215 LOG(("nsHttpChannel::ContinueAsyncRedirectChannelToURI [this=%p]", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ContinueAsyncRedirectChannelToURI [this=%p]"
, this); } } while (0)
;
3216
3217 // Since we handle mAPIRedirectToURI also after on-examine-response handler
3218 // rather drop it here to avoid any redirect loops, even just hypothetical.
3219 mAPIRedirectToURI = nullptr;
3220
3221 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3222 rv = OpenRedirectChannel(rv);
3223 }
3224
3225 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3226 // Cancel the channel here, the update to https had been vetoed
3227 // but from the security reasons we have to discard the whole channel
3228 // load.
3229 Cancel(rv);
3230 }
3231
3232 if (mLoadGroup) {
3233 mLoadGroup->RemoveRequest(this, nullptr, mStatus);
3234 }
3235
3236 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && !mCachePump && !mTransactionPump) {
3237 // We have to manually notify the listener because there is not any pump
3238 // that would call our OnStart/StopRequest after resume from waiting for
3239 // the redirect callback.
3240 DoNotifyListener();
3241 }
3242
3243 return rv;
3244}
3245
3246nsresult nsHttpChannel::OpenRedirectChannel(nsresult rv) {
3247 AutoRedirectVetoNotifier notifier(this, rv);
3248
3249 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3250
3251 if (!mRedirectChannel) {
3252 LOG((do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OpenRedirectChannel unexpected null redirect channel"
); } } while (0)
3253 "nsHttpChannel::OpenRedirectChannel unexpected null redirect channel"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OpenRedirectChannel unexpected null redirect channel"
); } } while (0)
;
3254 return NS_ERROR_FAILURE;
3255 }
3256
3257 // Make sure to do this after we received redirect veto answer,
3258 // i.e. after all sinks had been notified
3259 mRedirectChannel->SetOriginalURI(mOriginalURI);
3260
3261 // open new channel
3262 rv = mRedirectChannel->AsyncOpen(mListener);
3263
3264 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3264); return rv; } } while (false)
;
3265
3266 mStatus = NS_BINDING_REDIRECTED;
3267
3268 notifier.RedirectSucceeded();
3269
3270 ReleaseListeners();
3271
3272 return NS_OK;
3273}
3274
3275nsresult nsHttpChannel::AsyncDoReplaceWithProxy(nsIProxyInfo* pi) {
3276 LOG(("nsHttpChannel::AsyncDoReplaceWithProxy [this=%p pi=%p]", this, pi))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::AsyncDoReplaceWithProxy [this=%p pi=%p]", this
, pi); } } while (0)
;
3277 nsresult rv;
3278
3279 nsCOMPtr<nsIChannel> newChannel;
3280 rv = gHttpHandler->NewProxiedChannel(mURI, pi, mProxyResolveFlags, mProxyURI,
3281 mLoadInfo, getter_AddRefs(newChannel));
3282 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3283
3284 uint32_t flags = nsIChannelEventSink::REDIRECT_INTERNAL;
3285
3286 rv = SetupReplacementChannel(mURI, newChannel, true, flags);
3287 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3288
3289 // Inform consumers about this fake redirect
3290 mRedirectChannel = newChannel;
3291
3292 PushRedirectAsyncFunc(&nsHttpChannel::OpenRedirectChannel);
3293 rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, flags);
3294
3295 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) rv = WaitForRedirectCallback();
3296
3297 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3298 AutoRedirectVetoNotifier notifier(this, rv);
3299 PopRedirectAsyncFunc(&nsHttpChannel::OpenRedirectChannel);
3300 }
3301
3302 return rv;
3303}
3304
3305nsresult nsHttpChannel::ResolveProxy() {
3306 LOG(("nsHttpChannel::ResolveProxy [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResolveProxy [this=%p]\n", this); } } while
(0)
;
3307
3308 nsresult rv;
3309
3310 nsCOMPtr<nsIProtocolProxyService> pps =
3311 do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID"@mozilla.org/network/protocol-proxy-service;1", &rv);
3312 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3313
3314 // using the nsIProtocolProxyService2 allows a minor performance
3315 // optimization, but if an add-on has only provided the original interface
3316 // then it is ok to use that version.
3317 nsCOMPtr<nsIProtocolProxyService2> pps2 = do_QueryInterface(pps);
3318 if (pps2) {
3319 rv = pps2->AsyncResolve2(this, mProxyResolveFlags, this, nullptr,
3320 getter_AddRefs(mProxyRequest));
3321 } else {
3322 rv = pps->AsyncResolve(static_cast<nsIChannel*>(this), mProxyResolveFlags,
3323 this, nullptr, getter_AddRefs(mProxyRequest));
3324 }
3325
3326 return rv;
3327}
3328
3329bool nsHttpChannel::ResponseWouldVary(nsICacheEntry* entry) {
3330 nsresult rv;
3331 nsAutoCString buf, metaKey;
3332 Unused << mCachedResponseHead->GetHeader(nsHttp::Vary, buf);
3333
3334 constexpr auto prefix = "request-"_ns;
3335
3336 // enumerate the elements of the Vary header...
3337 for (const nsACString& token :
3338 nsCCharSeparatedTokenizer(buf, NS_HTTP_HEADER_SEP',').ToRange()) {
3339 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [channel=%p] " "processing %s\n"
, this, nsPromiseFlatCString(token).get()); } } while (0)
3340 ("nsHttpChannel::ResponseWouldVary [channel=%p] "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [channel=%p] " "processing %s\n"
, this, nsPromiseFlatCString(token).get()); } } while (0)
3341 "processing %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [channel=%p] " "processing %s\n"
, this, nsPromiseFlatCString(token).get()); } } while (0)
3342 this, nsPromiseFlatCString(token).get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [channel=%p] " "processing %s\n"
, this, nsPromiseFlatCString(token).get()); } } while (0)
;
3343 //
3344 // if "*", then assume response would vary. technically speaking,
3345 // "Vary: header, *" is not permitted, but we allow it anyways.
3346 //
3347 // We hash values of cookie-headers for the following reasons:
3348 //
3349 // 1- cookies can be very large in size
3350 //
3351 // 2- cookies may contain sensitive information. (for parity with
3352 // out policy of not storing Set-cookie headers in the cache
3353 // meta data, we likewise do not want to store cookie headers
3354 // here.)
3355 //
3356 if (token.EqualsLiteral("*")) {
3357 return true; // if we encounter this, just get out of here
3358 }
3359
3360 // build cache meta data key...
3361 metaKey = prefix + token;
3362
3363 // check the last value of the given request header to see if it has
3364 // since changed. if so, then indeed the cached response is invalid.
3365 nsCString lastVal;
3366 entry->GetMetaDataElement(metaKey.get(), getter_Copies(lastVal));
3367 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [channel=%p] " "stored value = \"%s\"\n"
, this, lastVal.get()); } } while (0)
3368 ("nsHttpChannel::ResponseWouldVary [channel=%p] "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [channel=%p] " "stored value = \"%s\"\n"
, this, lastVal.get()); } } while (0)
3369 "stored value = \"%s\"\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [channel=%p] " "stored value = \"%s\"\n"
, this, lastVal.get()); } } while (0)
3370 this, lastVal.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [channel=%p] " "stored value = \"%s\"\n"
, this, lastVal.get()); } } while (0)
;
3371
3372 // Look for value of "Cookie" in the request headers
3373 nsHttpAtom atom = nsHttp::ResolveAtom(token);
3374 nsAutoCString newVal;
3375 bool hasHeader = NS_SUCCEEDED(mRequestHead.GetHeader(atom, newVal))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mRequestHead.GetHeader
(atom, newVal))), 1)))
;
3376 if (!lastVal.IsEmpty()) {
3377 // value for this header in cache, but no value in request
3378 if (!hasHeader) {
3379 return true; // yes - response would vary
3380 }
3381
3382 // If this is a cookie-header, stored metadata is not
3383 // the value itself but the hash. So we also hash the
3384 // outgoing value here in order to compare the hashes
3385 nsAutoCString hash;
3386 if (atom == nsHttp::Cookie) {
3387 rv = Hash(newVal.get(), hash);
3388 // If hash failed, be conservative (the cached hash
3389 // exists at this point) and claim response would vary
3390 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return true;
3391 newVal = hash;
3392
3393 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [this=%p] " "set-cookie value hashed to %s\n"
, this, newVal.get()); } } while (0)
3394 ("nsHttpChannel::ResponseWouldVary [this=%p] "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [this=%p] " "set-cookie value hashed to %s\n"
, this, newVal.get()); } } while (0)
3395 "set-cookie value hashed to %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [this=%p] " "set-cookie value hashed to %s\n"
, this, newVal.get()); } } while (0)
3396 this, newVal.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ResponseWouldVary [this=%p] " "set-cookie value hashed to %s\n"
, this, newVal.get()); } } while (0)
;
3397 }
3398
3399 if (!newVal.Equals(lastVal)) {
3400 return true; // yes, response would vary
3401 }
3402
3403 } else if (hasHeader) { // old value is empty, but newVal is set
3404 return true;
3405 }
3406 }
3407
3408 return false;
3409}
3410
3411// We need to have an implementation of this function just so that we can keep
3412// all references to mCallOnResume of type nsHttpChannel: it's not OK in C++
3413// to set a member function ptr to a base class function.
3414void nsHttpChannel::HandleAsyncAbort() {
3415 HttpAsyncAborter<nsHttpChannel>::HandleAsyncAbort();
3416}
3417
3418//-----------------------------------------------------------------------------
3419// nsHttpChannel <byte-range>
3420//-----------------------------------------------------------------------------
3421
3422bool nsHttpChannel::IsResumable(int64_t partialLen, int64_t contentLength,
3423 bool ignoreMissingPartialLen) const {
3424 bool hasContentEncoding =
3425 mCachedResponseHead->HasHeader(nsHttp::Content_Encoding);
3426
3427 nsAutoCString etag;
3428 Unused << mCachedResponseHead->GetHeader(nsHttp::ETag, etag);
3429 bool hasWeakEtag = !etag.IsEmpty() && StringBeginsWith(etag, "W/"_ns);
3430
3431 return (partialLen < contentLength) &&
3432 (partialLen > 0 || ignoreMissingPartialLen) && !hasContentEncoding &&
3433 !hasWeakEtag && mCachedResponseHead->IsResumable() &&
3434 !LoadCustomConditionalRequest() && !mCachedResponseHead->NoStore();
3435}
3436
3437nsresult nsHttpChannel::MaybeSetupByteRangeRequest(
3438 int64_t partialLen, int64_t contentLength, bool ignoreMissingPartialLen) {
3439 // Be pesimistic
3440 StoreIsPartialRequest(false);
3441
3442 if (!IsResumable(partialLen, contentLength, ignoreMissingPartialLen)) {
3443 return NS_ERROR_NOT_RESUMABLE;
3444 }
3445
3446 // looks like a partial entry we can reuse; add If-Range
3447 // and Range headers.
3448 nsresult rv = SetupByteRangeRequest(partialLen);
3449 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3450 // Make the request unconditional again.
3451 UntieByteRangeRequest();
3452 }
3453
3454 return rv;
3455}
3456
3457nsresult nsHttpChannel::SetupByteRangeRequest(int64_t partialLen) {
3458 // cached content has been found to be partial, add necessary request
3459 // headers to complete cache entry.
3460
3461 // use strongest validator available...
3462 nsAutoCString val;
3463 Unused << mCachedResponseHead->GetHeader(nsHttp::ETag, val);
3464 if (val.IsEmpty()) {
3465 Unused << mCachedResponseHead->GetHeader(nsHttp::Last_Modified, val);
3466 }
3467 if (val.IsEmpty()) {
3468 // if we hit this code it means mCachedResponseHead->IsResumable() is
3469 // either broken or not being called.
3470 MOZ_ASSERT_UNREACHABLE("no cache validator")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"no cache validator" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3470); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "no cache validator" ")"); do { *
((volatile int*)__null) = 3470; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
3471 StoreIsPartialRequest(false);
3472 return NS_ERROR_FAILURE;
3473 }
3474
3475 char buf[64];
3476 SprintfLiteral(buf, "bytes=%" PRId64"l" "d" "-", partialLen);
3477
3478 DebugOnly<nsresult> rv{};
3479 rv = mRequestHead.SetHeader(nsHttp::Range, nsDependentCString(buf));
3480 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3480); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 3480; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3481 rv = mRequestHead.SetHeader(nsHttp::If_Range, val);
3482 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3482); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 3482; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3483 StoreIsPartialRequest(true);
3484
3485 return NS_OK;
3486}
3487
3488void nsHttpChannel::UntieByteRangeRequest() {
3489 DebugOnly<nsresult> rv{};
3490 rv = mRequestHead.ClearHeader(nsHttp::Range);
3491 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3491); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 3491; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3492 rv = mRequestHead.ClearHeader(nsHttp::If_Range);
3493 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3493); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 3493; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3494}
3495
3496nsresult nsHttpChannel::ProcessPartialContent(
3497 const std::function<nsresult(nsHttpChannel*, nsresult)>&
3498 aContinueProcessResponseFunc) {
3499 // ok, we've just received a 206
3500 //
3501 // we need to stream whatever data is in the cache out first, and then
3502 // pick up whatever data is on the wire, writing it into the cache.
3503
3504 LOG(("nsHttpChannel::ProcessPartialContent [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p]\n", this); }
} while (0)
;
3505
3506 NS_ENSURE_TRUE(mCachedResponseHead, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(mCachedResponseHead)), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mCachedResponseHead"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3506); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
3507 NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_INITIALIZED)do { if ((__builtin_expect(!!(!(mCacheEntry)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mCacheEntry" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3507); return NS_ERROR_NOT_INITIALIZED; } } while (false)
;
3508
3509 // Check if the content-encoding we now got is different from the one we
3510 // got before
3511 nsAutoCString contentEncoding, cachedContentEncoding;
3512 // It is possible that there is not such headers
3513 Unused << mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding);
3514 Unused << mCachedResponseHead->GetHeader(nsHttp::Content_Encoding,
3515 cachedContentEncoding);
3516 if (nsCRT::strcasecmp(contentEncoding.get(), cachedContentEncoding.get()) !=
3517 0) {
3518 Cancel(NS_ERROR_INVALID_CONTENT_ENCODING);
3519 return CallOnStartRequest();
3520 }
3521
3522 nsresult rv;
3523
3524 int64_t cachedContentLength = mCachedResponseHead->ContentLength();
3525 int64_t entitySize = mResponseHead->TotalEntitySize();
3526
3527 nsAutoCString contentRange;
3528 Unused << mResponseHead->GetHeader(nsHttp::Content_Range, contentRange);
3529 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p trans=%p] " "original content-length %"
"l" "d" ", entity-size %" "l" "d" ", content-range %s\n", this
, mTransaction.get(), cachedContentLength, entitySize, contentRange
.get()); } } while (0)
3530 ("nsHttpChannel::ProcessPartialContent [this=%p trans=%p] "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p trans=%p] " "original content-length %"
"l" "d" ", entity-size %" "l" "d" ", content-range %s\n", this
, mTransaction.get(), cachedContentLength, entitySize, contentRange
.get()); } } while (0)
3531 "original content-length %" PRId64 ", entity-size %" PRId64do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p trans=%p] " "original content-length %"
"l" "d" ", entity-size %" "l" "d" ", content-range %s\n", this
, mTransaction.get(), cachedContentLength, entitySize, contentRange
.get()); } } while (0)
3532 ", content-range %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p trans=%p] " "original content-length %"
"l" "d" ", entity-size %" "l" "d" ", content-range %s\n", this
, mTransaction.get(), cachedContentLength, entitySize, contentRange
.get()); } } while (0)
3533 this, mTransaction.get(), cachedContentLength, entitySize,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p trans=%p] " "original content-length %"
"l" "d" ", entity-size %" "l" "d" ", content-range %s\n", this
, mTransaction.get(), cachedContentLength, entitySize, contentRange
.get()); } } while (0)
3534 contentRange.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p trans=%p] " "original content-length %"
"l" "d" ", entity-size %" "l" "d" ", content-range %s\n", this
, mTransaction.get(), cachedContentLength, entitySize, contentRange
.get()); } } while (0)
;
3535
3536 if ((entitySize >= 0) && (cachedContentLength >= 0) &&
3537 (entitySize != cachedContentLength)) {
3538 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p] " "206 has different total entity size than the content length "
"of the original partially cached entity.\n", this); } } while
(0)
3539 ("nsHttpChannel::ProcessPartialContent [this=%p] "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p] " "206 has different total entity size than the content length "
"of the original partially cached entity.\n", this); } } while
(0)
3540 "206 has different total entity size than the content length "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p] " "206 has different total entity size than the content length "
"of the original partially cached entity.\n", this); } } while
(0)
3541 "of the original partially cached entity.\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p] " "206 has different total entity size than the content length "
"of the original partially cached entity.\n", this); } } while
(0)
3542 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessPartialContent [this=%p] " "206 has different total entity size than the content length "
"of the original partially cached entity.\n", this); } } while
(0)
;
3543
3544 mCacheEntry->AsyncDoom(nullptr);
3545 Cancel(NS_ERROR_CORRUPTED_CONTENT);
3546 return CallOnStartRequest();
3547 }
3548
3549 if (LoadConcurrentCacheAccess()) {
3550 // We started to read cached data sooner than its write has been done.
3551 // But the concurrent write has not finished completely, so we had to
3552 // do a range request. Now let the content coming from the network
3553 // be presented to consumers and also stored to the cache entry.
3554
3555 rv = InstallCacheListener(mLogicalOffset);
3556 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3557 } else {
3558 // suspend the current transaction
3559 rv = mTransactionPump->Suspend();
3560 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3561 }
3562
3563 // merge any new headers with the cached response headers
3564 mCachedResponseHead->UpdateHeaders(mResponseHead.get());
3565
3566 // update the cached response head
3567 nsAutoCString head;
3568 mCachedResponseHead->Flatten(head, true);
3569 rv = mCacheEntry->SetMetaDataElement("response-head", head.get());
3570 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3571
3572 // make the cached response be the current response
3573 mResponseHead = std::move(mCachedResponseHead);
3574
3575 UpdateInhibitPersistentCachingFlag();
3576
3577 rv = UpdateExpirationTime();
3578 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3579
3580 // notify observers interested in looking at a response that has been
3581 // merged with any cached headers (http-on-examine-merged-response).
3582 gHttpHandler->OnExamineMergedResponse(this);
3583
3584 if (LoadConcurrentCacheAccess()) {
3585 StoreCachedContentIsPartial(false);
3586 // Leave the ConcurrentCacheAccess flag set, we want to use it
3587 // to prevent duplicate OnStartRequest call on the target listener
3588 // in case this channel is canceled before it gets its OnStartRequest
3589 // from the http transaction.
3590 return rv;
3591 }
3592
3593 // Now we continue reading the network response.
3594 // the cached content is valid, although incomplete.
3595 mCachedContentIsValid = true;
3596 return CallOrWaitForResume([aContinueProcessResponseFunc](auto* self) {
3597 nsresult rv = self->ReadFromCache(false);
3598 return aContinueProcessResponseFunc(self, rv);
3599 });
3600}
3601
3602nsresult nsHttpChannel::OnDoneReadingPartialCacheEntry(bool* streamDone) {
3603 nsresult rv;
3604
3605 LOG(("nsHttpChannel::OnDoneReadingPartialCacheEntry [this=%p]", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OnDoneReadingPartialCacheEntry [this=%p]", this
); } } while (0)
;
3606
3607 // by default, assume we would have streamed all data or failed...
3608 *streamDone = true;
3609
3610 // setup cache listener to append to cache entry
3611 int64_t size;
3612 rv = mCacheEntry->GetDataSize(&size);
3613 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3614
3615 rv = InstallCacheListener(size);
3616 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3617
3618 // Entry is valid, do it now, after the output stream has been opened,
3619 // otherwise when done earlier, pending readers would consider the cache
3620 // entry still as partial (CacheEntry::GetDataSize would return the partial
3621 // data size) and consumers would do the conditional request again.
3622 rv = mCacheEntry->SetValid();
3623 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3624
3625 // need to track the logical offset of the data being sent to our listener
3626 mLogicalOffset = size;
3627
3628 // we're now completing the cached content, so we can clear this flag.
3629 // this puts us in the state of a regular download.
3630 StoreCachedContentIsPartial(false);
3631 // The cache input stream pump is finished, we do not need it any more.
3632 // (see bug 1313923)
3633 mCachePump = nullptr;
3634
3635 // resume the transaction if it exists, otherwise the pipe contained the
3636 // remaining part of the document and we've now streamed all of the data.
3637 if (mTransactionPump) {
3638 rv = mTransactionPump->Resume();
3639 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) *streamDone = false;
3640 } else {
3641 MOZ_ASSERT_UNREACHABLE("no transaction")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"no transaction" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3641); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "no transaction" ")"); do { *((volatile
int*)__null) = 3641; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
3642 }
3643 return rv;
3644}
3645
3646//-----------------------------------------------------------------------------
3647// nsHttpChannel <cache>
3648//-----------------------------------------------------------------------------
3649
3650bool nsHttpChannel::ShouldBypassProcessNotModified() {
3651 if (LoadCustomConditionalRequest()) {
3652 LOG(("Bypassing ProcessNotModified due to custom conditional headers"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Bypassing ProcessNotModified due to custom conditional headers"
); } } while (0)
;
3653 return true;
3654 }
3655
3656 if (!mDidReval) {
3657 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Server returned a 304 response even though we did not send a "
"conditional request"); } } while (0)
3658 ("Server returned a 304 response even though we did not send a "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Server returned a 304 response even though we did not send a "
"conditional request"); } } while (0)
3659 "conditional request"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Server returned a 304 response even though we did not send a "
"conditional request"); } } while (0)
;
3660 return true;
3661 }
3662
3663 return false;
3664}
3665
3666nsresult nsHttpChannel::ProcessNotModified(
3667 const std::function<nsresult(nsHttpChannel*, nsresult)>&
3668 aContinueProcessResponseFunc) {
3669 nsresult rv;
3670
3671 LOG(("nsHttpChannel::ProcessNotModified [this=%p]\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ProcessNotModified [this=%p]\n", this); } }
while (0)
;
3672
3673 // Assert ShouldBypassProcessNotModified() has been checked before call to
3674 // ProcessNotModified().
3675 MOZ_ASSERT(!ShouldBypassProcessNotModified())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ShouldBypassProcessNotModified())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!ShouldBypassProcessNotModified
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ShouldBypassProcessNotModified()", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ShouldBypassProcessNotModified()"
")"); do { *((volatile int*)__null) = 3675; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3676
3677 MOZ_ASSERT(mCachedResponseHead)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCachedResponseHead)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCachedResponseHead))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("mCachedResponseHead"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3677); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCachedResponseHead"
")"); do { *((volatile int*)__null) = 3677; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3678 MOZ_ASSERT(mCacheEntry)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCacheEntry)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCacheEntry))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mCacheEntry", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3678); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCacheEntry"
")"); do { *((volatile int*)__null) = 3678; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3679 NS_ENSURE_TRUE(mCachedResponseHead && mCacheEntry, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(mCachedResponseHead &&
mCacheEntry)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"mCachedResponseHead && mCacheEntry" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3679); return NS_ERROR_UNEXPECTED; } } while (false)
;
3680
3681 // If the 304 response contains a Last-Modified different than the
3682 // one in our cache that is pretty suspicious and is, in at least the
3683 // case of bug 716840, a sign of the server having previously corrupted
3684 // our cache with a bad response. Take the minor step here of just dooming
3685 // that cache entry so there is a fighting chance of getting things on the
3686 // right track.
3687
3688 nsAutoCString lastModifiedCached;
3689 nsAutoCString lastModified304;
3690
3691 rv =
3692 mCachedResponseHead->GetHeader(nsHttp::Last_Modified, lastModifiedCached);
3693 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3694 rv = mResponseHead->GetHeader(nsHttp::Last_Modified, lastModified304);
3695 }
3696
3697 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !lastModified304.Equals(lastModifiedCached)) {
3698 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Cache Entry and 304 Last-Modified Headers Do Not Match " "[%s] and [%s]\n"
, lastModifiedCached.get(), lastModified304.get()); } } while
(0)
3699 ("Cache Entry and 304 Last-Modified Headers Do Not Match "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Cache Entry and 304 Last-Modified Headers Do Not Match " "[%s] and [%s]\n"
, lastModifiedCached.get(), lastModified304.get()); } } while
(0)
3700 "[%s] and [%s]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Cache Entry and 304 Last-Modified Headers Do Not Match " "[%s] and [%s]\n"
, lastModifiedCached.get(), lastModified304.get()); } } while
(0)
3701 lastModifiedCached.get(), lastModified304.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Cache Entry and 304 Last-Modified Headers Do Not Match " "[%s] and [%s]\n"
, lastModifiedCached.get(), lastModified304.get()); } } while
(0)
;
3702
3703 mCacheEntry->AsyncDoom(nullptr);
3704 Telemetry::Accumulate(Telemetry::CACHE_LM_INCONSISTENT, true);
3705 }
3706
3707 // merge any new headers with the cached response headers
3708 mCachedResponseHead->UpdateHeaders(mResponseHead.get());
3709
3710 // update the cached response head
3711 nsAutoCString head;
3712 mCachedResponseHead->Flatten(head, true);
3713 rv = mCacheEntry->SetMetaDataElement("response-head", head.get());
3714 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3715
3716 // make the cached response be the current response
3717 mResponseHead = std::move(mCachedResponseHead);
3718
3719 UpdateInhibitPersistentCachingFlag();
3720
3721 rv = UpdateExpirationTime();
3722 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3723
3724 rv = AddCacheEntryHeaders(mCacheEntry);
3725 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3726
3727 // notify observers interested in looking at a reponse that has been
3728 // merged with any cached headers
3729 gHttpHandler->OnExamineMergedResponse(this);
3730
3731 mCachedContentIsValid = true;
3732
3733 // Tell other consumers the entry is OK to use
3734 rv = mCacheEntry->SetValid();
3735 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3736
3737 return CallOrWaitForResume([aContinueProcessResponseFunc](auto* self) {
3738 nsresult rv = self->ReadFromCache(false);
3739 return aContinueProcessResponseFunc(self, rv);
3740 });
3741}
3742
3743// Determines if a request is a byte range request for a subrange,
3744// i.e. is a byte range request, but not a 0- byte range request.
3745static bool IsSubRangeRequest(nsHttpRequestHead& aRequestHead) {
3746 nsAutoCString byteRange;
3747 if (NS_FAILED(aRequestHead.GetHeader(nsHttp::Range, byteRange))((bool)(__builtin_expect(!!(NS_FAILED_impl(aRequestHead.GetHeader
(nsHttp::Range, byteRange))), 0)))
) {
3748 return false;
3749 }
3750 return !byteRange.EqualsLiteral("bytes=0-");
3751}
3752
3753nsresult nsHttpChannel::OpenCacheEntry(bool isHttps) {
3754 // Drop this flag here
3755 StoreConcurrentCacheAccess(0);
3756
3757 LOG(("nsHttpChannel::OpenCacheEntry [this=%p]", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OpenCacheEntry [this=%p]", this); } } while
(0)
;
3758
3759 // make sure we're not abusing this function
3760 MOZ_ASSERT(!mCacheEntry, "cache entry already open")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCacheEntry)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCacheEntry))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mCacheEntry" " ("
"cache entry already open" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3760); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCacheEntry"
") (" "cache entry already open" ")"); do { *((volatile int*
)__null) = 3760; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3761
3762 if (mRequestHead.IsPost()) {
3763 // If the post id is already set then this is an attempt to replay
3764 // a post transaction via the cache. Otherwise, we need a unique
3765 // post id for this transaction.
3766 if (mPostID == 0) mPostID = gHttpHandler->GenerateUniqueID();
3767 } else if (!mRequestHead.IsGet() && !mRequestHead.IsHead()) {
3768 // don't use the cache for other types of requests
3769 return NS_OK;
3770 }
3771
3772 return OpenCacheEntryInternal(isHttps);
3773}
3774
3775nsresult nsHttpChannel::OpenCacheEntryInternal(bool isHttps) {
3776 nsresult rv;
3777
3778 if (LoadResuming()) {
3779 // We don't support caching for requests initiated
3780 // via nsIResumableChannel.
3781 return NS_OK;
3782 }
3783
3784 // Don't cache byte range requests which are subranges, only cache 0-
3785 // byte range requests.
3786 if (IsSubRangeRequest(mRequestHead)) {
3787 return NS_OK;
3788 }
3789
3790 // Handle correctly WaitForCacheEntry
3791 AutoCacheWaitFlags waitFlags(this);
3792
3793 nsAutoCString cacheKey;
3794
3795 nsCOMPtr<nsICacheStorageService> cacheStorageService(
3796 components::CacheStorage::Service());
3797 if (!cacheStorageService) {
3798 return NS_ERROR_NOT_AVAILABLE;
3799 }
3800
3801 nsCOMPtr<nsICacheStorage> cacheStorage;
3802 mCacheEntryURI = mURI;
3803
3804 RefPtr<LoadContextInfo> info = GetLoadContextInfo(this);
3805 if (!info) {
3806 return NS_ERROR_FAILURE;
3807 }
3808
3809 uint32_t cacheEntryOpenFlags;
3810 bool offline = gIOService->IsOffline();
3811
3812 RefPtr<mozilla::dom::BrowsingContext> bc;
3813 mLoadInfo->GetBrowsingContext(getter_AddRefs(bc));
3814
3815 bool maybeRCWN = false;
3816
3817 nsAutoCString cacheControlRequestHeader;
3818 Unused << mRequestHead.GetHeader(nsHttp::Cache_Control,
3819 cacheControlRequestHeader);
3820 CacheControlParser cacheControlRequest(cacheControlRequestHeader);
3821 if (cacheControlRequest.NoStore()) {
3822 return NS_OK;
3823 }
3824
3825 if (offline || (mLoadFlags & INHIBIT_CACHING) ||
3826 (bc && bc->Top()->GetForceOffline())) {
3827 if (BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())((mLoadFlags) & (nsIRequest::LOAD_BYPASS_CACHE | nsICachingChannel
::LOAD_BYPASS_LOCAL_CACHE) && !(((mLoadFlags) & nsIRequest
::LOAD_FROM_CACHE) && (LoadPreferCacheLoadOverBypass(
))))
&&
3828 !offline) {
3829 return NS_OK;
3830 }
3831 cacheEntryOpenFlags = nsICacheStorage::OPEN_READONLY;
3832 StoreCacheEntryIsReadOnly(true);
3833 } else if (BYPASS_LOCAL_CACHE(mLoadFlags, LoadPreferCacheLoadOverBypass())((mLoadFlags) & (nsIRequest::LOAD_BYPASS_CACHE | nsICachingChannel
::LOAD_BYPASS_LOCAL_CACHE) && !(((mLoadFlags) & nsIRequest
::LOAD_FROM_CACHE) && (LoadPreferCacheLoadOverBypass(
))))
) {
3834 cacheEntryOpenFlags = nsICacheStorage::OPEN_TRUNCATE;
3835 } else {
3836 cacheEntryOpenFlags =
3837 nsICacheStorage::OPEN_NORMALLY | nsICacheStorage::CHECK_MULTITHREADED;
3838 }
3839
3840 // Remember the request is a custom conditional request so that we can
3841 // process any 304 response correctly.
3842 StoreCustomConditionalRequest(
3843 mRequestHead.HasHeader(nsHttp::If_Modified_Since) ||
3844 mRequestHead.HasHeader(nsHttp::If_None_Match) ||
3845 mRequestHead.HasHeader(nsHttp::If_Unmodified_Since) ||
3846 mRequestHead.HasHeader(nsHttp::If_Match) ||
3847 mRequestHead.HasHeader(nsHttp::If_Range));
3848
3849 if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
3850 rv = cacheStorageService->MemoryCacheStorage(
3851 info, // ? choose app cache as well...
3852 getter_AddRefs(cacheStorage));
3853 } else if (LoadPinCacheContent()) {
3854 rv = cacheStorageService->PinningCacheStorage(info,
3855 getter_AddRefs(cacheStorage));
3856 } else {
3857 // Try to race only if we use disk cache storage
3858 maybeRCWN = mRequestHead.IsSafeMethod();
3859 rv = cacheStorageService->DiskCacheStorage(info,
3860 getter_AddRefs(cacheStorage));
3861 }
3862 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3862); return rv; } } while (false)
;
3863
3864 if ((mClassOfService.Flags() & nsIClassOfService::Leader) ||
3865 (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI)) {
3866 cacheEntryOpenFlags |= nsICacheStorage::OPEN_PRIORITY;
3867 }
3868
3869 // Only for backward compatibility with the old cache back end.
3870 // When removed, remove the flags and related code snippets.
3871 if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY) {
3872 cacheEntryOpenFlags |= nsICacheStorage::OPEN_BYPASS_IF_BUSY;
3873 }
3874
3875 if (mPostID) {
3876 mCacheIdExtension.Append(nsPrintfCString("%d", mPostID));
3877 }
3878 if (LoadIsTRRServiceChannel()) {
3879 mCacheIdExtension.Append("TRR");
3880 }
3881 if (mRequestHead.IsHead()) {
3882 mCacheIdExtension.Append("HEAD");
3883 }
3884 bool isThirdParty = false;
3885 if (StaticPrefs::network_fetch_cache_partition_cross_origin() &&
3886 (NS_FAILED(mLoadInfo->TriggeringPrincipal()->IsThirdPartyChannel(((bool)(__builtin_expect(!!(NS_FAILED_impl(mLoadInfo->TriggeringPrincipal
()->IsThirdPartyChannel( this, &isThirdParty))), 0)))
3887 this, &isThirdParty))((bool)(__builtin_expect(!!(NS_FAILED_impl(mLoadInfo->TriggeringPrincipal
()->IsThirdPartyChannel( this, &isThirdParty))), 0)))
||
3888 isThirdParty) &&
3889 (mLoadInfo->InternalContentPolicyType() == nsIContentPolicy::TYPE_FETCH ||
3890 mLoadInfo->InternalContentPolicyType() ==
3891 nsIContentPolicy::TYPE_XMLHTTPREQUEST ||
3892 mLoadInfo->InternalContentPolicyType() ==
3893 nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST)) {
3894 mCacheIdExtension.Append("FETCH");
3895 }
3896
3897 mCacheOpenWithPriority = cacheEntryOpenFlags & nsICacheStorage::OPEN_PRIORITY;
3898 mCacheQueueSizeWhenOpen =
3899 CacheStorageService::CacheQueueSize(mCacheOpenWithPriority);
3900
3901 if ((mNetworkTriggerDelay || StaticPrefs::network_http_rcwn_enabled()) &&
3902 maybeRCWN) {
3903 bool hasAltData = false;
3904 uint32_t sizeInKb = 0;
3905 rv = cacheStorage->GetCacheIndexEntryAttrs(
3906 mCacheEntryURI, mCacheIdExtension, &hasAltData, &sizeInKb);
3907
3908 // We will attempt to race the network vs the cache if we've found
3909 // this entry in the cache index, and it has appropriate attributes
3910 // (doesn't have alt-data, and has a small size)
3911 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !hasAltData &&
3912 sizeInKb < StaticPrefs::network_http_rcwn_small_resource_size_kb()) {
3913 MaybeRaceCacheWithNetwork();
3914 }
3915 }
3916
3917 if (!mCacheOpenDelay) {
3918 MOZ_ASSERT(NS_IsMainThread(), "Should be called on the main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Should be called on the main thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Should be called on the main thread" ")"); do { *((volatile
int*)__null) = 3918; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
3919 if (mNetworkTriggered) {
3920 mRaceCacheWithNetwork = StaticPrefs::network_http_rcwn_enabled();
3921 }
3922 rv = cacheStorage->AsyncOpenURI(mCacheEntryURI, mCacheIdExtension,
3923 cacheEntryOpenFlags, this);
3924 } else {
3925 // We pass `this` explicitly as a parameter due to the raw pointer
3926 // to refcounted object in lambda analysis.
3927 mCacheOpenFunc = [cacheEntryOpenFlags,
3928 cacheStorage](nsHttpChannel* self) -> void {
3929 MOZ_ASSERT(NS_IsMainThread(), "Should be called on the main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Should be called on the main thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3929); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Should be called on the main thread" ")"); do { *((volatile
int*)__null) = 3929; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
3930 cacheStorage->AsyncOpenURI(self->mCacheEntryURI, self->mCacheIdExtension,
3931 cacheEntryOpenFlags, self);
3932 };
3933
3934 // calls nsHttpChannel::Notify after `mCacheOpenDelay` milliseconds
3935 auto callback = MakeRefPtr<TimerCallback>(this);
3936 NS_NewTimerWithCallback(getter_AddRefs(mCacheOpenTimer), callback,
3937 mCacheOpenDelay, nsITimer::TYPE_ONE_SHOT);
3938 }
3939 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3939); return rv; } } while (false)
;
3940
3941 waitFlags.Keep(WAIT_FOR_CACHE_ENTRY);
3942
3943 return NS_OK;
3944}
3945
3946nsresult nsHttpChannel::CheckPartial(nsICacheEntry* aEntry, int64_t* aSize,
3947 int64_t* aContentLength) {
3948 return nsHttp::CheckPartial(
3949 aEntry, aSize, aContentLength,
3950 mCachedResponseHead ? mCachedResponseHead.get() : mResponseHead.get());
3951}
3952
3953void nsHttpChannel::UntieValidationRequest() {
3954 DebugOnly<nsresult> rv{};
3955 // Make the request unconditional again.
3956 rv = mRequestHead.ClearHeader(nsHttp::If_Modified_Since);
3957 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 3957; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3958 rv = mRequestHead.ClearHeader(nsHttp::If_None_Match);
3959 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3959); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 3959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3960 rv = mRequestHead.ClearHeader(nsHttp::ETag);
3961 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 3961); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 3961; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3962}
3963
3964NS_IMETHODIMPnsresult
3965nsHttpChannel::OnCacheEntryCheck(nsICacheEntry* entry, uint32_t* aResult) {
3966 nsresult rv = NS_OK;
3967
3968 LOG(("nsHttpChannel::OnCacheEntryCheck enter [channel=%p entry=%p]", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OnCacheEntryCheck enter [channel=%p entry=%p]"
, this, entry); } } while (0)
3969 entry))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OnCacheEntryCheck enter [channel=%p entry=%p]"
, this, entry); } } while (0)
;
3970
3971 mozilla::MutexAutoLock lock(mRCWNLock);
3972
3973 if (mRaceCacheWithNetwork && mFirstResponseSource == RESPONSE_FROM_NETWORK) {
3974 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Not using cached response because we've already got one from the "
"network\n"); } } while (0)
3975 ("Not using cached response because we've already got one from the "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Not using cached response because we've already got one from the "
"network\n"); } } while (0)
3976 "network\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Not using cached response because we've already got one from the "
"network\n"); } } while (0)
;
3977 *aResult = ENTRY_NOT_WANTED;
3978
3979 // Net-win indicates that mOnStartRequestTimestamp is from net.
3980 int64_t savedTime =
3981 (TimeStamp::Now() - mOnStartRequestTimestamp).ToMilliseconds();
3982 Telemetry::Accumulate(Telemetry::NETWORK_RACE_CACHE_WITH_NETWORK_SAVED_TIME,
3983 savedTime);
3984 return NS_OK;
3985 }
3986 if (mRaceCacheWithNetwork && mFirstResponseSource == RESPONSE_PENDING) {
3987 mOnCacheEntryCheckTimestamp = TimeStamp::Now();
3988 }
3989
3990 nsAutoCString cacheControlRequestHeader;
3991 Unused << mRequestHead.GetHeader(nsHttp::Cache_Control,
3992 cacheControlRequestHeader);
3993 CacheControlParser cacheControlRequest(cacheControlRequestHeader);
3994
3995 if (cacheControlRequest.NoStore()) {
3996 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Not using cached response based on no-store request cache "
"directive\n"); } } while (0)
3997 ("Not using cached response based on no-store request cache "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Not using cached response based on no-store request cache "
"directive\n"); } } while (0)
3998 "directive\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Not using cached response based on no-store request cache "
"directive\n"); } } while (0)
;
3999 *aResult = ENTRY_NOT_WANTED;
4000 return NS_OK;
4001 }
4002
4003 // Be pessimistic: assume the cache entry has no useful data.
4004 *aResult = ENTRY_WANTED;
4005 mCachedContentIsValid = false;
4006
4007 nsCString buf;
4008
4009 // Get the method that was used to generate the cached response
4010 rv = entry->GetMetaDataElement("request-method", getter_Copies(buf));
4011 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4011); return rv; } } while (false)
;
4012
4013 bool methodWasHead = buf.EqualsLiteral("HEAD");
4014 bool methodWasGet = buf.EqualsLiteral("GET");
4015
4016 if (methodWasHead) {
4017 // The cached response does not contain an entity. We can only reuse
4018 // the response if the current request is also HEAD.
4019 if (!mRequestHead.IsHead()) {
4020 *aResult = ENTRY_NOT_WANTED;
4021 return NS_OK;
4022 }
4023 }
4024 buf.Adopt(nullptr);
4025
4026 // We'll need this value in later computations...
4027 uint32_t lastModifiedTime;
4028 rv = entry->GetLastModified(&lastModifiedTime);
4029 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4029); return rv; } } while (false)
;
4030
4031 // Determine if this is the first time that this cache entry
4032 // has been accessed during this session.
4033 bool fromPreviousSession =
4034 (gHttpHandler->SessionStartTime() > lastModifiedTime);
4035
4036 // Get the cached HTTP response headers
4037 mCachedResponseHead = MakeUnique<nsHttpResponseHead>();
4038
4039 rv = nsHttp::GetHttpResponseHeadFromCacheEntry(entry,
4040 mCachedResponseHead.get());
4041 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4041); return rv; } } while (false)
;
4042
4043 bool isCachedRedirect = WillRedirect(*mCachedResponseHead);
4044
4045 // Do not return 304 responses from the cache, and also do not return
4046 // any other non-redirect 3xx responses from the cache (see bug 759043).
4047 NS_ENSURE_TRUE((mCachedResponseHead->Status() / 100 != 3) || isCachedRedirect,do { if ((__builtin_expect(!!(!((mCachedResponseHead->Status
() / 100 != 3) || isCachedRedirect)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "(mCachedResponseHead->Status() / 100 != 3) || isCachedRedirect"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4048); return NS_ERROR_ABORT; } } while (false)
4048 NS_ERROR_ABORT)do { if ((__builtin_expect(!!(!((mCachedResponseHead->Status
() / 100 != 3) || isCachedRedirect)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "(mCachedResponseHead->Status() / 100 != 3) || isCachedRedirect"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4048); return NS_ERROR_ABORT; } } while (false)
;
4049
4050 if (mCachedResponseHead->NoStore() && LoadCacheEntryIsReadOnly()) {
4051 // This prevents loading no-store responses when navigating back
4052 // while the browser is set to work offline.
4053 LOG((" entry loading as read-only but is no-store, set INHIBIT_CACHING"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " entry loading as read-only but is no-store, set INHIBIT_CACHING"
); } } while (0)
;
4054 mLoadFlags |= nsIRequest::INHIBIT_CACHING;
4055 }
4056
4057 // Don't bother to validate items that are read-only,
4058 // unless they are read-only because of INHIBIT_CACHING
4059 if ((LoadCacheEntryIsReadOnly() &&
4060 !(mLoadFlags & nsIRequest::INHIBIT_CACHING))) {
4061 int64_t size, contentLength;
4062 rv = CheckPartial(entry, &size, &contentLength);
4063 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4063); return rv; } } while (false)
;
4064
4065 if (contentLength != int64_t(-1) && contentLength != size) {
4066 *aResult = ENTRY_NOT_WANTED;
4067 return NS_OK;
4068 }
4069
4070 rv = OpenCacheInputStream(entry, true);
4071 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4072 mCachedContentIsValid = true;
4073 entry->MaybeMarkValid();
4074 }
4075 return rv;
4076 }
4077
4078 bool wantCompleteEntry = false;
4079
4080 if (!methodWasHead && !isCachedRedirect) {
4081 // If the cached content-length is set and it does not match the data
4082 // size of the cached content, then the cached response is partial...
4083 // either we need to issue a byte range request or we need to refetch
4084 // the entire document.
4085 //
4086 // We exclude redirects from this check because we (usually) strip the
4087 // entity when we store the cache entry, and even if we didn't, we
4088 // always ignore a cached redirect's entity anyway. See bug 759043.
4089 int64_t size, contentLength;
4090 rv = CheckPartial(entry, &size, &contentLength);
4091 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4091); return rv; } } while (false)
;
4092
4093 if (size == int64_t(-1)) {
4094 LOG((" write is in progress"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " write is in progress"); } } while (0)
;
4095 if (mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY) {
4096 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " not interested in the entry, " "LOAD_BYPASS_LOCAL_CACHE_IF_BUSY specified"
); } } while (0)
4097 (" not interested in the entry, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " not interested in the entry, " "LOAD_BYPASS_LOCAL_CACHE_IF_BUSY specified"
); } } while (0)
4098 "LOAD_BYPASS_LOCAL_CACHE_IF_BUSY specified"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " not interested in the entry, " "LOAD_BYPASS_LOCAL_CACHE_IF_BUSY specified"
); } } while (0)
;
4099
4100 *aResult = ENTRY_NOT_WANTED;
4101 return NS_OK;
4102 }
4103
4104 // Ignore !(size > 0) from the resumability condition
4105 if (!IsResumable(size, contentLength, true)) {
4106 if (IsNavigation()) {
4107 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " bypassing wait for the entry, " "this is a navigational load"
); } } while (0)
4108 (" bypassing wait for the entry, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " bypassing wait for the entry, " "this is a navigational load"
); } } while (0)
4109 "this is a navigational load"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " bypassing wait for the entry, " "this is a navigational load"
); } } while (0)
;
4110 *aResult = ENTRY_NOT_WANTED;
4111 return NS_OK;
4112 }
4113
4114 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " wait for entry completion, " "response is not resumable"
); } } while (0)
4115 (" wait for entry completion, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " wait for entry completion, " "response is not resumable"
); } } while (0)
4116 "response is not resumable"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " wait for entry completion, " "response is not resumable"
); } } while (0)
;
4117
4118 wantCompleteEntry = true;
4119 } else {
4120 StoreConcurrentCacheAccess(1);
4121 }
4122 } else if (contentLength != int64_t(-1) && contentLength != size) {
4123 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Cached data size does not match the Content-Length header "
"[content-length=%" "l" "d" " size=%" "l" "d" "]\n", contentLength
, size); } } while (0)
4124 ("Cached data size does not match the Content-Length header "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Cached data size does not match the Content-Length header "
"[content-length=%" "l" "d" " size=%" "l" "d" "]\n", contentLength
, size); } } while (0)
4125 "[content-length=%" PRId64 " size=%" PRId64 "]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Cached data size does not match the Content-Length header "
"[content-length=%" "l" "d" " size=%" "l" "d" "]\n", contentLength
, size); } } while (0)
4126 contentLength, size))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Cached data size does not match the Content-Length header "
"[content-length=%" "l" "d" " size=%" "l" "d" "]\n", contentLength
, size); } } while (0)
;
4127
4128 rv = MaybeSetupByteRangeRequest(size, contentLength);
4129 StoreCachedContentIsPartial(NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && LoadIsPartialRequest());
4130 if (LoadCachedContentIsPartial()) {
4131 rv = OpenCacheInputStream(entry, false);
4132 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4133 UntieByteRangeRequest();
4134 return rv;
4135 }
4136
4137 *aResult = ENTRY_NEEDS_REVALIDATION;
4138 return NS_OK;
4139 }
4140
4141 if (size == 0 && LoadCacheOnlyMetadata()) {
4142 // Don't break cache entry load when the entry's data size
4143 // is 0 and CacheOnlyMetadata flag is set. In that case we
4144 // want to proceed since the LOAD_ONLY_IF_MODIFIED flag is
4145 // also set.
4146 MOZ_ASSERT(mLoadFlags & LOAD_ONLY_IF_MODIFIED)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mLoadFlags & LOAD_ONLY_IF_MODIFIED)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mLoadFlags & LOAD_ONLY_IF_MODIFIED))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mLoadFlags & LOAD_ONLY_IF_MODIFIED"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mLoadFlags & LOAD_ONLY_IF_MODIFIED"
")"); do { *((volatile int*)__null) = 4146; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4147 } else {
4148 return rv;
4149 }
4150 }
4151 }
4152
4153 bool isHttps = mURI->SchemeIs("https");
4154
4155 bool doValidation = false;
4156 bool doBackgroundValidation = false;
4157 bool canAddImsHeader = true;
4158
4159 bool isForcedValid = false;
4160 entry->GetIsForcedValid(&isForcedValid);
4161 auto prefetchStatus = Telemetry::LABELS_PREDICTOR_PREFETCH_USE_STATUS::Used;
4162
4163 bool weaklyFramed, isImmutable;
4164 nsHttp::DetermineFramingAndImmutability(entry, mCachedResponseHead.get(),
4165 isHttps, &weaklyFramed, &isImmutable);
4166
4167 // Cached entry is not the entity we request (see bug #633743)
4168 if (ResponseWouldVary(entry)) {
4169 LOG(("Validating based on Vary headers returning TRUE\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Validating based on Vary headers returning TRUE\n"); } } while
(0)
;
4170 canAddImsHeader = false;
4171 doValidation = true;
4172 prefetchStatus = Telemetry::LABELS_PREDICTOR_PREFETCH_USE_STATUS::WouldVary;
4173 } else {
4174 if (mCachedResponseHead->ExpiresInPast() ||
4175 mCachedResponseHead->MustValidateIfExpired()) {
4176 prefetchStatus = Telemetry::LABELS_PREDICTOR_PREFETCH_USE_STATUS::Expired;
4177 }
4178 doValidation = nsHttp::ValidationRequired(
4179 isForcedValid, mCachedResponseHead.get(), mLoadFlags,
4180 LoadAllowStaleCacheContent(), LoadForceValidateCacheContent(),
4181 isImmutable, LoadCustomConditionalRequest(), mRequestHead, entry,
4182 cacheControlRequest, fromPreviousSession, &doBackgroundValidation);
4183 }
4184
4185 nsAutoCString requestedETag;
4186 if (!doValidation &&
4187 NS_SUCCEEDED(mRequestHead.GetHeader(nsHttp::If_Match, requestedETag))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mRequestHead.GetHeader
(nsHttp::If_Match, requestedETag))), 1)))
&&
4188 (methodWasGet || methodWasHead)) {
4189 nsAutoCString cachedETag;
4190 Unused << mCachedResponseHead->GetHeader(nsHttp::ETag, cachedETag);
4191 if (!cachedETag.IsEmpty() && (StringBeginsWith(cachedETag, "W/"_ns) ||
4192 !requestedETag.Equals(cachedETag))) {
4193 // User has defined If-Match header, if the cached entry is not
4194 // matching the provided header value or the cached ETag is weak,
4195 // force validation.
4196 doValidation = true;
4197 }
4198 }
4199
4200 // Previous error should not be propagated.
4201 rv = NS_OK;
4202
4203 if (!doValidation) {
4204 //
4205 // Check the authorization headers used to generate the cache entry.
4206 // We must validate the cache entry if:
4207 //
4208 // 1) the cache entry was generated prior to this session w/
4209 // credentials (see bug 103402).
4210 // 2) the cache entry was generated w/o credentials, but would now
4211 // require credentials (see bug 96705).
4212 //
4213 // NOTE: this does not apply to proxy authentication.
4214 //
4215 entry->GetMetaDataElement("auth", getter_Copies(buf));
4216 doValidation =
4217 (fromPreviousSession && !buf.IsEmpty()) ||
4218 (buf.IsEmpty() && mRequestHead.HasHeader(nsHttp::Authorization));
4219 if (doValidation) {
4220 prefetchStatus = Telemetry::LABELS_PREDICTOR_PREFETCH_USE_STATUS::Auth;
4221 }
4222 }
4223
4224 // Bug #561276: We maintain a chain of cache-keys which returns cached
4225 // 3xx-responses (redirects) in order to detect cycles. If a cycle is
4226 // found, ignore the cached response and hit the net. Otherwise, use
4227 // the cached response and add the cache-key to the chain. Note that
4228 // a limited number of redirects (cached or not) is allowed and is
4229 // enforced independently of this mechanism
4230 if (!doValidation && isCachedRedirect) {
4231 nsAutoCString cacheKey;
4232 rv = GenerateCacheKey(mPostID, cacheKey);
4233 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4233); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 4233; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4234
4235 auto redirectedCachekeys = mRedirectedCachekeys.Lock();
4236 auto& ref = redirectedCachekeys.ref();
4237 if (!ref) {
4238 ref = MakeUnique<nsTArray<nsCString>>();
4239 } else if (ref->Contains(cacheKey)) {
4240 doValidation = true;
4241 }
4242
4243 LOG(("Redirection-chain %s key %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Redirection-chain %s key %s\n", doValidation ? "contains" :
"does not contain", cacheKey.get()); } } while (0)
4244 doValidation ? "contains" : "does not contain", cacheKey.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Redirection-chain %s key %s\n", doValidation ? "contains" :
"does not contain", cacheKey.get()); } } while (0)
;
4245
4246 // Append cacheKey if not in the chain already
4247 if (!doValidation) {
4248 ref->AppendElement(cacheKey);
4249 } else {
4250 prefetchStatus =
4251 Telemetry::LABELS_PREDICTOR_PREFETCH_USE_STATUS::Redirect;
4252 }
4253 }
4254
4255 mCachedContentIsValid = !doValidation;
4256
4257 if (isForcedValid) {
4258 // Telemetry value is only useful if this was a prefetched item
4259 if (!doValidation) {
4260 // Could have gotten to a funky state with some of the if chain above
4261 // and in nsHttp::ValidationRequired. Make sure we get it right here.
4262 prefetchStatus = Telemetry::LABELS_PREDICTOR_PREFETCH_USE_STATUS::Used;
4263
4264 entry->MarkForcedValidUse();
4265 }
4266 Telemetry::AccumulateCategorical(prefetchStatus);
4267 }
4268
4269 if (doValidation) {
4270 //
4271 // now, we are definitely going to issue a HTTP request to the server.
4272 // make it conditional if possible.
4273 //
4274 // do not attempt to validate no-store content, since servers will not
4275 // expect it to be cached. (we only keep it in our cache for the
4276 // purposes of back/forward, etc.)
4277 //
4278 // the request method MUST be either GET or HEAD (see bug 175641) and
4279 // the cached response code must be < 400
4280 //
4281 // the cached content must not be weakly framed
4282 //
4283 // do not override conditional headers when consumer has defined its own
4284 if (!mCachedResponseHead->NoStore() &&
4285 (mRequestHead.IsGet() || mRequestHead.IsHead()) &&
4286 !LoadCustomConditionalRequest() && !weaklyFramed &&
4287 (mCachedResponseHead->Status() < 400)) {
4288 if (LoadConcurrentCacheAccess()) {
4289 // In case of concurrent read and also validation request we
4290 // must wait for the current writer to close the output stream
4291 // first. Otherwise, when the writer's job would have been interrupted
4292 // before all the data were downloaded, we'd have to do a range request
4293 // which would be a second request in line during this channel's
4294 // life-time. nsHttpChannel is not designed to do that, so rather
4295 // turn off concurrent read and wait for entry's completion.
4296 // Then only re-validation or range-re-validation request will go out.
4297 StoreConcurrentCacheAccess(0);
4298 // This will cause that OnCacheEntryCheck is called again with the same
4299 // entry after the writer is done.
4300 wantCompleteEntry = true;
4301 } else {
4302 nsAutoCString val;
4303 // Add If-Modified-Since header if a Last-Modified was given
4304 // and we are allowed to do this (see bugs 510359 and 269303)
4305 if (canAddImsHeader) {
4306 Unused << mCachedResponseHead->GetHeader(nsHttp::Last_Modified, val);
4307 if (!val.IsEmpty()) {
4308 rv = mRequestHead.SetHeader(nsHttp::If_Modified_Since, val);
4309 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4309); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 4309; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4310 }
4311 }
4312 // Add If-None-Match header if an ETag was given in the response
4313 Unused << mCachedResponseHead->GetHeader(nsHttp::ETag, val);
4314 if (!val.IsEmpty()) {
4315 rv = mRequestHead.SetHeader(nsHttp::If_None_Match, val);
4316 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4316); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 4316; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4317 }
4318 mDidReval = true;
4319 }
4320 }
4321 }
4322
4323 if (mCachedContentIsValid || mDidReval) {
4324 rv = OpenCacheInputStream(entry, mCachedContentIsValid);
4325 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4326 // If we can't get the entity then we have to act as though we
4327 // don't have the cache entry.
4328 if (mDidReval) {
4329 UntieValidationRequest();
4330 mDidReval = false;
4331 }
4332 mCachedContentIsValid = false;
4333 }
4334 }
4335
4336 if (mDidReval) {
4337 *aResult = ENTRY_NEEDS_REVALIDATION;
4338 } else if (wantCompleteEntry) {
4339 *aResult = RECHECK_AFTER_WRITE_FINISHED;
4340 } else {
4341 *aResult = ENTRY_WANTED;
4342
4343 if (doBackgroundValidation) {
4344 PerformBackgroundCacheRevalidation();
4345 }
4346 }
4347
4348 if (mCachedContentIsValid) {
4349 entry->MaybeMarkValid();
4350 }
4351
4352 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHTTPChannel::OnCacheEntryCheck exit [this=%p doValidation=%d "
"result=%d]\n", this, doValidation, *aResult); } } while (0)
4353 ("nsHTTPChannel::OnCacheEntryCheck exit [this=%p doValidation=%d "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHTTPChannel::OnCacheEntryCheck exit [this=%p doValidation=%d "
"result=%d]\n", this, doValidation, *aResult); } } while (0)
4354 "result=%d]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHTTPChannel::OnCacheEntryCheck exit [this=%p doValidation=%d "
"result=%d]\n", this, doValidation, *aResult); } } while (0)
4355 this, doValidation, *aResult))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHTTPChannel::OnCacheEntryCheck exit [this=%p doValidation=%d "
"result=%d]\n", this, doValidation, *aResult); } } while (0)
;
4356 return rv;
4357}
4358
4359NS_IMETHODIMPnsresult
4360nsHttpChannel::OnCacheEntryAvailable(nsICacheEntry* entry, bool aNew,
4361 nsresult status) {
4362 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4362); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4362; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4363
4364 nsresult rv;
4365
4366 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OnCacheEntryAvailable [this=%p entry=%p " "new=%d status=%"
"x" "]\n", this, entry, aNew, static_cast<uint32_t>(status
)); } } while (0)
4367 ("nsHttpChannel::OnCacheEntryAvailable [this=%p entry=%p "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OnCacheEntryAvailable [this=%p entry=%p " "new=%d status=%"
"x" "]\n", this, entry, aNew, static_cast<uint32_t>(status
)); } } while (0)
4368 "new=%d status=%" PRIx32 "]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OnCacheEntryAvailable [this=%p entry=%p " "new=%d status=%"
"x" "]\n", this, entry, aNew, static_cast<uint32_t>(status
)); } } while (0)
4369 this, entry, aNew, static_cast<uint32_t>(status)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::OnCacheEntryAvailable [this=%p entry=%p " "new=%d status=%"
"x" "]\n", this, entry, aNew, static_cast<uint32_t>(status
)); } } while (0)
;
4370
4371 // if the channel's already fired onStopRequest, then we should ignore
4372 // this event.
4373 if (!LoadIsPending()) {
4374 mCacheInputStream.CloseAndRelease();
4375 return NS_OK;
4376 }
4377
4378 rv = OnCacheEntryAvailableInternal(entry, aNew, status);
4379 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4380 CloseCacheEntry(false);
4381 if (mRaceCacheWithNetwork && mNetworkTriggered &&
4382 mFirstResponseSource != RESPONSE_FROM_CACHE) {
4383 // Ignore the error if we're racing cache with network and the cache
4384 // didn't win, The network part will handle cancelation or any other
4385 // error. Otherwise we could end up calling the listener twice, see
4386 // bug 1397593.
4387 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " not calling AsyncAbort() because we're racing cache with "
"network"); } } while (0)
4388 (" not calling AsyncAbort() because we're racing cache with "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " not calling AsyncAbort() because we're racing cache with "
"network"); } } while (0)
4389 "network"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " not calling AsyncAbort() because we're racing cache with "
"network"); } } while (0)
;
4390 } else {
4391 Unused << AsyncAbort(rv);
4392 }
4393 }
4394
4395 return NS_OK;
4396}
4397
4398nsresult nsHttpChannel::OnCacheEntryAvailableInternal(nsICacheEntry* entry,
4399 bool aNew,
4400 nsresult status) {
4401 nsresult rv;
4402
4403 if (mCanceled) {
4404 LOG(("channel was canceled [this=%p status=%" PRIx32 "]\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "channel was canceled [this=%p status=%" "x" "]\n", this, static_cast
<uint32_t>(static_cast<nsresult>(mStatus))); } } while
(0)
4405 static_cast<uint32_t>(static_cast<nsresult>(mStatus))))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "channel was canceled [this=%p status=%" "x" "]\n", this, static_cast
<uint32_t>(static_cast<nsresult>(mStatus))); } } while
(0)
;
4406 return mStatus;
4407 }
4408
4409 if (mIgnoreCacheEntry) {
4410 if (!entry || aNew) {
4411 // We use this flag later to decide whether to report
4412 // LABELS_NETWORK_RACE_CACHE_VALIDATION::NotSent. We didn't have
4413 // an usable entry, so drop the flag.
4414 mIgnoreCacheEntry = false;
4415 }
4416 entry = nullptr;
4417 status = NS_ERROR_NOT_AVAILABLE;
4418 }
4419
4420 rv = OnNormalCacheEntryAvailable(entry, aNew, status);
4421
4422 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && (mLoadFlags & LOAD_ONLY_FROM_CACHE)) {
4423 return NS_ERROR_DOCUMENT_NOT_CACHED;
4424 }
4425
4426 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4427 return rv;
4428 }
4429
4430 // We may be waiting for more callbacks...
4431 if (AwaitingCacheCallbacks()) {
4432 return NS_OK;
4433 }
4434
4435 if (mRaceCacheWithNetwork && ((mCacheEntry && !mCachedContentIsValid &&
4436 (mDidReval || LoadCachedContentIsPartial())) ||
4437 mIgnoreCacheEntry)) {
4438 // We won't send the conditional request because the unconditional
4439 // request was already sent (see bug 1377223).
4440 AccumulateCategorical(
4441 Telemetry::LABELS_NETWORK_RACE_CACHE_VALIDATION::NotSent);
4442 }
4443
4444 if (mRaceCacheWithNetwork && mCachedContentIsValid) {
4445 Unused << ReadFromCache(true);
4446 }
4447
4448 return TriggerNetwork();
4449}
4450
4451nsresult nsHttpChannel::OnNormalCacheEntryAvailable(nsICacheEntry* aEntry,
4452 bool aNew,
4453 nsresult aEntryStatus) {
4454 StoreWaitForCacheEntry(LoadWaitForCacheEntry() & ~WAIT_FOR_CACHE_ENTRY);
4455
4456 if (NS_FAILED(aEntryStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(aEntryStatus)), 0)
))
|| aNew) {
4457 // Make sure this flag is dropped. It may happen the entry is doomed
4458 // between OnCacheEntryCheck and OnCacheEntryAvailable.
4459 mCachedContentIsValid = false;
4460
4461 // From the same reason remove any conditional headers added
4462 // in OnCacheEntryCheck.
4463 if (mDidReval) {
4464 LOG((" Removing conditional request headers"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " Removing conditional request headers"); } } while (0)
;
4465 UntieValidationRequest();
4466 mDidReval = false;
4467 }
4468
4469 if (LoadCachedContentIsPartial()) {
4470 LOG((" Removing byte range request headers"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, " Removing byte range request headers"); } } while (0)
;
4471 UntieByteRangeRequest();
4472 StoreCachedContentIsPartial(false);
4473 }
4474
4475 if (mLoadFlags & LOAD_ONLY_FROM_CACHE) {
4476 // if this channel is only allowed to pull from the cache, then
4477 // we must fail if we were unable to open a cache entry for read.
4478 return NS_ERROR_DOCUMENT_NOT_CACHED;
4479 }
4480 }
4481
4482 if (NS_SUCCEEDED(aEntryStatus)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aEntryStatus)), 1
)))
) {
4483 mCacheEntry = aEntry;
4484 StoreCacheEntryIsWriteOnly(aNew);
4485
4486 if (!aNew && !mAsyncOpenTime.IsNull()) {
4487 // We use microseconds for IO operations. For consistency let's use
4488 // microseconds here too.
4489 uint32_t duration = (TimeStamp::Now() - mAsyncOpenTime).ToMicroseconds();
4490 bool isSlow = false;
4491 if ((mCacheOpenWithPriority &&
4492 mCacheQueueSizeWhenOpen >=
4493 StaticPrefs::
4494 network_http_rcwn_cache_queue_priority_threshold()) ||
4495 (!mCacheOpenWithPriority &&
4496 mCacheQueueSizeWhenOpen >=
4497 StaticPrefs::network_http_rcwn_cache_queue_normal_threshold())) {
4498 isSlow = true;
4499 }
4500 CacheFileUtils::CachePerfStats::AddValue(
4501 CacheFileUtils::CachePerfStats::ENTRY_OPEN, duration, isSlow);
4502 }
4503 }
4504
4505 return NS_OK;
4506}
4507
4508// Generates the proper cache-key for this instance of nsHttpChannel
4509nsresult nsHttpChannel::GenerateCacheKey(uint32_t postID,
4510 nsACString& cacheKey) {
4511 AssembleCacheKey(mSpec.get(), postID, cacheKey);
4512 return NS_OK;
4513}
4514
4515// Assembles a cache-key from the given pieces of information and |mLoadFlags|
4516void nsHttpChannel::AssembleCacheKey(const char* spec, uint32_t postID,
4517 nsACString& cacheKey) {
4518 cacheKey.Truncate();
4519
4520 if (mLoadFlags & LOAD_ANONYMOUS) {
4521 cacheKey.AssignLiteral("anon&");
4522 }
4523
4524 if (postID) {
4525 char buf[32];
4526 SprintfLiteral(buf, "id=%x&", postID);
4527 cacheKey.Append(buf);
4528 }
4529
4530 if (!cacheKey.IsEmpty()) {
4531 cacheKey.AppendLiteral("uri=");
4532 }
4533
4534 // Strip any trailing #ref from the URL before using it as the key
4535 const char* p = strchr(spec, '#');
4536 if (p) {
4537 cacheKey.Append(spec, p - spec);
4538 } else {
4539 cacheKey.Append(spec);
4540 }
4541}
4542
4543nsresult DoUpdateExpirationTime(nsHttpChannel* aSelf,
4544 nsICacheEntry* aCacheEntry,
4545 nsHttpResponseHead* aResponseHead,
4546 uint32_t& aExpirationTime) {
4547 MOZ_ASSERT(aExpirationTime == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aExpirationTime == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aExpirationTime == 0))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aExpirationTime == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4547); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aExpirationTime == 0"
")"); do { *((volatile int*)__null) = 4547; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4548 NS_ENSURE_TRUE(aResponseHead, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(aResponseHead)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aResponseHead" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4548); return NS_ERROR_FAILURE; } } while (false)
;
4549
4550 nsresult rv;
4551
4552 if (!aResponseHead->MustValidate()) {
4553 // For stale-while-revalidate we use expiration time as the absolute base
4554 // for calculation of the stale window absolute end time. Hence, when the
4555 // entry may be served w/o revalidation, we need a non-zero value for the
4556 // expiration time. Let's set it to |now|, which basicly means "expired",
4557 // same as when set to 0.
4558 uint32_t now = NowInSeconds()PRTimeToSeconds(PR_Now());
4559 aExpirationTime = now;
4560
4561 uint32_t freshnessLifetime = 0;
4562
4563 rv = aResponseHead->ComputeFreshnessLifetime(&freshnessLifetime);
4564 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
4565
4566 if (freshnessLifetime > 0) {
4567 uint32_t currentAge = 0;
4568
4569 rv = aResponseHead->ComputeCurrentAge(now, aSelf->GetRequestTime(),
4570 &currentAge);
4571 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
4572
4573 LOG(("freshnessLifetime = %u, currentAge = %u\n", freshnessLifetime,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "freshnessLifetime = %u, currentAge = %u\n", freshnessLifetime
, currentAge); } } while (0)
4574 currentAge))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "freshnessLifetime = %u, currentAge = %u\n", freshnessLifetime
, currentAge); } } while (0)
;
4575
4576 if (freshnessLifetime > currentAge) {
4577 uint32_t timeRemaining = freshnessLifetime - currentAge;
4578 // be careful... now + timeRemaining may overflow
4579 if (now + timeRemaining < now) {
4580 aExpirationTime = uint32_t(-1);
4581 } else {
4582 aExpirationTime = now + timeRemaining;
4583 }
4584 }
4585 }
4586 }
4587
4588 rv = aCacheEntry->SetExpirationTime(aExpirationTime);
4589 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4589); return rv; } } while (false)
;
4590
4591 return rv;
4592}
4593
4594// UpdateExpirationTime is called when a new response comes in from the server.
4595// It updates the stored response-time and sets the expiration time on the
4596// cache entry.
4597//
4598// From section 13.2.4 of RFC2616, we compute expiration time as follows:
4599//
4600// timeRemaining = freshnessLifetime - currentAge
4601// expirationTime = now + timeRemaining
4602//
4603nsresult nsHttpChannel::UpdateExpirationTime() {
4604 uint32_t expirationTime = 0;
4605 nsresult rv = DoUpdateExpirationTime(this, mCacheEntry, mResponseHead.get(),
4606 expirationTime);
4607 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4607); return rv; } } while (false)
;
4608
4609 return NS_OK;
4610}
4611
4612nsresult nsHttpChannel::OpenCacheInputStream(nsICacheEntry* cacheEntry,
4613 bool startBuffering) {
4614 nsresult rv;
4615
4616 if (mURI->SchemeIs("https")) {
4617 rv = cacheEntry->GetSecurityInfo(getter_AddRefs(mCachedSecurityInfo));
4618 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4619 LOG(("failed to parse security-info [channel=%p, entry=%p]", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "failed to parse security-info [channel=%p, entry=%p]", this
, cacheEntry); } } while (0)
4620 cacheEntry))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "failed to parse security-info [channel=%p, entry=%p]", this
, cacheEntry); } } while (0)
;
4621 NS_WARNING("failed to parse security-info")NS_DebugBreak(NS_DEBUG_WARNING, "failed to parse security-info"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4621)
;
4622 cacheEntry->AsyncDoom(nullptr);
4623 return rv;
4624 }
4625
4626 MOZ_ASSERT(mCachedSecurityInfo)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCachedSecurityInfo)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCachedSecurityInfo))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("mCachedSecurityInfo"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4626); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCachedSecurityInfo"
")"); do { *((volatile int*)__null) = 4626; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4627 if (!mCachedSecurityInfo) {
4628 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "mCacheEntry->GetSecurityInfo returned success but did not "
"return the security info [channel=%p, entry=%p]", this, cacheEntry
); } } while (0)
4629 ("mCacheEntry->GetSecurityInfo returned success but did not "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "mCacheEntry->GetSecurityInfo returned success but did not "
"return the security info [channel=%p, entry=%p]", this, cacheEntry
); } } while (0)
4630 "return the security info [channel=%p, entry=%p]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "mCacheEntry->GetSecurityInfo returned success but did not "
"return the security info [channel=%p, entry=%p]", this, cacheEntry
); } } while (0)
4631 this, cacheEntry))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "mCacheEntry->GetSecurityInfo returned success but did not "
"return the security info [channel=%p, entry=%p]", this, cacheEntry
); } } while (0)
;
4632 cacheEntry->AsyncDoom(nullptr);
4633 return NS_ERROR_UNEXPECTED; // XXX error code
4634 }
4635 }
4636
4637 // Keep the conditions below in sync with the conditions in ReadFromCache.
4638
4639 rv = NS_OK;
4640
4641 if (WillRedirect(*mCachedResponseHead)) {
4642 // Do not even try to read the entity for a redirect because we do not
4643 // return an entity to the application when we process redirects.
4644 LOG(("Will skip read of cached redirect entity\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Will skip read of cached redirect entity\n"); } } while (0
)
;
4645 return NS_OK;
4646 }
4647
4648 if ((mLoadFlags & nsICachingChannel::LOAD_ONLY_IF_MODIFIED) &&
4649 !LoadCachedContentIsPartial()) {
4650 // For LOAD_ONLY_IF_MODIFIED, we usually don't have to deal with the
4651 // cached entity.
4652 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Will skip read from cache based on LOAD_ONLY_IF_MODIFIED "
"load flag\n"); } } while (0)
4653 ("Will skip read from cache based on LOAD_ONLY_IF_MODIFIED "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Will skip read from cache based on LOAD_ONLY_IF_MODIFIED "
"load flag\n"); } } while (0)
4654 "load flag\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Will skip read from cache based on LOAD_ONLY_IF_MODIFIED "
"load flag\n"); } } while (0)
;
4655 return NS_OK;
4656 }
4657
4658 // Open an input stream for the entity, so that the call to OpenInputStream
4659 // happens off the main thread.
4660 nsCOMPtr<nsIInputStream> stream;
4661
4662 // If an alternate representation was requested, try to open the alt
4663 // input stream.
4664 // If the entry has a "is-from-child" metadata, then only open the altdata
4665 // stream if the consumer is also from child.
4666 bool altDataFromChild = false;
4667 {
4668 nsCString value;
4669 rv = cacheEntry->GetMetaDataElement("alt-data-from-child",
4670 getter_Copies(value));
4671 altDataFromChild = !value.IsEmpty();
4672 }
4673
4674 nsAutoCString altDataType;
4675 Unused << cacheEntry->GetAltDataType(altDataType);
4676
4677 nsAutoCString contentType;
4678 mCachedResponseHead->ContentType(contentType);
4679
4680 bool foundAltData = false;
4681 bool deliverAltData = true;
4682 if (!LoadDisableAltDataCache() && !altDataType.IsEmpty() &&
4683 !mPreferredCachedAltDataTypes.IsEmpty() &&
4684 altDataFromChild == LoadAltDataForChild()) {
4685 for (auto& pref : mPreferredCachedAltDataTypes) {
4686 if (pref.type() == altDataType &&
4687 (pref.contentType().IsEmpty() || pref.contentType() == contentType)) {
4688 foundAltData = true;
4689 deliverAltData =
4690 pref.deliverAltData() ==
4691 nsICacheInfoChannel::PreferredAlternativeDataDeliveryType::ASYNC;
4692 break;
4693 }
4694 }
4695 }
4696
4697 nsCOMPtr<nsIInputStream> altData;
4698 int64_t altDataSize = -1;
4699 if (foundAltData) {
4700 rv = cacheEntry->OpenAlternativeInputStream(altDataType,
4701 getter_AddRefs(altData));
4702 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4703 // We have succeeded.
4704 mAvailableCachedAltDataType = altDataType;
4705 StoreDeliveringAltData(deliverAltData);
4706
4707 // Set the correct data size on the channel.
4708 Unused << cacheEntry->GetAltDataSize(&altDataSize);
4709 mAltDataLength = altDataSize;
4710
4711 LOG(("Opened alt-data input stream [type=%s, size=%" PRId64do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Opened alt-data input stream [type=%s, size=%" "l" "d" ", deliverAltData=%d]"
, altDataType.get(), mAltDataLength, deliverAltData); } } while
(0)
4712 ", deliverAltData=%d]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Opened alt-data input stream [type=%s, size=%" "l" "d" ", deliverAltData=%d]"
, altDataType.get(), mAltDataLength, deliverAltData); } } while
(0)
4713 altDataType.get(), mAltDataLength, deliverAltData))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Opened alt-data input stream [type=%s, size=%" "l" "d" ", deliverAltData=%d]"
, altDataType.get(), mAltDataLength, deliverAltData); } } while
(0)
;
4714
4715 if (deliverAltData) {
4716 stream = altData;
4717 }
4718 }
4719 }
4720
4721 if (!stream) {
4722 rv = cacheEntry->OpenInputStream(0, getter_AddRefs(stream));
4723 }
4724
4725 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4726 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Failed to open cache input stream [channel=%p, " "mCacheEntry=%p]"
, this, cacheEntry); } } while (0)
4727 ("Failed to open cache input stream [channel=%p, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Failed to open cache input stream [channel=%p, " "mCacheEntry=%p]"
, this, cacheEntry); } } while (0)
4728 "mCacheEntry=%p]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Failed to open cache input stream [channel=%p, " "mCacheEntry=%p]"
, this, cacheEntry); } } while (0)
4729 this, cacheEntry))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Failed to open cache input stream [channel=%p, " "mCacheEntry=%p]"
, this, cacheEntry); } } while (0)
;
4730 return rv;
4731 }
4732
4733 if (startBuffering) {
4734 bool nonBlocking;
4735 rv = stream->IsNonBlocking(&nonBlocking);
4736 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && nonBlocking) startBuffering = false;
4737 }
4738
4739 if (!startBuffering) {
4740 // Bypass wrapping the input stream for the new cache back-end since
4741 // nsIStreamTransportService expects a blocking stream. Preloading of
4742 // the data must be done on the level of the cache backend, internally.
4743 //
4744 // We do not connect the stream to the stream transport service if we
4745 // have to validate the entry with the server. If we did, we would get
4746 // into a race condition between the stream transport service reading
4747 // the existing contents and the opening of the cache entry's output
4748 // stream to write the new contents in the case where we get a non-304
4749 // response.
4750 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Opened cache input stream without buffering [channel=%p, "
"mCacheEntry=%p, stream=%p]", this, cacheEntry, stream.get()
); } } while (0)
4751 ("Opened cache input stream without buffering [channel=%p, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Opened cache input stream without buffering [channel=%p, "
"mCacheEntry=%p, stream=%p]", this, cacheEntry, stream.get()
); } } while (0)
4752 "mCacheEntry=%p, stream=%p]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Opened cache input stream without buffering [channel=%p, "
"mCacheEntry=%p, stream=%p]", this, cacheEntry, stream.get()
); } } while (0)
4753 this, cacheEntry, stream.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Opened cache input stream without buffering [channel=%p, "
"mCacheEntry=%p, stream=%p]", this, cacheEntry, stream.get()
); } } while (0)
;
4754 mCacheInputStream.takeOver(stream);
4755 return rv;
4756 }
4757
4758 // Have the stream transport service start reading the entity on one of its
4759 // background threads.
4760
4761 nsCOMPtr<nsITransport> transport;
4762 nsCOMPtr<nsIInputStream> wrapper;
4763
4764 nsCOMPtr<nsIStreamTransportService> sts(
4765 components::StreamTransport::Service());
4766 rv = sts ? NS_OK : NS_ERROR_NOT_AVAILABLE;
4767 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4768 rv = sts->CreateInputTransport(stream, true, getter_AddRefs(transport));
4769 }
4770 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4771 rv = transport->OpenInputStream(0, 0, 0, getter_AddRefs(wrapper));
4772 }
4773 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4774 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Opened cache input stream [channel=%p, wrapper=%p, " "transport=%p, stream=%p]"
, this, wrapper.get(), transport.get(), stream.get()); } } while
(0)
4775 ("Opened cache input stream [channel=%p, wrapper=%p, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Opened cache input stream [channel=%p, wrapper=%p, " "transport=%p, stream=%p]"
, this, wrapper.get(), transport.get(), stream.get()); } } while
(0)
4776 "transport=%p, stream=%p]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Opened cache input stream [channel=%p, wrapper=%p, " "transport=%p, stream=%p]"
, this, wrapper.get(), transport.get(), stream.get()); } } while
(0)
4777 this, wrapper.get(), transport.get(), stream.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Opened cache input stream [channel=%p, wrapper=%p, " "transport=%p, stream=%p]"
, this, wrapper.get(), transport.get(), stream.get()); } } while
(0)
;
4778 } else {
4779 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Failed to open cache input stream [channel=%p, " "wrapper=%p, transport=%p, stream=%p]"
, this, wrapper.get(), transport.get(), stream.get()); } } while
(0)
4780 ("Failed to open cache input stream [channel=%p, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Failed to open cache input stream [channel=%p, " "wrapper=%p, transport=%p, stream=%p]"
, this, wrapper.get(), transport.get(), stream.get()); } } while
(0)
4781 "wrapper=%p, transport=%p, stream=%p]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Failed to open cache input stream [channel=%p, " "wrapper=%p, transport=%p, stream=%p]"
, this, wrapper.get(), transport.get(), stream.get()); } } while
(0)
4782 this, wrapper.get(), transport.get(), stream.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Failed to open cache input stream [channel=%p, " "wrapper=%p, transport=%p, stream=%p]"
, this, wrapper.get(), transport.get(), stream.get()); } } while
(0)
;
4783
4784 stream->Close();
4785 return rv;
4786 }
4787
4788 mCacheInputStream.takeOver(wrapper);
4789
4790 return NS_OK;
4791}
4792
4793// Actually process the cached response that we started to handle in CheckCache
4794// and/or StartBufferingCachedEntity.
4795nsresult nsHttpChannel::ReadFromCache(bool alreadyMarkedValid) {
4796 NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mCacheEntry)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mCacheEntry" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4796); return NS_ERROR_FAILURE; } } while (false)
;
4797 NS_ENSURE_TRUE(mCachedContentIsValid, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mCachedContentIsValid)), 0)))
{ NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mCachedContentIsValid"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4797); return NS_ERROR_FAILURE; } } while (false)
;
4798 NS_ENSURE_TRUE(!mCachePump, NS_OK)do { if ((__builtin_expect(!!(!(!mCachePump)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "!mCachePump" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4798); return NS_OK; } } while (false)
; // already opened
4799
4800 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ReadFromCache [this=%p] " "Using cached copy of: %s\n"
, this, mSpec.get()); } } while (0)
4801 ("nsHttpChannel::ReadFromCache [this=%p] "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ReadFromCache [this=%p] " "Using cached copy of: %s\n"
, this, mSpec.get()); } } while (0)
4802 "Using cached copy of: %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ReadFromCache [this=%p] " "Using cached copy of: %s\n"
, this, mSpec.get()); } } while (0)
4803 this, mSpec.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "nsHttpChannel::ReadFromCache [this=%p] " "Using cached copy of: %s\n"
, this, mSpec.get()); } } while (0)
;
4804
4805 // When racing the cache with the network with a timer, and we get data from
4806 // the cache, we should prevent the timer from triggering a network request.
4807 if (mNetworkTriggerTimer) {
4808 mNetworkTriggerTimer->Cancel();
4809 mNetworkTriggerTimer = nullptr;
4810 }
4811
4812 if (mRaceCacheWithNetwork) {
4813 MOZ_ASSERT(mFirstResponseSource != RESPONSE_FROM_CACHE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFirstResponseSource != RESPONSE_FROM_CACHE)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mFirstResponseSource != RESPONSE_FROM_CACHE))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mFirstResponseSource != RESPONSE_FROM_CACHE"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4813); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFirstResponseSource != RESPONSE_FROM_CACHE"
")"); do { *((volatile int*)__null) = 4813; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4814 if (mFirstResponseSource == RESPONSE_PENDING) {
4815 LOG(("First response from cache\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "First response from cache\n"); } } while (0)
;
4816 mFirstResponseSource = RESPONSE_FROM_CACHE;
4817
4818 // Cancel the transaction because we will serve the request from the cache
4819 CancelNetworkRequest(NS_BINDING_ABORTED);
4820 if (mTransactionPump && mSuspendCount) {
4821 uint32_t suspendCount = mSuspendCount;
4822 while (suspendCount--) {
4823 mTransactionPump->Resume();
4824 }
4825 }
4826 mTransaction = nullptr;
4827 mTransactionPump = nullptr;
4828 } else {
4829 MOZ_ASSERT(mFirstResponseSource == RESPONSE_FROM_NETWORK)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFirstResponseSource == RESPONSE_FROM_NETWORK)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mFirstResponseSource == RESPONSE_FROM_NETWORK))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("mFirstResponseSource == RESPONSE_FROM_NETWORK"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4829); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFirstResponseSource == RESPONSE_FROM_NETWORK"
")"); do { *((volatile int*)__null) = 4829; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4830 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Skipping read from cache because first response was from "
"network\n"); } } while (0)
4831 ("Skipping read from cache because first response was from "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Skipping read from cache because first response was from "
"network\n"); } } while (0)
4832 "network\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Skipping read from cache because first response was from "
"network\n"); } } while (0)
;
4833
4834 if (!mOnCacheEntryCheckTimestamp.IsNull()) {
4835 TimeStamp currentTime = TimeStamp::Now();
4836 int64_t savedTime =
4837 (currentTime - mOnStartRequestTimestamp).ToMilliseconds();
4838 Telemetry::Accumulate(
4839 Telemetry::NETWORK_RACE_CACHE_WITH_NETWORK_SAVED_TIME, savedTime);
4840
4841 int64_t diffTime =
4842 (currentTime - mOnCacheEntryCheckTimestamp).ToMilliseconds();
4843 Telemetry::Accumulate(
4844 Telemetry::NETWORK_RACE_CACHE_WITH_NETWORK_OCEC_ON_START_DIFF,
4845 diffTime);
4846 }
4847 return NS_OK;
4848 }
4849 }
4850
4851 if (mCachedResponseHead) mResponseHead = std::move(mCachedResponseHead);
4852
4853 UpdateInhibitPersistentCachingFlag();
4854
4855 // if we don't already have security info, try to get it from the cache
4856 // entry. there are two cases to consider here: 1) we are just reading
4857 // from the cache, or 2) this may be due to a 304 not modified response,
4858 // in which case we could have security info from a socket transport.
4859 if (!mSecurityInfo) mSecurityInfo = mCachedSecurityInfo;
4860
4861 if (!alreadyMarkedValid && !LoadCachedContentIsPartial()) {
4862 // We validated the entry, and we have write access to the cache, so
4863 // mark the cache entry as valid in order to allow others access to
4864 // this cache entry.
4865 //
4866 // TODO: This should be done asynchronously so we don't take the cache
4867 // service lock on the main thread.
4868 mCacheEntry->MaybeMarkValid();
4869 }
4870
4871 nsresult rv;
4872
4873 // Keep the conditions below in sync with the conditions in
4874 // StartBufferingCachedEntity.
4875
4876 if (WillRedirect(*mResponseHead)) {
4877 // TODO: Bug 759040 - We should call HandleAsyncRedirect directly here,
4878 // to avoid event dispatching latency.
4879 MOZ_ASSERT(!mCacheInputStream)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCacheInputStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCacheInputStream))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mCacheInputStream"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/nsHttpChannel.cpp"
, 4879); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCacheInputStream"
")"); do { *((volatile int*)__null) = 4879; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4880 LOG(("Skipping skip read of cached redirect entity\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Skipping skip read of cached redirect entity\n"); } } while
(0)
;
4881 return AsyncCall(&nsHttpChannel::HandleAsyncRedirect);
4882 }
4883
4884 if ((mLoadFlags & LOAD_ONLY_IF_MODIFIED) && !LoadCachedContentIsPartial()) {
4885 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Skipping read from cache based on LOAD_ONLY_IF_MODIFIED " "load flag\n"
); } } while (0)
4886 ("Skipping read from cache based on LOAD_ONLY_IF_MODIFIED "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Skipping read from cache based on LOAD_ONLY_IF_MODIFIED " "load flag\n"
); } } while (0)
4887 "load flag\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozi