Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/protocol/http/./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp
Warning:line 824, column 5
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_protocol_http5.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=/root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/protocol/http -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/protocol/http -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_APP_UA_NAME="" -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/netwerk/protocol/http -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/protocol/http -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/dom/base -I /root/firefox-clang/netwerk/base -I /root/firefox-clang/netwerk/cookie -I /root/firefox-clang/netwerk/dns -I /root/firefox-clang/netwerk/ipc -I /root/firefox-clang/netwerk/socket/neqo_glue -I /root/firefox-clang/netwerk/url-classifier -I /root/firefox-clang/extensions/auth -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -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-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 -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-28-231034-2746175-1 -x c++ Unified_cpp_protocol_http5.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "nsCORSListenerProxy.h"
6
7#include <algorithm>
8
9#include "HttpChannelChild.h"
10#include "mozilla/Assertions.h"
11#include "mozilla/BasePrincipal.h"
12#include "mozilla/Components.h"
13#include "mozilla/ExpandedPrincipal.h"
14#include "mozilla/LinkedList.h"
15#include "mozilla/LoadInfo.h"
16#include "mozilla/NullPrincipal.h"
17#include "mozilla/Preferences.h"
18#include "mozilla/StaticPrefs_content.h"
19#include "mozilla/StaticPrefs_dom.h"
20#include "mozilla/StaticPrefs_network.h"
21#include "mozilla/StoragePrincipalHelper.h"
22#include "mozilla/dom/ReferrerInfo.h"
23#include "mozilla/dom/RequestBinding.h"
24#include "mozilla/dom/nsHTTPSOnlyUtils.h"
25#include "mozilla/glean/NetwerkProtocolHttpMetrics.h"
26#include "nsAsyncRedirectVerifyHelper.h"
27#include "nsCharSeparatedTokenizer.h"
28#include "nsClassHashtable.h"
29#include "nsComponentManagerUtils.h"
30#include "nsContentUtils.h"
31#include "nsError.h"
32#include "nsHashKeys.h"
33#include "nsHttpChannel.h"
34#include "nsIAsyncVerifyRedirectCallback.h"
35#include "nsICORSPreflightCache.h"
36#include "nsIChannel.h"
37#include "nsIChannelEventSink.h"
38#include "nsIConsoleService.h"
39#include "nsICorsPreflightCallback.h"
40#include "nsIDNSRecord.h"
41#include "nsIDNSService.h"
42#include "nsIHttpChannel.h"
43#include "nsIHttpChannelInternal.h"
44#include "nsIHttpHeaderVisitor.h"
45#include "nsIInterfaceRequestorUtils.h"
46#include "nsILoadContext.h"
47#include "nsILoadGroup.h"
48#include "nsINetworkInterceptController.h"
49#include "nsIScriptError.h"
50#include "nsISupportsImpl.h"
51#include "nsIThreadRetargetableStreamListener.h"
52#include "nsMimeTypes.h"
53#include "nsNetUtil.h"
54#include "nsQueryObject.h"
55#include "nsServiceManagerUtils.h"
56#include "nsStreamUtils.h"
57#include "nsString.h"
58#include "nsStringStream.h"
59#include "nsWhitespaceTokenizer.h"
60
61using namespace mozilla;
62using namespace mozilla::net;
63
64struct CORSCacheEntry;
65
66#define PREFLIGHT_CACHE_SIZE100 100
67// 5 seconds is chosen to be compatible with Chromium.
68#define PREFLIGHT_DEFAULT_EXPIRY_SECONDS5 5
69
70static inline nsAutoString GetStatusCodeAsString(nsIHttpChannel* aHttp) {
71 nsAutoString result;
72 uint32_t code;
73 if (NS_SUCCEEDED(aHttp->GetResponseStatus(&code))((bool)(__builtin_expect(!!(!NS_FAILED_impl(aHttp->GetResponseStatus
(&code))), 1)))
) {
74 result.AppendInt(code);
75 }
76 return result;
77}
78
79static void LogBlockedRequest(nsIRequest* aRequest, const char* aProperty,
80 const char16_t* aParam, uint32_t aBlockingReason,
81 nsIHttpChannel* aCreatingChannel,
82 bool aIsWarning = false) {
83 nsresult rv = NS_OK;
84
85 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
86
87 if (!aIsWarning) {
88 NS_SetRequestBlockingReason(channel, aBlockingReason);
89 }
90
91 nsCOMPtr<nsIURI> aUri;
92 channel->GetURI(getter_AddRefs(aUri));
93 nsAutoCString spec;
94 if (aUri) {
95 spec = aUri->GetSpecOrDefault();
96 }
97
98 // Generate the error message
99 nsAutoString blockedMessage;
100 AutoTArray<nsString, 2> params;
101 CopyUTF8toUTF16(spec, *params.AppendElement());
102 if (aParam) {
103 params.AppendElement(aParam);
104 }
105 NS_ConvertUTF8toUTF16 specUTF16(spec);
106 rv = nsContentUtils::FormatLocalizedString(
107 PropertiesFile::SECURITY_PROPERTIES, aProperty, params, blockedMessage);
108
109 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
110 NS_WARNING("Failed to log blocked cross-site request (no formalizedStr")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to log blocked cross-site request (no formalizedStr"
, nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 110)
;
111 return;
112 }
113
114 nsAutoString msg(blockedMessage.get());
115 nsDependentCString category(aProperty);
116
117 if (XRE_IsParentProcess()) {
118 if (aCreatingChannel) {
119 rv = aCreatingChannel->LogBlockedCORSRequest(msg, category, aIsWarning);
120 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
121 return;
122 }
123 }
124 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Failed to log blocked cross-site request to web console from "
"parent->child, falling back to browser console", nullptr
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 126)
125 "Failed to log blocked cross-site request to web console from "NS_DebugBreak(NS_DEBUG_WARNING, "Failed to log blocked cross-site request to web console from "
"parent->child, falling back to browser console", nullptr
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 126)
126 "parent->child, falling back to browser console")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to log blocked cross-site request to web console from "
"parent->child, falling back to browser console", nullptr
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 126)
;
127 }
128
129 bool privateBrowsing = false;
130 if (aRequest) {
131 nsCOMPtr<nsILoadGroup> loadGroup;
132 rv = aRequest->GetLoadGroup(getter_AddRefs(loadGroup));
133 NS_ENSURE_SUCCESS_VOID(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_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 133); return; } } while (false)
;
134 privateBrowsing = nsContentUtils::IsInPrivateBrowsing(loadGroup);
135 }
136
137 bool fromChromeContext = false;
138 if (channel) {
139 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
140 fromChromeContext = loadInfo->TriggeringPrincipal()->IsSystemPrincipal();
141 }
142
143 // we are passing aProperty as the category so we can link to the
144 // appropriate MDN docs depending on the specific error.
145 uint64_t innerWindowID = nsContentUtils::GetInnerWindowID(aRequest);
146 // The |innerWindowID| could be 0 if this request is created from script.
147 // We can always try top level content window id in this case,
148 // since the window id can lead to current top level window's web console.
149 if (!innerWindowID) {
150 if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest)) {
151 (void)httpChannel->GetTopLevelContentWindowId(&innerWindowID);
152 }
153 }
154 nsCORSListenerProxy::LogBlockedCORSRequest(innerWindowID, privateBrowsing,
155 fromChromeContext, msg, category,
156 aIsWarning);
157}
158
159//////////////////////////////////////////////////////////////////////////
160// Preflight cache
161
162class nsPreflightCache : public nsICORSPreflightCache {
163 public:
164 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
165 NS_DECL_NSICORSPREFLIGHTCACHEvirtual nsresult GetEntries(nsIPrincipal *principal, nsTArray
<RefPtr<nsICORSPreflightCacheEntry>>& _retval
) override; virtual nsresult ClearEntry(nsICORSPreflightCacheEntry
*entry) override;
166
167 struct TokenTime {
168 nsCString token;
169 TimeStamp expirationTime;
170 };
171
172 already_AddRefed<CORSCacheEntry> GetEntry(
173 nsIURI* aURI, nsIPrincipal* aPrincipal, bool aWithCredentials,
174 const OriginAttributes& aOriginAttributes, bool aCreate);
175 void RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal,
176 const OriginAttributes& aOriginAttributes);
177 void PurgePrivateBrowsingEntries();
178
179 void Clear();
180
181 protected:
182 virtual ~nsPreflightCache() { Clear(); }
183
184 private:
185 nsRefPtrHashtable<nsCStringHashKey, CORSCacheEntry> mTable;
186 LinkedList<CORSCacheEntry> mList;
187};
188
189struct CORSCacheEntry : public LinkedListElement<CORSCacheEntry>,
190 public nsICORSPreflightCacheEntry {
191 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
192 NS_DECL_NSICORSPREFLIGHTCACHEENTRYvirtual nsresult GetKey(nsACString& aKey) override; virtual
nsresult GetURI(nsIURI **aURI) override; virtual nsresult GetOriginAttributes
(JSContext* cx, JS::MutableHandle<JS::Value> aOriginAttributes
) override; virtual const mozilla::OriginAttributes & OriginAttributesRef
(void) override; virtual nsresult GetPrincipal(nsIPrincipal *
*aPrincipal) override; virtual nsresult GetPrivateBrowsing(bool
*aPrivateBrowsing) override; virtual nsresult GetWithCredentials
(bool *aWithCredentials) override;
193 explicit CORSCacheEntry(nsIURI* aUri,
194 const OriginAttributes& aOriginAttributes,
195 nsIPrincipal* aPrincipal, bool withCredentials,
196 nsCString& aKey)
197 : mURI(aUri),
198 mOA(aOriginAttributes),
199 mPrincipal(aPrincipal),
200 mWithCredentials(withCredentials),
201 mKey(aKey) {}
202
203 void PurgeExpired(TimeStamp now);
204 bool CheckRequest(const nsCString& aMethod,
205 const nsTArray<nsCString>& aHeaders);
206
207 nsCOMPtr<nsIURI> mURI;
208 const OriginAttributes mOA;
209 nsCOMPtr<nsIPrincipal> mPrincipal;
210 bool mWithCredentials;
211 nsCString mKey; // serialized key
212 const TimeStamp mCreationTime{TimeStamp::NowLoRes()};
213 bool mDoomed{false};
214 bool mIsProxyUsed{false};
215
216 nsTArray<nsPreflightCache::TokenTime> mMethods;
217 nsTArray<nsPreflightCache::TokenTime> mHeaders;
218
219 private:
220 virtual ~CORSCacheEntry() = default;
221
222 bool CheckDNSCache();
223};
224
225NS_IMPL_ISUPPORTS(nsPreflightCache, nsICORSPreflightCache)MozExternalRefCountType nsPreflightCache::AddRef(void) { static_assert
(!std::is_destructible_v<nsPreflightCache>, "Reference-counted class "
"nsPreflightCache" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 225); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 225
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsPreflightCache" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsPreflightCache" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsPreflightCache\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 225); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPreflightCache\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 225); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsPreflightCache" " not thread-safe"); nsrefcnt count = ++mRefCnt
; NS_LogAddRef((this), (count), ("nsPreflightCache"), (uint32_t
)(sizeof(*this))); return count; } MozExternalRefCountType nsPreflightCache
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 225); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 225
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsPreflightCache" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsPreflightCache" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsPreflightCache\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 225); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPreflightCache\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 225); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsPreflightCache" " not thread-safe"); const char* const nametmp
= "nsPreflightCache"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult nsPreflightCache
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 225); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsPreflightCache, nsICORSPreflightCache>
, int32_t( reinterpret_cast<char*>(static_cast<nsICORSPreflightCache
*>((nsPreflightCache*)0x1000)) - reinterpret_cast<char*
>((nsPreflightCache*)0x1000))}, {&mozilla::detail::kImplementedIID
<nsPreflightCache, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsICORSPreflightCache*>((nsPreflightCache*)0x1000))) - reinterpret_cast
<char*>((nsPreflightCache*)0x1000))}, { nullptr, 0 } } ;
static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
226
227NS_IMETHODIMPnsresult
228nsPreflightCache::GetEntries(
229 nsIPrincipal* aPrincipal,
230 nsTArray<RefPtr<nsICORSPreflightCacheEntry>>& aEntries) {
231 for (auto iter = mTable.Iter(); !iter.Done(); iter.Next()) {
232 RefPtr<nsIPrincipal> iterPrincipal;
233 iter.Data()->GetPrincipal(getter_AddRefs(iterPrincipal));
234 if (iterPrincipal->Equals(aPrincipal)) {
235 auto* entry = iter.UserData();
236 aEntries.AppendElement(entry);
237 }
238 }
239 return NS_OK;
240}
241
242NS_IMETHODIMPnsresult
243nsPreflightCache::ClearEntry(nsICORSPreflightCacheEntry* entry) {
244 nsCOMPtr<nsIURI> uri;
245 nsresult rv = entry->GetURI(getter_AddRefs(uri));
246 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 246); return rv; } } while (false)
;
247
248 nsCOMPtr<nsIPrincipal> principal;
249 rv = entry->GetPrincipal(getter_AddRefs(principal));
250 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 250); return rv; } } while (false)
;
251
252 const OriginAttributes oa = entry->OriginAttributesRef();
253
254 RemoveEntries(uri, principal, oa);
255 return NS_OK;
256}
257
258// Will be initialized in EnsurePreflightCache.
259static StaticRefPtr<nsPreflightCache> sPreflightCache;
260
261static bool EnsurePreflightCache() {
262 if (sPreflightCache) return true;
263
264 RefPtr<nsPreflightCache> newCache(new nsPreflightCache());
265 sPreflightCache = newCache;
266 return true;
267}
268
269void nsPreflightCache::PurgePrivateBrowsingEntries() {
270 for (auto iter = mTable.Iter(); !iter.Done(); iter.Next()) {
271 auto* entry = iter.UserData();
272 if (entry->mOA.IsPrivateBrowsing()) {
273 // last private browsing window closed, remove preflight cache entries
274 entry->removeFrom(sPreflightCache->mList);
275 iter.Remove();
276 }
277 }
278}
279
280NS_IMPL_ISUPPORTS(CORSCacheEntry, nsICORSPreflightCacheEntry)MozExternalRefCountType CORSCacheEntry::AddRef(void) { static_assert
(!std::is_destructible_v<CORSCacheEntry>, "Reference-counted class "
"CORSCacheEntry" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 280); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 280
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CORSCacheEntry" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("CORSCacheEntry" != nullptr)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"CORSCacheEntry\" != nullptr"
" (" "Must specify a name" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 280); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CORSCacheEntry\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 280); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("CORSCacheEntry" " not thread-safe"); nsrefcnt count = ++mRefCnt
; NS_LogAddRef((this), (count), ("CORSCacheEntry"), (uint32_t
)(sizeof(*this))); return count; } MozExternalRefCountType CORSCacheEntry
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 280); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 280
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CORSCacheEntry" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("CORSCacheEntry" != nullptr)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"CORSCacheEntry\" != nullptr"
" (" "Must specify a name" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 280); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CORSCacheEntry\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 280); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("CORSCacheEntry" " not thread-safe"); const char* const nametmp
= "CORSCacheEntry"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult CORSCacheEntry::
QueryInterface(const nsIID& aIID, void** aInstancePtr) { do
{ if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 280); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<CORSCacheEntry, nsICORSPreflightCacheEntry
>, int32_t( reinterpret_cast<char*>(static_cast<nsICORSPreflightCacheEntry
*>((CORSCacheEntry*)0x1000)) - reinterpret_cast<char*>
((CORSCacheEntry*)0x1000))}, {&mozilla::detail::kImplementedIID
<CORSCacheEntry, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsICORSPreflightCacheEntry*>((CORSCacheEntry*)0x1000))) - reinterpret_cast
<char*>((CORSCacheEntry*)0x1000))}, { nullptr, 0 } } ; static_assert
(std::size(table) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
281
282NS_IMETHODIMPnsresult
283CORSCacheEntry::GetKey(nsACString& aKey) {
284 aKey = mKey;
285 return NS_OK;
286}
287
288NS_IMETHODIMPnsresult
289CORSCacheEntry::GetURI(nsIURI** aURI) {
290 *aURI = do_AddRef(mURI).take();
291 return NS_OK;
292}
293
294NS_IMETHODIMPnsresult
295CORSCacheEntry::GetOriginAttributes(JSContext* aCx,
296 JS::MutableHandle<JS::Value> aVal) {
297 if (NS_WARN_IF(!ToJSValue(aCx, mOA, aVal))NS_warn_if_impl(!ToJSValue(aCx, mOA, aVal), "!ToJSValue(aCx, mOA, aVal)"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 297)
) {
298 return NS_ERROR_FAILURE;
299 }
300 return NS_OK;
301}
302
303const OriginAttributes& CORSCacheEntry::OriginAttributesRef() { return mOA; }
304
305NS_IMETHODIMPnsresult
306CORSCacheEntry::GetPrincipal(nsIPrincipal** aPrincipal) {
307 *aPrincipal = do_AddRef(mPrincipal).take();
308 return NS_OK;
309}
310
311NS_IMETHODIMPnsresult
312CORSCacheEntry::GetPrivateBrowsing(bool* aPrivateBrowsing) {
313 *aPrivateBrowsing = mOA.IsPrivateBrowsing();
314 return NS_OK;
315}
316
317NS_IMETHODIMPnsresult
318CORSCacheEntry::GetWithCredentials(bool* aWithCredentials) {
319 *aWithCredentials = mWithCredentials;
320 return NS_OK;
321}
322
323void CORSCacheEntry::PurgeExpired(TimeStamp now) {
324 for (uint32_t i = 0, len = mMethods.Length(); i < len; ++i) {
325 if (now >= mMethods[i].expirationTime) {
326 mMethods.UnorderedRemoveElementAt(i);
327 --i; // Examine the element again, if necessary.
328 --len;
329 }
330 }
331 for (uint32_t i = 0, len = mHeaders.Length(); i < len; ++i) {
332 if (now >= mHeaders[i].expirationTime) {
333 mHeaders.UnorderedRemoveElementAt(i);
334 --i; // Examine the element again, if necessary.
335 --len;
336 }
337 }
338}
339
340bool CORSCacheEntry::CheckDNSCache() {
341 // When proxy is used, the DNS lookup is done by proxy, so we skip this check.
342 if (mIsProxyUsed) {
343 return true;
344 }
345
346 nsCOMPtr<nsIDNSService> dns;
347 dns = mozilla::components::DNS::Service();
348 if (!dns) {
349 return false;
350 }
351
352 nsAutoCString host;
353 if (NS_FAILED(mURI->GetAsciiHost(host))((bool)(__builtin_expect(!!(NS_FAILED_impl(mURI->GetAsciiHost
(host))), 0)))
) {
354 return false;
355 }
356
357 // Happy Eyeballs resolves each address family separately, so the host may be
358 // cached only as per-family (AF_INET/AF_INET6) records with no AF_UNSPEC
359 // entry. Check each family: the cached preflight is still valid as long as a
360 // matching DNS entry exists and none was updated after the preflight was
361 // created.
362 const nsIDNSService::DNSFlags familyFlags[] = {
363 nsIDNSService::RESOLVE_DEFAULT_FLAGS, // AF_UNSPEC
364 nsIDNSService::RESOLVE_DISABLE_IPV6, // AF_INET
365 nsIDNSService::RESOLVE_DISABLE_IPV4, // AF_INET6
366 };
367
368 bool foundRecord = false;
369 for (const auto& flags : familyFlags) {
370 nsCOMPtr<nsIDNSRecord> record;
371 nsresult rv =
372 dns->ResolveNative(host, nsIDNSService::RESOLVE_OFFLINE | flags, mOA,
373 getter_AddRefs(record));
374 nsCOMPtr<nsIDNSAddrRecord> addrRec = do_QueryInterface(record);
375 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !addrRec) {
376 continue;
377 }
378
379 foundRecord = true;
380 TimeStamp lastUpdate;
381 (void)addrRec->GetLastUpdate(&lastUpdate);
382 if (lastUpdate > mCreationTime) {
383 // The DNS result was re-resolved after the preflight was cached.
384 return false;
385 }
386 }
387
388 return foundRecord;
389}
390
391bool CORSCacheEntry::CheckRequest(const nsCString& aMethod,
392 const nsTArray<nsCString>& aHeaders) {
393 PurgeExpired(TimeStamp::NowLoRes());
394
395 if (!CheckDNSCache()) {
396 mMethods.Clear();
397 mHeaders.Clear();
398 mDoomed = true;
399 return false;
400 }
401
402 if (!aMethod.EqualsLiteral("GET") && !aMethod.EqualsLiteral("POST")) {
403 struct CheckToken {
404 bool Equals(const nsPreflightCache::TokenTime& e,
405 const nsCString& method) const {
406 return e.token.Equals(method);
407 }
408 };
409
410 if (!mMethods.Contains(aMethod, CheckToken())) {
411 return false;
412 }
413 }
414
415 struct CheckHeaderToken {
416 bool Equals(const nsPreflightCache::TokenTime& e,
417 const nsCString& header) const {
418 return e.token.Equals(header, nsCaseInsensitiveCStringComparator);
419 }
420 } checker;
421 for (uint32_t i = 0; i < aHeaders.Length(); ++i) {
422 if (!mHeaders.Contains(aHeaders[i], checker)) {
423 return false;
424 }
425 }
426
427 return true;
428}
429
430already_AddRefed<CORSCacheEntry> nsPreflightCache::GetEntry(
431 nsIURI* aURI, nsIPrincipal* aPrincipal, bool aWithCredentials,
432 const OriginAttributes& aOriginAttributes, bool aCreate) {
433 nsAutoCString key;
434 if (NS_FAILED(aPrincipal->GetPrefLightCacheKey(aURI, aWithCredentials,((bool)(__builtin_expect(!!(NS_FAILED_impl(aPrincipal->GetPrefLightCacheKey
(aURI, aWithCredentials, aOriginAttributes, key))), 0)))
435 aOriginAttributes, key))((bool)(__builtin_expect(!!(NS_FAILED_impl(aPrincipal->GetPrefLightCacheKey
(aURI, aWithCredentials, aOriginAttributes, key))), 0)))
) {
436 NS_WARNING("Invalid cache key!")NS_DebugBreak(NS_DEBUG_WARNING, "Invalid cache key!", nullptr
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 436)
;
437 return nullptr;
438 }
439
440 RefPtr<CORSCacheEntry> existingEntry = nullptr;
441 if ((existingEntry = mTable.Get(key))) {
442 if (existingEntry->mDoomed) {
443 existingEntry->removeFrom(mList);
444 mTable.Remove(key);
445 } else {
446 // Entry already existed so just return it. Also update the LRU list.
447 // Move to the head of the list.
448 existingEntry->removeFrom(mList);
449 mList.insertFront(existingEntry);
450 return existingEntry.forget();
451 }
452 }
453
454 if (!aCreate) {
455 return nullptr;
456 }
457
458 // This is a new entry, allocate and insert into the table now so that any
459 // failures don't cause items to be removed from a full cache.
460 RefPtr<CORSCacheEntry> newEntry = new CORSCacheEntry(
461 aURI, aOriginAttributes, aPrincipal, aWithCredentials, key);
462
463 NS_ASSERTION(mTable.Count() <= PREFLIGHT_CACHE_SIZE,do { if (!(mTable.Count() <= 100)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Something is borked, too many entries in the cache!", "mTable.Count() <= PREFLIGHT_CACHE_SIZE"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 464); MOZ_PretendNoReturn(); } } while (0)
464 "Something is borked, too many entries in the cache!")do { if (!(mTable.Count() <= 100)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Something is borked, too many entries in the cache!", "mTable.Count() <= PREFLIGHT_CACHE_SIZE"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 464); MOZ_PretendNoReturn(); } } while (0)
;
465
466 // Now enforce the max count.
467 if (mTable.Count() == PREFLIGHT_CACHE_SIZE100) {
468 // Try to kick out all the expired entries.
469 TimeStamp now = TimeStamp::NowLoRes();
470 for (auto iter = mTable.Iter(); !iter.Done(); iter.Next()) {
471 auto* entry = iter.UserData();
472 entry->PurgeExpired(now);
473
474 if (entry->mHeaders.IsEmpty() && entry->mMethods.IsEmpty()) {
475 // Expired, remove from the list as well as the hash table.
476 entry->removeFrom(sPreflightCache->mList);
477 iter.Remove();
478 }
479 }
480
481 // If that didn't remove anything then kick out the least recently used
482 // entry.
483 if (mTable.Count() == PREFLIGHT_CACHE_SIZE100) {
484 CORSCacheEntry* lruEntry = static_cast<CORSCacheEntry*>(mList.popLast());
485 MOZ_ASSERT(lruEntry)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lruEntry)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lruEntry))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("lruEntry", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 485); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lruEntry" ")"
); do { MOZ_CrashSequence(__null, 485); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
486
487 // This will delete 'lruEntry'.
488 nsAutoCString lruKey;
489 lruEntry->GetKey(lruKey);
490 mTable.Remove(lruKey);
491
492 NS_ASSERTION(mTable.Count() == PREFLIGHT_CACHE_SIZE - 1,do { if (!(mTable.Count() == 100 - 1)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Somehow tried to remove an entry that was never added!", "mTable.Count() == PREFLIGHT_CACHE_SIZE - 1"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 493); MOZ_PretendNoReturn(); } } while (0)
493 "Somehow tried to remove an entry that was never added!")do { if (!(mTable.Count() == 100 - 1)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Somehow tried to remove an entry that was never added!", "mTable.Count() == PREFLIGHT_CACHE_SIZE - 1"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 493); MOZ_PretendNoReturn(); } } while (0)
;
494 }
495 }
496 CORSCacheEntry* newEntryWeak = newEntry.get();
497 mTable.InsertOrUpdate(key, newEntry);
498 mList.insertFront(newEntryWeak);
499 return newEntry.forget();
500}
501
502void nsPreflightCache::RemoveEntries(
503 nsIURI* aURI, nsIPrincipal* aPrincipal,
504 const OriginAttributes& aOriginAttributes) {
505 RefPtr<CORSCacheEntry> entry;
506 nsCString key;
507 if (NS_SUCCEEDED(aPrincipal->GetPrefLightCacheKey(aURI, true,((bool)(__builtin_expect(!!(!NS_FAILED_impl(aPrincipal->GetPrefLightCacheKey
(aURI, true, aOriginAttributes, key))), 1)))
508 aOriginAttributes, key))((bool)(__builtin_expect(!!(!NS_FAILED_impl(aPrincipal->GetPrefLightCacheKey
(aURI, true, aOriginAttributes, key))), 1)))
) {
509 if ((entry = mTable.Get(key))) {
510 entry->removeFrom(mList);
511 mTable.Remove(key);
512 }
513 }
514
515 if (NS_SUCCEEDED(aPrincipal->GetPrefLightCacheKey(aURI, false,((bool)(__builtin_expect(!!(!NS_FAILED_impl(aPrincipal->GetPrefLightCacheKey
(aURI, false, aOriginAttributes, key))), 1)))
516 aOriginAttributes, key))((bool)(__builtin_expect(!!(!NS_FAILED_impl(aPrincipal->GetPrefLightCacheKey
(aURI, false, aOriginAttributes, key))), 1)))
) {
517 if ((entry = mTable.Get(key))) {
518 entry->removeFrom(mList);
519 mTable.Remove(key);
520 }
521 }
522}
523
524void nsPreflightCache::Clear() {
525 mList.clear();
526 mTable.Clear();
527}
528
529//////////////////////////////////////////////////////////////////////////
530// nsCORSListenerProxy
531
532NS_IMPL_ISUPPORTS(nsCORSListenerProxy, nsIStreamListener, nsIRequestObserver,MozExternalRefCountType nsCORSListenerProxy::AddRef(void) { static_assert
(!std::is_destructible_v<nsCORSListenerProxy>, "Reference-counted class "
"nsCORSListenerProxy" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 534
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSListenerProxy" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsCORSListenerProxy" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsCORSListenerProxy\" != nullptr" " (" "Must specify a name"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSListenerProxy\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 534); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsCORSListenerProxy" " not thread-safe"); nsrefcnt count = ++
mRefCnt; NS_LogAddRef((this), (count), ("nsCORSListenerProxy"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsCORSListenerProxy::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 534
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSListenerProxy" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsCORSListenerProxy" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsCORSListenerProxy\" != nullptr" " (" "Must specify a name"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSListenerProxy\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 534); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsCORSListenerProxy" " not thread-safe"); const char* const
nametmp = "nsCORSListenerProxy"; nsrefcnt count = --mRefCnt;
NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
nsCORSListenerProxy::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(5 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsCORSListenerProxy, nsIStreamListener>
, int32_t( reinterpret_cast<char*>(static_cast<nsIStreamListener
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIRequestObserver>
, int32_t( reinterpret_cast<char*>(static_cast<nsIRequestObserver
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIChannelEventSink>
, int32_t( reinterpret_cast<char*>(static_cast<nsIChannelEventSink
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIInterfaceRequestor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIInterfaceRequestor
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIThreadRetargetableStreamListener
>, int32_t( reinterpret_cast<char*>(static_cast<nsIThreadRetargetableStreamListener
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIStreamListener*>((nsCORSListenerProxy*
)0x1000))) - reinterpret_cast<char*>((nsCORSListenerProxy
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
533 nsIChannelEventSink, nsIInterfaceRequestor,MozExternalRefCountType nsCORSListenerProxy::AddRef(void) { static_assert
(!std::is_destructible_v<nsCORSListenerProxy>, "Reference-counted class "
"nsCORSListenerProxy" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 534
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSListenerProxy" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsCORSListenerProxy" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsCORSListenerProxy\" != nullptr" " (" "Must specify a name"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSListenerProxy\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 534); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsCORSListenerProxy" " not thread-safe"); nsrefcnt count = ++
mRefCnt; NS_LogAddRef((this), (count), ("nsCORSListenerProxy"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsCORSListenerProxy::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 534
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSListenerProxy" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsCORSListenerProxy" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsCORSListenerProxy\" != nullptr" " (" "Must specify a name"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSListenerProxy\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 534); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsCORSListenerProxy" " not thread-safe"); const char* const
nametmp = "nsCORSListenerProxy"; nsrefcnt count = --mRefCnt;
NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
nsCORSListenerProxy::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(5 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsCORSListenerProxy, nsIStreamListener>
, int32_t( reinterpret_cast<char*>(static_cast<nsIStreamListener
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIRequestObserver>
, int32_t( reinterpret_cast<char*>(static_cast<nsIRequestObserver
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIChannelEventSink>
, int32_t( reinterpret_cast<char*>(static_cast<nsIChannelEventSink
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIInterfaceRequestor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIInterfaceRequestor
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIThreadRetargetableStreamListener
>, int32_t( reinterpret_cast<char*>(static_cast<nsIThreadRetargetableStreamListener
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIStreamListener*>((nsCORSListenerProxy*
)0x1000))) - reinterpret_cast<char*>((nsCORSListenerProxy
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
534 nsIThreadRetargetableStreamListener)MozExternalRefCountType nsCORSListenerProxy::AddRef(void) { static_assert
(!std::is_destructible_v<nsCORSListenerProxy>, "Reference-counted class "
"nsCORSListenerProxy" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 534
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSListenerProxy" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsCORSListenerProxy" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsCORSListenerProxy\" != nullptr" " (" "Must specify a name"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSListenerProxy\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 534); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsCORSListenerProxy" " not thread-safe"); nsrefcnt count = ++
mRefCnt; NS_LogAddRef((this), (count), ("nsCORSListenerProxy"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsCORSListenerProxy::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 534
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSListenerProxy" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsCORSListenerProxy" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsCORSListenerProxy\" != nullptr" " (" "Must specify a name"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSListenerProxy\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 534); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsCORSListenerProxy" " not thread-safe"); const char* const
nametmp = "nsCORSListenerProxy"; nsrefcnt count = --mRefCnt;
NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
nsCORSListenerProxy::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 534); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(5 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsCORSListenerProxy, nsIStreamListener>
, int32_t( reinterpret_cast<char*>(static_cast<nsIStreamListener
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIRequestObserver>
, int32_t( reinterpret_cast<char*>(static_cast<nsIRequestObserver
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIChannelEventSink>
, int32_t( reinterpret_cast<char*>(static_cast<nsIChannelEventSink
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIInterfaceRequestor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIInterfaceRequestor
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsIThreadRetargetableStreamListener
>, int32_t( reinterpret_cast<char*>(static_cast<nsIThreadRetargetableStreamListener
*>((nsCORSListenerProxy*)0x1000)) - reinterpret_cast<char
*>((nsCORSListenerProxy*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsCORSListenerProxy, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIStreamListener*>((nsCORSListenerProxy*
)0x1000))) - reinterpret_cast<char*>((nsCORSListenerProxy
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
535
536/* static */
537already_AddRefed<nsICORSPreflightCache>
538nsCORSListenerProxy::GetCORSPreflightSingleton() {
539 NS_ASSERTION(!IsNeckoChild(), "not a parent process")do { if (!(!IsNeckoChild())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "not a parent process", "!IsNeckoChild()", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 539); MOZ_PretendNoReturn(); } } while (0)
;
540
541 if (!EnsurePreflightCache()) {
542 NS_ASSERTION(false, "Failed to get the preflightCache")do { if (!(false)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to get the preflightCache"
, "false", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 542); MOZ_PretendNoReturn(); } } while (0)
;
543 }
544 return do_AddRef(sPreflightCache);
545}
546
547/* static */
548void nsCORSListenerProxy::Shutdown() { sPreflightCache = nullptr; }
549
550/* static */
551void nsCORSListenerProxy::ClearCache() {
552 if (!sPreflightCache) {
553 return;
554 }
555 sPreflightCache->Clear();
556}
557
558// static
559void nsCORSListenerProxy::ClearPrivateBrowsingCache() {
560 if (!sPreflightCache) {
561 return;
562 }
563 sPreflightCache->PurgePrivateBrowsingEntries();
564}
565
566// Usually, when using an expanded principal, there's no particularly good
567// origin to do the request with. However if the expanded principal only wraps
568// one principal, we can use that one instead.
569//
570// This is needed so that DevTools can still do CORS-enabled requests (since
571// DevTools uses a triggering principal expanding the node principal to bypass
572// CSP checks, see Element::CreateDevToolsPrincipal(), bug 1604562, and bug
573// 1391994).
574static nsIPrincipal* GetOriginHeaderPrincipal(nsIPrincipal* aPrincipal) {
575 while (aPrincipal && aPrincipal->GetIsExpandedPrincipal()) {
576 auto* ep = BasePrincipal::Cast(aPrincipal)->As<ExpandedPrincipal>();
577 if (ep->AllowList().Length() != 1) {
578 break;
579 }
580 aPrincipal = ep->AllowList()[0];
581 }
582 return aPrincipal;
583}
584
585nsCORSListenerProxy::nsCORSListenerProxy(nsIStreamListener* aOuter,
586 nsIPrincipal* aRequestingPrincipal,
587 bool aWithCredentials)
588 : mOuterListener(aOuter),
589 mRequestingPrincipal(aRequestingPrincipal),
590 mOriginHeaderPrincipal(GetOriginHeaderPrincipal(aRequestingPrincipal)),
591 mWithCredentials(aWithCredentials),
592 mRequestApproved(false),
593 mHasBeenCrossSite(false),
594#ifdef DEBUG1
595 mInited(false),
596#endif
597 mMutex("nsCORSListenerProxy") {
598}
599
600nsresult nsCORSListenerProxy::Init(nsIChannel* aChannel,
601 DataURIHandling aAllowDataURI) {
602 aChannel->GetNotificationCallbacks(
603 getter_AddRefs(mOuterNotificationCallbacks));
604 aChannel->SetNotificationCallbacks(this);
605
606 nsresult rv =
607 UpdateChannel(aChannel, aAllowDataURI, UpdateType::Default, false);
608 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
609 {
610 MutexAutoLock lock(mMutex);
611 mOuterListener = nullptr;
612 }
613 mRequestingPrincipal = nullptr;
614 mOriginHeaderPrincipal = nullptr;
615 mOuterNotificationCallbacks = nullptr;
616 mHttpChannel = nullptr;
617 }
618#ifdef DEBUG1
619 mInited = true;
620#endif
621 return rv;
622}
623
624NS_IMETHODIMPnsresult
625nsCORSListenerProxy::OnStartRequest(nsIRequest* aRequest) {
626 MOZ_ASSERT(mInited, "nsCORSListenerProxy has not been initialized properly")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mInited)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mInited))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mInited" " (" "nsCORSListenerProxy has not been initialized properly"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 626); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mInited" ") ("
"nsCORSListenerProxy has not been initialized properly" ")")
; do { MOZ_CrashSequence(__null, 626); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
627 nsresult rv = CheckRequestApproved(aRequest);
628 mRequestApproved = NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
629 if (!mRequestApproved) {
630 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
631 if (channel) {
632 nsCOMPtr<nsIURI> uri;
633 NS_GetFinalChannelURI(channel, getter_AddRefs(uri));
634 if (uri) {
635 OriginAttributes attrs;
636 StoragePrincipalHelper::GetOriginAttributesForNetworkState(channel,
637 attrs);
638
639 if (sPreflightCache) {
640 // OK to use mRequestingPrincipal since preflights never get
641 // redirected.
642 sPreflightCache->RemoveEntries(uri, mRequestingPrincipal, attrs);
643 } else {
644 nsCOMPtr<nsIHttpChannelChild> httpChannelChild =
645 do_QueryInterface(channel);
646 if (httpChannelChild) {
647 rv = httpChannelChild->RemoveCorsPreflightCacheEntry(
648 uri, mRequestingPrincipal, attrs);
649 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
650 // Only warn here to ensure we fall through the request Cancel()
651 // and outer listener OnStartRequest() calls.
652 NS_WARNING("Failed to remove CORS preflight cache entry!")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to remove CORS preflight cache entry!"
, nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 652)
;
653 }
654 }
655 }
656 }
657 }
658
659 aRequest->Cancel(NS_ERROR_DOM_BAD_URI);
660 nsCOMPtr<nsIStreamListener> listener;
661 {
662 MutexAutoLock lock(mMutex);
663 listener = mOuterListener;
664 }
665 listener->OnStartRequest(aRequest);
666
667 // Reason for NS_ERROR_DOM_BAD_URI already logged in CheckRequestApproved()
668 return NS_ERROR_DOM_BAD_URI;
669 }
670
671 nsCOMPtr<nsIStreamListener> listener;
672 {
673 MutexAutoLock lock(mMutex);
674 listener = mOuterListener;
675 }
676 return listener->OnStartRequest(aRequest);
677}
678
679namespace {
680class CheckOriginHeader final : public nsIHttpHeaderVisitor {
681 public:
682 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
683
684 CheckOriginHeader() = default;
685
686 NS_IMETHODvirtual nsresult
687 VisitHeader(const nsACString& aHeader, const nsACString& aValue) override {
688 if (aHeader.EqualsLiteral("Access-Control-Allow-Origin")) {
689 mHeaderCount++;
690 }
691
692 if (mHeaderCount > 1) {
693 return NS_ERROR_DOM_BAD_URI;
694 }
695 return NS_OK;
696 }
697
698 private:
699 uint32_t mHeaderCount{0};
700
701 ~CheckOriginHeader() = default;
702};
703
704NS_IMPL_ISUPPORTS(CheckOriginHeader, nsIHttpHeaderVisitor)MozExternalRefCountType CheckOriginHeader::AddRef(void) { static_assert
(!std::is_destructible_v<CheckOriginHeader>, "Reference-counted class "
"CheckOriginHeader" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 704); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 704
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CheckOriginHeader" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("CheckOriginHeader" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"CheckOriginHeader\" != nullptr" " (" "Must specify a name"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 704); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CheckOriginHeader\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 704); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("CheckOriginHeader" " not thread-safe"); nsrefcnt count = ++
mRefCnt; NS_LogAddRef((this), (count), ("CheckOriginHeader"),
(uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
CheckOriginHeader::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 704); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 704
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("CheckOriginHeader" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("CheckOriginHeader" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"CheckOriginHeader\" != nullptr" " (" "Must specify a name"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 704); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"CheckOriginHeader\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 704); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("CheckOriginHeader" " not thread-safe"); const char* const nametmp
= "CheckOriginHeader"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult CheckOriginHeader
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 704); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<CheckOriginHeader, nsIHttpHeaderVisitor>
, int32_t( reinterpret_cast<char*>(static_cast<nsIHttpHeaderVisitor
*>((CheckOriginHeader*)0x1000)) - reinterpret_cast<char
*>((CheckOriginHeader*)0x1000))}, {&mozilla::detail::kImplementedIID
<CheckOriginHeader, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsIHttpHeaderVisitor*>((CheckOriginHeader*)0x1000))) - reinterpret_cast
<char*>((CheckOriginHeader*)0x1000))}, { nullptr, 0 } }
; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
705} // namespace
706
707nsresult nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest) {
708 // Check if this was actually a cross domain request
709 if (!mHasBeenCrossSite) {
710 return NS_OK;
711 }
712 nsCOMPtr<nsIHttpChannel> topChannel;
713 topChannel.swap(mHttpChannel);
714
715 if (StaticPrefs::content_cors_disable()) {
716 LogBlockedRequest(aRequest, "CORSDisabled", nullptr,
717 nsILoadInfo::BLOCKING_REASON_CORSDISABLED, topChannel);
718 return NS_ERROR_DOM_BAD_URI;
719 }
720
721 // Check if the request failed
722 nsresult status;
723 nsresult rv = aRequest->GetStatus(&status);
724 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
725 LogBlockedRequest(aRequest, "CORSDidNotSucceed2", nullptr,
726 nsILoadInfo::BLOCKING_REASON_CORSDIDNOTSUCCEED,
727 topChannel);
728 return rv;
729 }
730
731 if (NS_FAILED(status)((bool)(__builtin_expect(!!(NS_FAILED_impl(status)), 0)))) {
732 if (NS_BINDING_ABORTED != status) {
733 // Don't want to log mere cancellation as an error.
734 LogBlockedRequest(aRequest, "CORSDidNotSucceed2", nullptr,
735 nsILoadInfo::BLOCKING_REASON_CORSDIDNOTSUCCEED,
736 topChannel);
737 }
738 return status;
739 }
740
741 // Test that things worked on a HTTP level
742 nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
743 if (!http) {
744 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
745 nsCOMPtr<nsIURI> uri;
746 NS_GetFinalChannelURI(channel, getter_AddRefs(uri));
747 if (uri && uri->SchemeIs("moz-extension")) {
748 // moz-extension:-URLs do not support CORS, but can universally be read
749 // if an extension lists the resource in web_accessible_resources.
750 // Access will be checked in UpdateChannel.
751 return NS_OK;
752 }
753 LogBlockedRequest(aRequest, "CORSRequestNotHttp", nullptr,
754 nsILoadInfo::BLOCKING_REASON_CORSREQUESTNOTHTTP,
755 topChannel);
756 return NS_ERROR_DOM_BAD_URI;
757 }
758
759 nsCOMPtr<nsILoadInfo> loadInfo = http->LoadInfo();
760 if (loadInfo->GetServiceWorkerTaintingSynthesized()) {
761 // For synthesized responses, we don't need to perform any checks.
762 // Note: This would be unsafe if we ever changed our behavior to allow
763 // service workers to intercept CORS preflights.
764 return NS_OK;
765 }
766
767 // Check the Access-Control-Allow-Origin header
768 RefPtr<CheckOriginHeader> visitor = new CheckOriginHeader();
769 nsAutoCString allowedOriginHeader;
770
771 // check for duplicate headers
772 rv = http->VisitOriginalResponseHeaders(visitor);
773 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
774 LogBlockedRequest(
775 aRequest, "CORSMultipleAllowOriginNotAllowed", nullptr,
776 nsILoadInfo::BLOCKING_REASON_CORSMULTIPLEALLOWORIGINNOTALLOWED,
777 topChannel);
778 return rv;
779 }
780
781 rv = http->GetResponseHeader("Access-Control-Allow-Origin"_ns,
782 allowedOriginHeader);
783 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
784 auto statusCode = GetStatusCodeAsString(http);
785 LogBlockedRequest(aRequest, "CORSMissingAllowOrigin2", statusCode.get(),
786 nsILoadInfo::BLOCKING_REASON_CORSMISSINGALLOWORIGIN,
787 topChannel);
788 return rv;
789 }
790
791 // Bug 1210985 - Explicitly point out the error that the credential is
792 // not supported if the allowing origin is '*'. Note that this check
793 // has to be done before the condition
794 //
795 // >> if (mWithCredentials || !allowedOriginHeader.EqualsLiteral("*"))
796 //
797 // below since "if (A && B)" is included in "if (A || !B)".
798 //
799 if (mWithCredentials && allowedOriginHeader.EqualsLiteral("*")) {
800 LogBlockedRequest(aRequest, "CORSNotSupportingCredentials", nullptr,
801 nsILoadInfo::BLOCKING_REASON_CORSNOTSUPPORTINGCREDENTIALS,
802 topChannel);
803 return NS_ERROR_DOM_BAD_URI;
804 }
805
806 if (mWithCredentials || !allowedOriginHeader.EqualsLiteral("*")) {
807 MOZ_ASSERT(!mOriginHeaderPrincipal->GetIsExpandedPrincipal())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mOriginHeaderPrincipal->GetIsExpandedPrincipal()
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mOriginHeaderPrincipal->GetIsExpandedPrincipal()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mOriginHeaderPrincipal->GetIsExpandedPrincipal()", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 807); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mOriginHeaderPrincipal->GetIsExpandedPrincipal()"
")"); do { MOZ_CrashSequence(__null, 807); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
808 nsAutoCString origin;
809 mOriginHeaderPrincipal->GetWebExposedOriginSerialization(origin);
810
811 if (!allowedOriginHeader.Equals(origin)) {
812 LogBlockedRequest(
813 aRequest, "CORSAllowOriginNotMatchingOrigin",
814 NS_ConvertUTF8toUTF16(allowedOriginHeader).get(),
815 nsILoadInfo::BLOCKING_REASON_CORSALLOWORIGINNOTMATCHINGORIGIN,
816 topChannel);
817 return NS_ERROR_DOM_BAD_URI;
818 }
819 }
820
821 // Check Access-Control-Allow-Credentials header
822 if (mWithCredentials) {
823 nsAutoCString allowCredentialsHeader;
824 rv = http->GetResponseHeader("Access-Control-Allow-Credentials"_ns,
Value stored to 'rv' is never read
825 allowCredentialsHeader);
826
827 if (!allowCredentialsHeader.EqualsLiteral("true")) {
828 LogBlockedRequest(
829 aRequest, "CORSMissingAllowCredentials", nullptr,
830 nsILoadInfo::BLOCKING_REASON_CORSMISSINGALLOWCREDENTIALS, topChannel);
831 return NS_ERROR_DOM_BAD_URI;
832 }
833 }
834
835 return NS_OK;
836}
837
838NS_IMETHODIMPnsresult
839nsCORSListenerProxy::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
840 MOZ_ASSERT(mInited, "nsCORSListenerProxy has not been initialized properly")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mInited)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mInited))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mInited" " (" "nsCORSListenerProxy has not been initialized properly"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 840); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mInited" ") ("
"nsCORSListenerProxy has not been initialized properly" ")")
; do { MOZ_CrashSequence(__null, 840); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
841 nsCOMPtr<nsIStreamListener> listener;
842 {
843 MutexAutoLock lock(mMutex);
844 listener = std::move(mOuterListener);
845 }
846 nsresult rv = listener->OnStopRequest(aRequest, aStatusCode);
847 mOuterNotificationCallbacks = nullptr;
848 mHttpChannel = nullptr;
849 return rv;
850}
851
852NS_IMETHODIMPnsresult
853nsCORSListenerProxy::OnDataAvailable(nsIRequest* aRequest,
854 nsIInputStream* aInputStream,
855 uint64_t aOffset, uint32_t aCount) {
856 // NB: This can be called on any thread! But we're guaranteed that it is
857 // called between OnStartRequest and OnStopRequest, so we don't need to worry
858 // about races.
859
860 MOZ_ASSERT(mInited, "nsCORSListenerProxy has not been initialized properly")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mInited)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mInited))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mInited" " (" "nsCORSListenerProxy has not been initialized properly"
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mInited" ") ("
"nsCORSListenerProxy has not been initialized properly" ")")
; do { MOZ_CrashSequence(__null, 860); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
861 if (!mRequestApproved) {
862 // Reason for NS_ERROR_DOM_BAD_URI already logged in CheckRequestApproved()
863 return NS_ERROR_DOM_BAD_URI;
864 }
865 nsCOMPtr<nsIStreamListener> listener;
866 {
867 MutexAutoLock lock(mMutex);
868 listener = mOuterListener;
869 }
870 return listener->OnDataAvailable(aRequest, aInputStream, aOffset, aCount);
871}
872
873NS_IMETHODIMPnsresult
874nsCORSListenerProxy::OnDataFinished(nsresult aStatus) {
875 nsCOMPtr<nsIStreamListener> listener;
876 {
877 MutexAutoLock lock(mMutex);
878 listener = mOuterListener;
879 }
880 if (!listener) {
881 return NS_ERROR_FAILURE;
882 }
883 nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
884 do_QueryInterface(listener);
885 if (retargetableListener) {
886 return retargetableListener->OnDataFinished(aStatus);
887 }
888
889 return NS_OK;
890}
891
892void nsCORSListenerProxy::SetInterceptController(
893 nsINetworkInterceptController* aInterceptController) {
894 mInterceptController = aInterceptController;
895}
896
897NS_IMETHODIMPnsresult
898nsCORSListenerProxy::GetInterface(const nsIID& aIID, void** aResult) {
899 if (aIID.Equals(NS_GET_IID(nsIChannelEventSink)(nsIChannelEventSink::kIID))) {
900 *aResult = static_cast<nsIChannelEventSink*>(this);
901 NS_ADDREF_THIS()AddRef();
902
903 return NS_OK;
904 }
905
906 if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController)(nsINetworkInterceptController::kIID)) &&
907 mInterceptController) {
908 nsCOMPtr<nsINetworkInterceptController> copy(mInterceptController);
909 *aResult = copy.forget().take();
910
911 return NS_OK;
912 }
913
914 return mOuterNotificationCallbacks
915 ? mOuterNotificationCallbacks->GetInterface(aIID, aResult)
916 : NS_ERROR_NO_INTERFACE;
917}
918
919NS_IMETHODIMPnsresult
920nsCORSListenerProxy::AsyncOnChannelRedirect(
921 nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags,
922 nsIAsyncVerifyRedirectCallback* aCb) {
923 nsresult rv;
924 if (NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags) ||
925 NS_IsHSTSUpgradeRedirect(aOldChannel, aNewChannel, aFlags)) {
926 // Internal redirects still need to be updated in order to maintain
927 // the correct headers. We use DataURIHandling::Allow, since unallowed
928 // data URIs should have been blocked before we got to the internal
929 // redirect.
930 rv = UpdateChannel(aNewChannel, DataURIHandling::Allow,
931 UpdateType::InternalOrHSTSRedirect, false);
932 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
933 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "nsCORSListenerProxy::AsyncOnChannelRedirect: "
"internal redirect UpdateChannel() returned failure", nullptr
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 935)
934 "nsCORSListenerProxy::AsyncOnChannelRedirect: "NS_DebugBreak(NS_DEBUG_WARNING, "nsCORSListenerProxy::AsyncOnChannelRedirect: "
"internal redirect UpdateChannel() returned failure", nullptr
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 935)
935 "internal redirect UpdateChannel() returned failure")NS_DebugBreak(NS_DEBUG_WARNING, "nsCORSListenerProxy::AsyncOnChannelRedirect: "
"internal redirect UpdateChannel() returned failure", nullptr
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 935)
;
936 aOldChannel->Cancel(rv);
937 return rv;
938 }
939 } else {
940 mIsRedirect = true;
941 // A real, external redirect. Perform CORS checking on new URL.
942 rv = CheckRequestApproved(aOldChannel);
943 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
944 nsCOMPtr<nsIURI> oldURI;
945 NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI));
946 if (oldURI) {
947 OriginAttributes attrs;
948 StoragePrincipalHelper::GetOriginAttributesForNetworkState(aOldChannel,
949 attrs);
950 if (sPreflightCache) {
951 // OK to use mRequestingPrincipal since preflights never get
952 // redirected.
953 sPreflightCache->RemoveEntries(oldURI, mRequestingPrincipal, attrs);
954 } else {
955 nsCOMPtr<nsIHttpChannelChild> httpChannelChild =
956 do_QueryInterface(aOldChannel);
957 if (httpChannelChild) {
958 rv = httpChannelChild->RemoveCorsPreflightCacheEntry(
959 oldURI, mRequestingPrincipal, attrs);
960 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
961 // Only warn here to ensure we call the channel Cancel() below
962 NS_WARNING("Failed to remove CORS preflight cache entry!")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to remove CORS preflight cache entry!"
, nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 962)
;
963 }
964 }
965 }
966 }
967 aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
968 // Reason for NS_ERROR_DOM_BAD_URI already logged in
969 // CheckRequestApproved()
970 return NS_ERROR_DOM_BAD_URI;
971 }
972
973 if (mHasBeenCrossSite) {
974 // Once we've been cross-site, cross-origin redirects reset our source
975 // origin. Note that we need to call GetChannelURIPrincipal() because
976 // we are looking for the principal that is actually being loaded and not
977 // the principal that initiated the load.
978 nsCOMPtr<nsIPrincipal> oldChannelPrincipal;
979 nsContentUtils::GetSecurityManager()->GetChannelURIPrincipal(
980 aOldChannel, getter_AddRefs(oldChannelPrincipal));
981 nsCOMPtr<nsIPrincipal> newChannelPrincipal;
982 nsContentUtils::GetSecurityManager()->GetChannelURIPrincipal(
983 aNewChannel, getter_AddRefs(newChannelPrincipal));
984 if (!oldChannelPrincipal || !newChannelPrincipal) {
985 rv = NS_ERROR_OUT_OF_MEMORY;
986 }
987
988 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
989 aOldChannel->Cancel(rv);
990 return rv;
991 }
992
993 if (!oldChannelPrincipal->Equals(newChannelPrincipal)) {
994 // Spec says to set our source origin to a unique origin.
995 mOriginHeaderPrincipal =
996 NullPrincipal::CreateWithInheritedAttributes(oldChannelPrincipal);
997 }
998 }
999
1000 bool rewriteToGET = false;
1001 // We need to strip auth header from preflight request for
1002 // cross-origin redirects.
1003 // See Bug 1874132
1004 bool stripAuthHeader =
1005 NS_ShouldRemoveAuthHeaderOnRedirect(aOldChannel, aNewChannel, aFlags);
1006
1007 nsCOMPtr<nsIHttpChannel> oldHttpChannel = do_QueryInterface(aOldChannel);
1008 if (oldHttpChannel) {
1009 nsAutoCString method;
1010 (void)oldHttpChannel->GetRequestMethod(method);
1011 (void)oldHttpChannel->ShouldStripRequestBodyHeader(method, &rewriteToGET);
1012 }
1013
1014 rv = UpdateChannel(
1015 aNewChannel, DataURIHandling::Disallow,
1016 rewriteToGET ? UpdateType::StripRequestBodyHeader : UpdateType::Default,
1017 stripAuthHeader);
1018 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1019 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "nsCORSListenerProxy::AsyncOnChannelRedirect: "
"UpdateChannel() returned failure", nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1021)
1020 "nsCORSListenerProxy::AsyncOnChannelRedirect: "NS_DebugBreak(NS_DEBUG_WARNING, "nsCORSListenerProxy::AsyncOnChannelRedirect: "
"UpdateChannel() returned failure", nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1021)
1021 "UpdateChannel() returned failure")NS_DebugBreak(NS_DEBUG_WARNING, "nsCORSListenerProxy::AsyncOnChannelRedirect: "
"UpdateChannel() returned failure", nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1021)
;
1022 aOldChannel->Cancel(rv);
1023 return rv;
1024 }
1025 }
1026
1027 nsCOMPtr<nsIChannelEventSink> outer =
1028 do_GetInterface(mOuterNotificationCallbacks);
1029 if (outer) {
1030 return outer->AsyncOnChannelRedirect(aOldChannel, aNewChannel, aFlags, aCb);
1031 }
1032
1033 aCb->OnRedirectVerifyCallback(NS_OK);
1034
1035 return NS_OK;
1036}
1037
1038NS_IMETHODIMPnsresult
1039nsCORSListenerProxy::CheckListenerChain() {
1040 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()"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1040); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { MOZ_CrashSequence(__null, 1040); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1041
1042 nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener;
1043 {
1044 MutexAutoLock lock(mMutex);
1045 retargetableListener = do_QueryInterface(mOuterListener);
1046 }
1047 if (!retargetableListener) {
1048 return NS_ERROR_NO_INTERFACE;
1049 }
1050
1051 return retargetableListener->CheckListenerChain();
1052}
1053
1054// Please note that the CSP directive 'upgrade-insecure-requests' and the
1055// HTTPS-Only Mode are relying on the promise that channels get updated from
1056// http: to https: before the channel fetches any data from the netwerk. Such
1057// channels should not be blocked by CORS and marked as cross origin requests.
1058// E.g.: toplevel page: https://www.example.com loads
1059// xhr: http://www.example.com/foo which gets updated to
1060// https://www.example.com/foo
1061// In such a case we should bail out of CORS and rely on the promise that
1062// nsHttpChannel::Connect() upgrades the request from http to https.
1063bool CheckInsecureUpgradePreventsCORS(nsIPrincipal* aRequestingPrincipal,
1064 nsIChannel* aChannel) {
1065 nsCOMPtr<nsIURI> channelURI;
1066 nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
1067 NS_ENSURE_SUCCESS(rv, false)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", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1067); return false; } } while (false)
;
1068
1069 // upgrade insecure requests is only applicable to http requests
1070 if (!channelURI->SchemeIs("http")) {
1071 return false;
1072 }
1073
1074 nsCOMPtr<nsIURI> originalURI;
1075 rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI));
1076 NS_ENSURE_SUCCESS(rv, false)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", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1076); return false; } } while (false)
;
1077
1078 nsAutoCString principalHost, channelHost, origChannelHost;
1079
1080 // if we can not query a host from the uri, there is nothing to do
1081 if (NS_FAILED(aRequestingPrincipal->GetAsciiHost(principalHost))((bool)(__builtin_expect(!!(NS_FAILED_impl(aRequestingPrincipal
->GetAsciiHost(principalHost))), 0)))
||
1082 NS_FAILED(channelURI->GetAsciiHost(channelHost))((bool)(__builtin_expect(!!(NS_FAILED_impl(channelURI->GetAsciiHost
(channelHost))), 0)))
||
1083 NS_FAILED(originalURI->GetAsciiHost(origChannelHost))((bool)(__builtin_expect(!!(NS_FAILED_impl(originalURI->GetAsciiHost
(origChannelHost))), 0)))
) {
1084 return false;
1085 }
1086
1087 // if the hosts do not match, there is nothing to do
1088 if (!principalHost.EqualsIgnoreCase(channelHost.get())) {
1089 return false;
1090 }
1091
1092 // also check that uri matches the one of the originalURI
1093 if (!channelHost.EqualsIgnoreCase(origChannelHost.get())) {
1094 return false;
1095 }
1096
1097 return true;
1098}
1099
1100nsresult nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel,
1101 DataURIHandling aAllowDataURI,
1102 UpdateType aUpdateType,
1103 bool aStripAuthHeader) {
1104 MOZ_ASSERT_IF(aUpdateType == UpdateType::InternalOrHSTSRedirect,do { if (aUpdateType == UpdateType::InternalOrHSTSRedirect) {
do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aStripAuthHeader)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aStripAuthHeader))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!aStripAuthHeader"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aStripAuthHeader"
")"); do { MOZ_CrashSequence(__null, 1105); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1105 !aStripAuthHeader)do { if (aUpdateType == UpdateType::InternalOrHSTSRedirect) {
do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aStripAuthHeader)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aStripAuthHeader))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!aStripAuthHeader"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aStripAuthHeader"
")"); do { MOZ_CrashSequence(__null, 1105); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1106 nsCOMPtr<nsIURI> uri, originalURI;
1107 nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
1108 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1108); return rv; } } while (false)
;
1109 rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI));
1110 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1110); return rv; } } while (false)
;
1111
1112 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
1113
1114 // Introduced for DevTools in order to allow overriding some requests
1115 // with the content of data: URIs.
1116 if (loadInfo->GetAllowInsecureRedirectToDataURI() && uri->SchemeIs("data")) {
1117 return NS_OK;
1118 }
1119
1120 // exempt data URIs from the same origin check.
1121 if (aAllowDataURI == DataURIHandling::Allow && originalURI == uri) {
1122 if (uri->SchemeIs("data")) {
1123 return NS_OK;
1124 }
1125 if (loadInfo->GetAboutBlankInherits() && NS_IsAboutBlank(uri)) {
1126 return NS_OK;
1127 }
1128 }
1129
1130 // Set CORS attributes on channel so that intercepted requests get correct
1131 // values. We have to do this here because the CheckMayLoad checks may lead
1132 // to early return. We can't be sure this is an http channel though, so we
1133 // can't return early on failure.
1134 nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aChannel);
1135 if (internal) {
1136 rv = internal->SetRequestMode(dom::RequestMode::Cors);
1137 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1137); return rv; } } while (false)
;
1138 rv = internal->SetCorsIncludeCredentials(mWithCredentials);
1139 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1139); return rv; } } while (false)
;
1140 }
1141
1142 // TODO: Bug 1353683
1143 // consider calling SetBlockedRequest in nsCORSListenerProxy::UpdateChannel
1144 //
1145 // Check that the uri is ok to load
1146 uint32_t flags = loadInfo->CheckLoadURIFlags();
1147 rv = nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
1148 mRequestingPrincipal, uri, flags, loadInfo->GetInnerWindowID());
1149 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1149); return rv; } } while (false)
;
1150
1151 if (originalURI != uri) {
1152 rv = nsContentUtils::GetSecurityManager()->CheckLoadURIWithPrincipal(
1153 mRequestingPrincipal, originalURI, flags, loadInfo->GetInnerWindowID());
1154 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1154); return rv; } } while (false)
;
1155 }
1156
1157 if (uri->SchemeIs("moz-extension")) {
1158 // moz-extension:-URLs do not support CORS, but can universally be read
1159 // if an extension lists the resource in web_accessible_resources.
1160 // This is enforced via the CheckLoadURIWithPrincipal call above:
1161 // moz-extension resources have the URI_DANGEROUS_TO_LOAD flag, unless
1162 // listed in web_accessible_resources.
1163 return NS_OK;
1164 }
1165
1166 if (!mHasBeenCrossSite &&
1167 NS_SUCCEEDED(mRequestingPrincipal->CheckMayLoad(uri, false))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mRequestingPrincipal
->CheckMayLoad(uri, false))), 1)))
&&
1168 (originalURI == uri ||
1169 NS_SUCCEEDED(mRequestingPrincipal->CheckMayLoad(originalURI, false))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mRequestingPrincipal
->CheckMayLoad(originalURI, false))), 1)))
)) {
1170 return NS_OK;
1171 }
1172
1173 // If the CSP directive 'upgrade-insecure-requests' is used or the HTTPS-Only
1174 // Mode is enabled then we should not incorrectly require CORS if the only
1175 // difference of a subresource request and the main page is the scheme. e.g.
1176 // toplevel page: https://www.example.com loads
1177 // xhr: http://www.example.com/somefoo,
1178 // then the xhr request will be upgraded to https before it fetches any data
1179 // from the netwerk, hence we shouldn't require CORS in that specific case.
1180 if (CheckInsecureUpgradePreventsCORS(mRequestingPrincipal, aChannel)) {
1181 // Check if https-only mode upgrades this later anyway
1182 nsCOMPtr<nsILoadInfo> loadinfo = aChannel->LoadInfo();
1183 if (nsHTTPSOnlyUtils::IsSafeToAcceptCORSOrMixedContent(loadinfo)) {
1184 return NS_OK;
1185 }
1186 // Check if 'upgrade-insecure-requests' is used
1187 if (loadInfo->GetUpgradeInsecureRequests() ||
1188 loadInfo->GetBrowserUpgradeInsecureRequests()) {
1189 return NS_OK;
1190 }
1191 }
1192
1193 // Check if we need to do a preflight, and if so set one up. This must be
1194 // called once we know that the request is going, or has gone, cross-origin.
1195 rv = CheckPreflightNeeded(aChannel, aUpdateType, aStripAuthHeader);
1196 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1196); return rv; } } while (false)
;
1197
1198 // It's a cross site load
1199 mHasBeenCrossSite = true;
1200
1201 if (mIsRedirect) {
1202 // https://fetch.spec.whatwg.org/#http-redirect-fetch
1203 // Step 9. If request’s mode is "cors", locationURL includes credentials,
1204 // and request’s origin is not same origin with locationURL’s origin,
1205 // then return a network error.
1206
1207 nsAutoCString userpass;
1208 uri->GetUserPass(userpass);
1209 NS_ENSURE_TRUE(userpass.IsEmpty(), NS_ERROR_DOM_BAD_URI)do { if ((__builtin_expect(!!(!(userpass.IsEmpty())), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "userpass.IsEmpty()" ") failed"
, nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1209); return NS_ERROR_DOM_BAD_URI; } } while (false)
;
1210 }
1211
1212 // If we have an expanded principal here, we'll reject the CORS request,
1213 // because we can't send a useful Origin header which is required for CORS.
1214 if (nsContentUtils::IsExpandedPrincipal(mOriginHeaderPrincipal)) {
1215 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
1216 LogBlockedRequest(aChannel, "CORSOriginHeaderNotAdded", nullptr,
1217 nsILoadInfo::BLOCKING_REASON_CORSORIGINHEADERNOTADDED,
1218 httpChannel);
1219 return NS_ERROR_DOM_BAD_URI;
1220 }
1221
1222 // Add the Origin header
1223 nsAutoCString origin;
1224 rv = mOriginHeaderPrincipal->GetWebExposedOriginSerialization(origin);
1225 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1225); return rv; } } while (false)
;
1226
1227 nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aChannel);
1228 NS_ENSURE_TRUE(http, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(http)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "http" ") failed", nullptr
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1228); return NS_ERROR_FAILURE; } } while (false)
;
1229
1230 // hide the Origin header when requesting from .onion and requesting CORS
1231 if (StaticPrefs::network_http_referer_hideOnionSource()) {
1232 if (mOriginHeaderPrincipal->GetIsOnion()) {
1233 origin.AssignLiteral("null");
1234 }
1235 }
1236
1237 rv = http->SetRequestHeader(net::nsHttp::Origin.val(), origin, false);
1238 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1238); return rv; } } while (false)
;
1239
1240 // Make cookie-less if needed. We don't need to do anything here if the
1241 // channel was opened with AsyncOpen, since then AsyncOpen will take
1242 // care of the cookie policy for us.
1243 if (!mWithCredentials) {
1244 nsLoadFlags flags;
1245 rv = http->GetLoadFlags(&flags);
1246 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1246); return rv; } } while (false)
;
1247
1248 flags |= nsIRequest::LOAD_ANONYMOUS;
1249 if (StaticPrefs::network_cors_preflight_allow_client_cert()) {
1250 flags |= nsIRequest::LOAD_ANONYMOUS_ALLOW_CLIENT_CERT;
1251 }
1252 rv = http->SetLoadFlags(flags);
1253 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1253); return rv; } } while (false)
;
1254 }
1255
1256 mHttpChannel = std::move(http);
1257
1258 return NS_OK;
1259}
1260
1261nsresult nsCORSListenerProxy::CheckPreflightNeeded(nsIChannel* aChannel,
1262 UpdateType aUpdateType,
1263 bool aStripAuthHeader) {
1264 // If this caller isn't using AsyncOpen, or if this *is* a preflight channel,
1265 // then we shouldn't initiate preflight for this channel.
1266 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
1267 if (loadInfo->GetSecurityMode() !=
1268 nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT ||
1269 loadInfo->GetIsPreflight()) {
1270 return NS_OK;
1271 }
1272
1273 bool doPreflight = loadInfo->GetForcePreflight();
1274
1275 nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aChannel);
1276 if (!http) {
1277 // Note: A preflight is not needed for moz-extension:-requests either, but
1278 // there is already a check for that in the caller of CheckPreflightNeeded,
1279 // in UpdateChannel.
1280 LogBlockedRequest(aChannel, "CORSRequestNotHttp", nullptr,
1281 nsILoadInfo::BLOCKING_REASON_CORSREQUESTNOTHTTP,
1282 mHttpChannel);
1283 return NS_ERROR_DOM_BAD_URI;
1284 }
1285
1286 nsAutoCString method;
1287 (void)http->GetRequestMethod(method);
1288 if (!method.LowerCaseEqualsLiteral("get") &&
1289 !method.LowerCaseEqualsLiteral("post") &&
1290 !method.LowerCaseEqualsLiteral("head")) {
1291 doPreflight = true;
1292 }
1293
1294 // Avoid copying the array here
1295 const nsTArray<nsCString>& loadInfoHeaders = loadInfo->CorsUnsafeHeaders();
1296 if (!loadInfoHeaders.IsEmpty()) {
1297 doPreflight = true;
1298 }
1299
1300 // Add Content-Type header if needed
1301 nsTArray<nsCString> headers;
1302 nsAutoCString contentTypeHeader;
1303 nsresult rv = http->GetRequestHeader("Content-Type"_ns, contentTypeHeader);
1304 // GetRequestHeader return an error if the header is not set. Don't add
1305 // "content-type" to the list if that's the case.
1306 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) &&
1307 !nsContentUtils::IsAllowedNonCorsContentType(contentTypeHeader) &&
1308 !loadInfoHeaders.Contains("content-type"_ns,
1309 nsCaseInsensitiveCStringArrayComparator())) {
1310 headers.AppendElements(loadInfoHeaders);
1311 headers.AppendElement("content-type"_ns);
1312 doPreflight = true;
1313 }
1314
1315 if (!doPreflight) {
1316 return NS_OK;
1317 }
1318
1319 nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(http);
1320 if (!internal) {
1321 auto statusCode = GetStatusCodeAsString(http);
1322 LogBlockedRequest(aChannel, "CORSDidNotSucceed2", statusCode.get(),
1323 nsILoadInfo::BLOCKING_REASON_CORSDIDNOTSUCCEED,
1324 mHttpChannel);
1325 return NS_ERROR_DOM_BAD_URI;
1326 }
1327
1328 internal->SetCorsPreflightParameters(
1329 headers.IsEmpty() ? loadInfoHeaders : headers,
1330 aUpdateType == UpdateType::StripRequestBodyHeader, aStripAuthHeader);
1331
1332 return NS_OK;
1333}
1334
1335//////////////////////////////////////////////////////////////////////////
1336// Preflight proxy
1337
1338// Class used as streamlistener and notification callback when
1339// doing the initial OPTIONS request for a CORS check
1340class nsCORSPreflightListener final : public nsIStreamListener,
1341 public nsIInterfaceRequestor,
1342 public nsIChannelEventSink {
1343 public:
1344 nsCORSPreflightListener(nsIPrincipal* aReferrerPrincipal,
1345 nsICorsPreflightCallback* aCallback,
1346 nsILoadContext* aLoadContext, bool aWithCredentials,
1347 const nsCString& aPreflightMethod,
1348 const nsTArray<nsCString>& aPreflightHeaders)
1349 : mPreflightMethod(aPreflightMethod),
1350 mPreflightHeaders(aPreflightHeaders.Clone()),
1351 mReferrerPrincipal(aReferrerPrincipal),
1352 mCallback(aCallback),
1353 mLoadContext(aLoadContext),
1354 mWithCredentials(aWithCredentials) {}
1355
1356 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
1357 NS_DECL_NSISTREAMLISTENERvirtual nsresult OnDataAvailable(nsIRequest *aRequest, nsIInputStream
*aInputStream, uint64_t aOffset, uint32_t aCount) override;
1358 NS_DECL_NSIREQUESTOBSERVERvirtual nsresult OnStartRequest(nsIRequest *aRequest) override
; virtual nsresult OnStopRequest(nsIRequest *aRequest, nsresult
aStatusCode) override;
1359 NS_DECL_NSIINTERFACEREQUESTORvirtual nsresult GetInterface(const nsIID & uuid, void * *
result) override;
1360 NS_DECL_NSICHANNELEVENTSINKvirtual nsresult AsyncOnChannelRedirect(nsIChannel *oldChannel
, nsIChannel *newChannel, uint32_t flags, nsIAsyncVerifyRedirectCallback
*callback) override;
1361
1362 nsresult CheckPreflightRequestApproved(nsIRequest* aRequest);
1363
1364 private:
1365 ~nsCORSPreflightListener() = default;
1366
1367 void AddResultToCache(nsIRequest* aRequest);
1368
1369 nsCString mPreflightMethod;
1370 nsTArray<nsCString> mPreflightHeaders;
1371 nsCOMPtr<nsIPrincipal> mReferrerPrincipal;
1372 nsCOMPtr<nsICorsPreflightCallback> mCallback;
1373 nsCOMPtr<nsILoadContext> mLoadContext;
1374 bool mWithCredentials;
1375};
1376
1377NS_IMPL_ISUPPORTS(nsCORSPreflightListener, nsIStreamListener,MozExternalRefCountType nsCORSPreflightListener::AddRef(void)
{ static_assert(!std::is_destructible_v<nsCORSPreflightListener
>, "Reference-counted class " "nsCORSPreflightListener" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1379
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSPreflightListener" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsCORSPreflightListener" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsCORSPreflightListener\" != nullptr"
" (" "Must specify a name" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSPreflightListener\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1379); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsCORSPreflightListener" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"nsCORSPreflightListener"), (uint32_t)(sizeof(*this))); return
count; } MozExternalRefCountType nsCORSPreflightListener::Release
(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1379
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSPreflightListener" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsCORSPreflightListener" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsCORSPreflightListener\" != nullptr"
" (" "Must specify a name" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSPreflightListener\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1379); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsCORSPreflightListener" " not thread-safe"
); const char* const nametmp = "nsCORSPreflightListener"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult nsCORSPreflightListener::QueryInterface(const
nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(4 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsCORSPreflightListener, nsIStreamListener
>, int32_t( reinterpret_cast<char*>(static_cast<nsIStreamListener
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsIRequestObserver
>, int32_t( reinterpret_cast<char*>(static_cast<nsIRequestObserver
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsIInterfaceRequestor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIInterfaceRequestor
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsIChannelEventSink
>, int32_t( reinterpret_cast<char*>(static_cast<nsIChannelEventSink
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsISupports
>, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsIStreamListener*>((nsCORSPreflightListener
*)0x1000))) - reinterpret_cast<char*>((nsCORSPreflightListener
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
1378 nsIRequestObserver, nsIInterfaceRequestor,MozExternalRefCountType nsCORSPreflightListener::AddRef(void)
{ static_assert(!std::is_destructible_v<nsCORSPreflightListener
>, "Reference-counted class " "nsCORSPreflightListener" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1379
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSPreflightListener" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsCORSPreflightListener" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsCORSPreflightListener\" != nullptr"
" (" "Must specify a name" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSPreflightListener\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1379); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsCORSPreflightListener" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"nsCORSPreflightListener"), (uint32_t)(sizeof(*this))); return
count; } MozExternalRefCountType nsCORSPreflightListener::Release
(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1379
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSPreflightListener" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsCORSPreflightListener" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsCORSPreflightListener\" != nullptr"
" (" "Must specify a name" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSPreflightListener\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1379); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsCORSPreflightListener" " not thread-safe"
); const char* const nametmp = "nsCORSPreflightListener"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult nsCORSPreflightListener::QueryInterface(const
nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(4 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsCORSPreflightListener, nsIStreamListener
>, int32_t( reinterpret_cast<char*>(static_cast<nsIStreamListener
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsIRequestObserver
>, int32_t( reinterpret_cast<char*>(static_cast<nsIRequestObserver
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsIInterfaceRequestor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIInterfaceRequestor
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsIChannelEventSink
>, int32_t( reinterpret_cast<char*>(static_cast<nsIChannelEventSink
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsISupports
>, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsIStreamListener*>((nsCORSPreflightListener
*)0x1000))) - reinterpret_cast<char*>((nsCORSPreflightListener
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
1379 nsIChannelEventSink)MozExternalRefCountType nsCORSPreflightListener::AddRef(void)
{ static_assert(!std::is_destructible_v<nsCORSPreflightListener
>, "Reference-counted class " "nsCORSPreflightListener" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1379
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSPreflightListener" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsCORSPreflightListener" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsCORSPreflightListener\" != nullptr"
" (" "Must specify a name" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSPreflightListener\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1379); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsCORSPreflightListener" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"nsCORSPreflightListener"), (uint32_t)(sizeof(*this))); return
count; } MozExternalRefCountType nsCORSPreflightListener::Release
(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1379
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsCORSPreflightListener" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsCORSPreflightListener" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsCORSPreflightListener\" != nullptr"
" (" "Must specify a name" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsCORSPreflightListener\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1379); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsCORSPreflightListener" " not thread-safe"
); const char* const nametmp = "nsCORSPreflightListener"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult nsCORSPreflightListener::QueryInterface(const
nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1379); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(4 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsCORSPreflightListener, nsIStreamListener
>, int32_t( reinterpret_cast<char*>(static_cast<nsIStreamListener
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsIRequestObserver
>, int32_t( reinterpret_cast<char*>(static_cast<nsIRequestObserver
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsIInterfaceRequestor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIInterfaceRequestor
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsIChannelEventSink
>, int32_t( reinterpret_cast<char*>(static_cast<nsIChannelEventSink
*>((nsCORSPreflightListener*)0x1000)) - reinterpret_cast<
char*>((nsCORSPreflightListener*)0x1000))}, {&mozilla::
detail::kImplementedIID<nsCORSPreflightListener, nsISupports
>, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsIStreamListener*>((nsCORSPreflightListener
*)0x1000))) - reinterpret_cast<char*>((nsCORSPreflightListener
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
1380
1381void nsCORSPreflightListener::AddResultToCache(nsIRequest* aRequest) {
1382 nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
1383 NS_ASSERTION(http, "Request was not http")do { if (!(http)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Request was not http"
, "http", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1383); MOZ_PretendNoReturn(); } } while (0)
;
1384
1385 // The "Access-Control-Max-Age" header should return an age in seconds.
1386 nsAutoCString headerVal;
1387 uint32_t age = 0;
1388 (void)http->GetResponseHeader("Access-Control-Max-Age"_ns, headerVal);
1389 if (headerVal.IsEmpty()) {
1390 age = PREFLIGHT_DEFAULT_EXPIRY_SECONDS5;
1391 } else {
1392 // Sanitize the string. We only allow 'delta-seconds' as specified by
1393 // http://dev.w3.org/2006/waf/access-control (digits 0-9 with no leading or
1394 // trailing non-whitespace characters).
1395 nsACString::const_char_iterator iter, end;
1396 headerVal.BeginReading(iter);
1397 headerVal.EndReading(end);
1398 while (iter != end) {
1399 if (*iter < '0' || *iter > '9') {
1400 return;
1401 }
1402 age = age * 10 + (*iter - '0');
1403 // Cap at 24 hours. This also avoids overflow
1404 age = std::min(age, 86400U);
1405 ++iter;
1406 }
1407 }
1408
1409 if (!age || !EnsurePreflightCache()) {
1410 return;
1411 }
1412
1413 // String seems fine, go ahead and cache.
1414 // Note that we have already checked that these headers follow the correct
1415 // syntax.
1416
1417 nsCOMPtr<nsIURI> uri;
1418 NS_GetFinalChannelURI(http, getter_AddRefs(uri));
1419
1420 TimeStamp expirationTime =
1421 TimeStamp::NowLoRes() + TimeDuration::FromSeconds(age);
1422
1423 OriginAttributes attrs;
1424 StoragePrincipalHelper::GetOriginAttributesForNetworkState(http, attrs);
1425
1426 RefPtr<CORSCacheEntry> entry = sPreflightCache->GetEntry(
1427 uri, mReferrerPrincipal, mWithCredentials, attrs, true);
1428 if (!entry) {
1429 return;
1430 }
1431
1432 nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(
1433 do_QueryInterface(aRequest));
1434 if (httpChannelInternal) {
1435 (void)httpChannelInternal->GetIsProxyUsed(&entry->mIsProxyUsed);
1436 }
1437
1438 // The "Access-Control-Allow-Methods" header contains a comma separated
1439 // list of method names.
1440 (void)http->GetResponseHeader("Access-Control-Allow-Methods"_ns, headerVal);
1441
1442 for (const nsACString& method :
1443 nsCCharSeparatedTokenizer(headerVal, ',').ToRange()) {
1444 if (method.IsEmpty()) {
1445 continue;
1446 }
1447 uint32_t i;
1448 for (i = 0; i < entry->mMethods.Length(); ++i) {
1449 if (entry->mMethods[i].token.Equals(method)) {
1450 entry->mMethods[i].expirationTime = expirationTime;
1451 break;
1452 }
1453 }
1454 if (i == entry->mMethods.Length()) {
1455 nsPreflightCache::TokenTime* newMethod = entry->mMethods.AppendElement();
1456 if (!newMethod) {
1457 return;
1458 }
1459
1460 newMethod->token = method;
1461 newMethod->expirationTime = expirationTime;
1462 }
1463 }
1464
1465 // The "Access-Control-Allow-Headers" header contains a comma separated
1466 // list of method names.
1467 (void)http->GetResponseHeader("Access-Control-Allow-Headers"_ns, headerVal);
1468
1469 for (const nsACString& header :
1470 nsCCharSeparatedTokenizer(headerVal, ',').ToRange()) {
1471 if (header.IsEmpty()) {
1472 continue;
1473 }
1474 uint32_t i;
1475 for (i = 0; i < entry->mHeaders.Length(); ++i) {
1476 if (entry->mHeaders[i].token.Equals(header)) {
1477 entry->mHeaders[i].expirationTime = expirationTime;
1478 break;
1479 }
1480 }
1481 if (i == entry->mHeaders.Length()) {
1482 nsPreflightCache::TokenTime* newHeader = entry->mHeaders.AppendElement();
1483 if (!newHeader) {
1484 return;
1485 }
1486
1487 newHeader->token = header;
1488 newHeader->expirationTime = expirationTime;
1489 }
1490 }
1491}
1492
1493NS_IMETHODIMPnsresult
1494nsCORSPreflightListener::OnStartRequest(nsIRequest* aRequest) {
1495#ifdef DEBUG1
1496 {
1497 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
1498 nsCOMPtr<nsILoadInfo> loadInfo = channel ? channel->LoadInfo() : nullptr;
1499 MOZ_ASSERT(!loadInfo || !loadInfo->GetServiceWorkerTaintingSynthesized())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!loadInfo || !loadInfo->GetServiceWorkerTaintingSynthesized
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!loadInfo || !loadInfo->GetServiceWorkerTaintingSynthesized
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!loadInfo || !loadInfo->GetServiceWorkerTaintingSynthesized()"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!loadInfo || !loadInfo->GetServiceWorkerTaintingSynthesized()"
")"); do { MOZ_CrashSequence(__null, 1499); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1500 }
1501#endif
1502
1503 nsresult rv = CheckPreflightRequestApproved(aRequest);
1504
1505 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1506 // Everything worked, try to cache and then fire off the actual request.
1507 AddResultToCache(aRequest);
1508
1509 mCallback->OnPreflightSucceeded();
1510 } else {
1511 mCallback->OnPreflightFailed(rv);
1512 }
1513
1514 return rv;
1515}
1516
1517NS_IMETHODIMPnsresult
1518nsCORSPreflightListener::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
1519 mCallback = nullptr;
1520 return NS_OK;
1521}
1522
1523/** nsIStreamListener methods **/
1524
1525NS_IMETHODIMPnsresult
1526nsCORSPreflightListener::OnDataAvailable(nsIRequest* aRequest,
1527 nsIInputStream* inStr,
1528 uint64_t sourceOffset,
1529 uint32_t count) {
1530 uint32_t totalRead;
1531 return inStr->ReadSegments(NS_DiscardSegment, nullptr, count, &totalRead);
1532}
1533
1534NS_IMETHODIMPnsresult
1535nsCORSPreflightListener::AsyncOnChannelRedirect(
1536 nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags,
1537 nsIAsyncVerifyRedirectCallback* callback) {
1538 // Only internal redirects allowed for now.
1539 if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags) &&
1540 !NS_IsHSTSUpgradeRedirect(aOldChannel, aNewChannel, aFlags)) {
1541 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
1542 LogBlockedRequest(
1543 aOldChannel, "CORSExternalRedirectNotAllowed", nullptr,
1544 nsILoadInfo::BLOCKING_REASON_CORSEXTERNALREDIRECTNOTALLOWED,
1545 httpChannel);
1546 return NS_ERROR_DOM_BAD_URI;
1547 }
1548
1549 callback->OnRedirectVerifyCallback(NS_OK);
1550 return NS_OK;
1551}
1552
1553nsresult nsCORSPreflightListener::CheckPreflightRequestApproved(
1554 nsIRequest* aRequest) {
1555 nsresult status;
1556 nsresult rv = aRequest->GetStatus(&status);
1557 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1557); return rv; } } while (false)
;
1558 NS_ENSURE_SUCCESS(status, status)do { nsresult __rv = status; 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", "status", "status", static_cast<
uint32_t>(__rv), name ? " (" : "", name ? name : "", name ?
")" : ""); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1558); return status; } } while (false)
;
1559
1560 // Test that things worked on a HTTP level
1561 nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
1562 nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aRequest);
1563 NS_ENSURE_STATE(internal)do { if ((__builtin_expect(!!(!(internal)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "internal" ") failed", nullptr
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1563); return NS_ERROR_UNEXPECTED; } } while (false)
;
1564 nsCOMPtr<nsIHttpChannel> parentHttpChannel = do_QueryInterface(mCallback);
1565
1566 bool succeedded;
1567 rv = http->GetRequestSucceeded(&succeedded);
1568 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !succeedded) {
1569 auto statusCode = GetStatusCodeAsString(http);
1570 LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed3", statusCode.get(),
1571 nsILoadInfo::BLOCKING_REASON_CORSPREFLIGHTDIDNOTSUCCEED,
1572 parentHttpChannel);
1573 return NS_ERROR_DOM_BAD_URI;
1574 }
1575
1576 nsAutoCString headerVal;
1577 // The "Access-Control-Allow-Methods" header contains a comma separated
1578 // list of method names.
1579 (void)http->GetResponseHeader("Access-Control-Allow-Methods"_ns, headerVal);
1580 bool foundMethod = mPreflightMethod.EqualsLiteral("GET") ||
1581 mPreflightMethod.EqualsLiteral("HEAD") ||
1582 mPreflightMethod.EqualsLiteral("POST");
1583 for (const nsACString& method :
1584 nsCCharSeparatedTokenizer(headerVal, ',').ToRange()) {
1585 if (method.IsEmpty()) {
1586 continue;
1587 }
1588 if (!NS_IsValidHTTPToken(method)) {
1589 LogBlockedRequest(aRequest, "CORSInvalidAllowMethod",
1590 NS_ConvertUTF8toUTF16(method).get(),
1591 nsILoadInfo::BLOCKING_REASON_CORSINVALIDALLOWMETHOD,
1592 parentHttpChannel);
1593 return NS_ERROR_DOM_BAD_URI;
1594 }
1595
1596 if (method.EqualsLiteral("*") && !mWithCredentials) {
1597 foundMethod = true;
1598 } else {
1599 foundMethod |= mPreflightMethod.Equals(method);
1600 }
1601 }
1602 if (!foundMethod) {
1603 LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr,
1604 nsILoadInfo::BLOCKING_REASON_CORSMETHODNOTFOUND,
1605 parentHttpChannel);
1606 return NS_ERROR_DOM_BAD_URI;
1607 }
1608
1609 // The "Access-Control-Allow-Headers" header contains a comma separated
1610 // list of header names.
1611 (void)http->GetResponseHeader("Access-Control-Allow-Headers"_ns, headerVal);
1612 nsTArray<nsCString> headers;
1613 bool wildcard = false;
1614 bool hasAuthorizationHeader = false;
1615 for (const nsACString& header :
1616 nsCCharSeparatedTokenizer(headerVal, ',').ToRange()) {
1617 if (header.IsEmpty()) {
1618 continue;
1619 }
1620 if (!NS_IsValidHTTPToken(header)) {
1621 LogBlockedRequest(aRequest, "CORSInvalidAllowHeader",
1622 NS_ConvertUTF8toUTF16(header).get(),
1623 nsILoadInfo::BLOCKING_REASON_CORSINVALIDALLOWHEADER,
1624 parentHttpChannel);
1625 return NS_ERROR_DOM_BAD_URI;
1626 }
1627 if (header.EqualsLiteral("*") && !mWithCredentials) {
1628 wildcard = true;
1629 } else {
1630 headers.AppendElement(header);
1631 }
1632
1633 if (header.LowerCaseEqualsASCII("authorization")) {
1634 hasAuthorizationHeader = true;
1635 }
1636 }
1637
1638 bool authorizationInPreflightHeaders = false;
1639 bool authorizationCoveredByWildcard = false;
1640 for (uint32_t i = 0; i < mPreflightHeaders.Length(); ++i) {
1641 // Cache the result of the authorization header.
1642 bool isAuthorization =
1643 mPreflightHeaders[i].LowerCaseEqualsASCII("authorization");
1644 if (wildcard) {
1645 if (!isAuthorization) {
1646 continue;
1647 } else {
1648 authorizationInPreflightHeaders = true;
1649 if (StaticPrefs::
1650 network_cors_preflight_authorization_covered_by_wildcard() &&
1651 !hasAuthorizationHeader) {
1652 // When `Access-Control-Allow-Headers` is `*` and there is no
1653 // `Authorization` header listed, we send a deprecation warning to the
1654 // console.
1655 LogBlockedRequest(aRequest, "CORSAllowHeaderFromPreflightDeprecation",
1656 nullptr, 0, parentHttpChannel, true);
1657 glean::network::cors_authorization_header
1658 .Get("covered_by_wildcard"_ns)
1659 .Add(1);
1660 authorizationCoveredByWildcard = true;
1661 continue;
1662 }
1663 }
1664 }
1665
1666 const auto& comparator = nsCaseInsensitiveCStringArrayComparator();
1667 if (!headers.Contains(mPreflightHeaders[i], comparator)) {
1668 LogBlockedRequest(
1669 aRequest, "CORSMissingAllowHeaderFromPreflight2",
1670 NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get(),
1671 nsILoadInfo::BLOCKING_REASON_CORSMISSINGALLOWHEADERFROMPREFLIGHT,
1672 parentHttpChannel);
1673 if (isAuthorization) {
1674 glean::network::cors_authorization_header.Get("disallowed"_ns).Add(1);
1675 }
1676 return NS_ERROR_DOM_BAD_URI;
1677 }
1678 }
1679
1680 if (authorizationInPreflightHeaders && !authorizationCoveredByWildcard) {
1681 glean::network::cors_authorization_header.Get("allowed"_ns).Add(1);
1682 }
1683
1684 return NS_OK;
1685}
1686
1687NS_IMETHODIMPnsresult
1688nsCORSPreflightListener::GetInterface(const nsIID& aIID, void** aResult) {
1689 if (aIID.Equals(NS_GET_IID(nsILoadContext)(nsILoadContext::kIID)) && mLoadContext) {
1690 nsCOMPtr<nsILoadContext> copy = mLoadContext;
1691 copy.forget(aResult);
1692 return NS_OK;
1693 }
1694
1695 return QueryInterface(aIID, aResult);
1696}
1697
1698void nsCORSListenerProxy::RemoveFromCorsPreflightCache(
1699 nsIURI* aURI, nsIPrincipal* aRequestingPrincipal,
1700 const OriginAttributes& aOriginAttributes) {
1701 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1701); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { MOZ_CrashSequence(__null, 1701); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1702 if (sPreflightCache) {
1703 sPreflightCache->RemoveEntries(aURI, aRequestingPrincipal,
1704 aOriginAttributes);
1705 }
1706}
1707
1708// static
1709nsresult nsCORSListenerProxy::StartCORSPreflight(
1710 nsIChannel* aRequestChannel, nsICorsPreflightCallback* aCallback,
1711 nsTArray<nsCString>& aUnsafeHeaders, nsIChannel** aPreflightChannel) {
1712 *aPreflightChannel = nullptr;
1713
1714 if (StaticPrefs::content_cors_disable()) {
1715 nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequestChannel);
1716 LogBlockedRequest(aRequestChannel, "CORSDisabled", nullptr,
1717 nsILoadInfo::BLOCKING_REASON_CORSDISABLED, http);
1718 return NS_ERROR_DOM_BAD_URI;
1719 }
1720
1721 nsAutoCString method;
1722 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequestChannel));
1723 NS_ENSURE_TRUE(httpChannel, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(httpChannel)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "httpChannel" ") failed"
, nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1723); return NS_ERROR_UNEXPECTED; } } while (false)
;
1724 (void)httpChannel->GetRequestMethod(method);
1725
1726 nsCOMPtr<nsIURI> uri;
1727 nsresult rv = NS_GetFinalChannelURI(aRequestChannel, getter_AddRefs(uri));
1728 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1728); return rv; } } while (false)
;
1729
1730 nsCOMPtr<nsILoadInfo> originalLoadInfo = aRequestChannel->LoadInfo();
1731 MOZ_ASSERT(originalLoadInfo->GetSecurityMode() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(originalLoadInfo->GetSecurityMode() == nsILoadInfo
::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(originalLoadInfo->GetSecurityMode
() == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("originalLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT"
" (" "how did we end up here?" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1733); AnnotateMozCrashReason("MOZ_ASSERT" "(" "originalLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT"
") (" "how did we end up here?" ")"); do { MOZ_CrashSequence
(__null, 1733); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1732 nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(originalLoadInfo->GetSecurityMode() == nsILoadInfo
::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(originalLoadInfo->GetSecurityMode
() == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("originalLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT"
" (" "how did we end up here?" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1733); AnnotateMozCrashReason("MOZ_ASSERT" "(" "originalLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT"
") (" "how did we end up here?" ")"); do { MOZ_CrashSequence
(__null, 1733); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1733 "how did we end up here?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(originalLoadInfo->GetSecurityMode() == nsILoadInfo
::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(originalLoadInfo->GetSecurityMode
() == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("originalLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT"
" (" "how did we end up here?" ")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1733); AnnotateMozCrashReason("MOZ_ASSERT" "(" "originalLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT"
") (" "how did we end up here?" ")"); do { MOZ_CrashSequence
(__null, 1733); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1734
1735 nsCOMPtr<nsIPrincipal> principal = originalLoadInfo->GetLoadingPrincipal();
1736 MOZ_ASSERT(principal && originalLoadInfo->GetExternalContentPolicyType() !=do { static_assert( mozilla::detail::AssertionConditionType<
decltype(principal && originalLoadInfo->GetExternalContentPolicyType
() != ExtContentPolicy::TYPE_DOCUMENT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(principal && originalLoadInfo
->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"principal && originalLoadInfo->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT"
" (" "Should not do CORS loads for top-level loads, so a " "loadingPrincipal should always exist."
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1739); AnnotateMozCrashReason("MOZ_ASSERT" "(" "principal && originalLoadInfo->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT"
") (" "Should not do CORS loads for top-level loads, so a " "loadingPrincipal should always exist."
")"); do { MOZ_CrashSequence(__null, 1739); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1737 ExtContentPolicy::TYPE_DOCUMENT,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(principal && originalLoadInfo->GetExternalContentPolicyType
() != ExtContentPolicy::TYPE_DOCUMENT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(principal && originalLoadInfo
->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"principal && originalLoadInfo->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT"
" (" "Should not do CORS loads for top-level loads, so a " "loadingPrincipal should always exist."
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1739); AnnotateMozCrashReason("MOZ_ASSERT" "(" "principal && originalLoadInfo->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT"
") (" "Should not do CORS loads for top-level loads, so a " "loadingPrincipal should always exist."
")"); do { MOZ_CrashSequence(__null, 1739); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1738 "Should not do CORS loads for top-level loads, so a "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(principal && originalLoadInfo->GetExternalContentPolicyType
() != ExtContentPolicy::TYPE_DOCUMENT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(principal && originalLoadInfo
->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"principal && originalLoadInfo->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT"
" (" "Should not do CORS loads for top-level loads, so a " "loadingPrincipal should always exist."
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1739); AnnotateMozCrashReason("MOZ_ASSERT" "(" "principal && originalLoadInfo->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT"
") (" "Should not do CORS loads for top-level loads, so a " "loadingPrincipal should always exist."
")"); do { MOZ_CrashSequence(__null, 1739); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1739 "loadingPrincipal should always exist.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(principal && originalLoadInfo->GetExternalContentPolicyType
() != ExtContentPolicy::TYPE_DOCUMENT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(principal && originalLoadInfo
->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"principal && originalLoadInfo->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT"
" (" "Should not do CORS loads for top-level loads, so a " "loadingPrincipal should always exist."
")", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1739); AnnotateMozCrashReason("MOZ_ASSERT" "(" "principal && originalLoadInfo->GetExternalContentPolicyType() != ExtContentPolicy::TYPE_DOCUMENT"
") (" "Should not do CORS loads for top-level loads, so a " "loadingPrincipal should always exist."
")"); do { MOZ_CrashSequence(__null, 1739); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1740 bool withCredentials =
1741 originalLoadInfo->GetCookiePolicy() == nsILoadInfo::SEC_COOKIES_INCLUDE;
1742
1743 RefPtr<CORSCacheEntry> entry;
1744
1745 nsLoadFlags loadFlags;
1746 rv = aRequestChannel->GetLoadFlags(&loadFlags);
1747 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1747); return rv; } } while (false)
;
1748
1749 // Disable preflight cache if devtools says so or on other force reloads
1750 bool disableCache = (loadFlags & nsIRequest::LOAD_BYPASS_CACHE);
1751
1752 if (sPreflightCache && !disableCache) {
1753 OriginAttributes attrs;
1754 StoragePrincipalHelper::GetOriginAttributesForNetworkState(aRequestChannel,
1755 attrs);
1756 entry = sPreflightCache->GetEntry(uri, principal, withCredentials, attrs,
1757 false);
1758 }
1759
1760 if (entry && entry->CheckRequest(method, aUnsafeHeaders)) {
1761 aCallback->OnPreflightSucceeded();
1762 return NS_OK;
1763 }
1764
1765 // Either it wasn't cached or the cached result has expired. Build a
1766 // channel for the OPTIONS request.
1767
1768 nsCOMPtr<nsILoadInfo> loadInfo =
1769 static_cast<mozilla::net::LoadInfo*>(originalLoadInfo.get())
1770 ->CloneForNewRequest();
1771 static_cast<mozilla::net::LoadInfo*>(loadInfo.get())->SetIsPreflight();
1772
1773 nsCOMPtr<nsILoadGroup> loadGroup;
1774 rv = aRequestChannel->GetLoadGroup(getter_AddRefs(loadGroup));
1775 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1775); return rv; } } while (false)
;
1776
1777 // We want to give the preflight channel's notification callbacks the same
1778 // load context as the original channel's notification callbacks had. We
1779 // don't worry about a load context provided via the loadgroup here, since
1780 // they have the same loadgroup.
1781 nsCOMPtr<nsIInterfaceRequestor> callbacks;
1782 rv = aRequestChannel->GetNotificationCallbacks(getter_AddRefs(callbacks));
1783 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1783); return rv; } } while (false)
;
1784 nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
1785
1786 // Preflight requests should never be intercepted by service workers and
1787 // are always anonymous.
1788 // NOTE: We ignore CORS checks on synthesized responses (see the CORS
1789 // preflights, then we need to extend the GetResponseSynthesized() check in
1790 // nsCORSListenerProxy::CheckRequestApproved()). If we change our behavior
1791 // here and allow service workers to intercept CORS preflights, then that
1792 // check won't be safe any more.
1793 loadFlags |=
1794 nsIChannel::LOAD_BYPASS_SERVICE_WORKER | nsIRequest::LOAD_ANONYMOUS;
1795
1796 if (StaticPrefs::network_cors_preflight_allow_client_cert()) {
1797 loadFlags |= nsIRequest::LOAD_ANONYMOUS_ALLOW_CLIENT_CERT;
1798 }
1799
1800 nsCOMPtr<nsIChannel> preflightChannel;
1801 rv = NS_NewChannelInternal(getter_AddRefs(preflightChannel), uri, loadInfo,
1802 nullptr, // PerformanceStorage
1803 loadGroup,
1804 nullptr, // aCallbacks
1805 loadFlags);
1806 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1806); return rv; } } while (false)
;
1807
1808 // Set method and headers
1809 nsCOMPtr<nsIHttpChannel> preHttp = do_QueryInterface(preflightChannel);
1810 NS_ASSERTION(preHttp, "Failed to QI to nsIHttpChannel!")do { if (!(preHttp)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to QI to nsIHttpChannel!"
, "preHttp", "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1810); MOZ_PretendNoReturn(); } } while (0)
;
1811
1812 rv = preHttp->SetRequestMethod("OPTIONS"_ns);
1813 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1813); return rv; } } while (false)
;
1814
1815 rv = preHttp->SetRequestHeader("Access-Control-Request-Method"_ns, method,
1816 false);
1817 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1817); return rv; } } while (false)
;
1818
1819 // Set the CORS preflight channel's warning reporter to be the same as the
1820 // requesting channel so that all log messages are able to be reported through
1821 // the warning reporter.
1822 RefPtr<nsHttpChannel> reqCh = do_QueryObject(aRequestChannel);
1823 RefPtr<nsHttpChannel> preCh = do_QueryObject(preHttp);
1824 if (preCh && reqCh) { // there are other implementers of nsIHttpChannel
1825 preCh->SetWarningReporter(reqCh->GetWarningReporter());
1826 }
1827
1828 nsTArray<nsCString> preflightHeaders;
1829 if (!aUnsafeHeaders.IsEmpty()) {
1830 for (uint32_t i = 0; i < aUnsafeHeaders.Length(); ++i) {
1831 preflightHeaders.AppendElement();
1832 ToLowerCase(aUnsafeHeaders[i], preflightHeaders[i]);
1833 }
1834 preflightHeaders.Sort();
1835 nsAutoCString headers;
1836 for (uint32_t i = 0; i < preflightHeaders.Length(); ++i) {
1837 if (i != 0) {
1838 headers += ',';
1839 }
1840 headers += preflightHeaders[i];
1841 }
1842 rv = preHttp->SetRequestHeader("Access-Control-Request-Headers"_ns, headers,
1843 false);
1844 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1844); return rv; } } while (false)
;
1845 }
1846
1847 // Set up listener which will start the original channel
1848 RefPtr<nsCORSPreflightListener> preflightListener =
1849 new nsCORSPreflightListener(principal, aCallback, loadContext,
1850 withCredentials, method, preflightHeaders);
1851
1852 rv = preflightChannel->SetNotificationCallbacks(preflightListener);
1853 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1853); return rv; } } while (false)
;
1854
1855 if (preCh && reqCh) {
1856 // Per https://fetch.spec.whatwg.org/#cors-preflight-fetch step 1, the
1857 // request's referrer and referrer policy should match the original request.
1858 nsCOMPtr<nsIReferrerInfo> referrerInfo;
1859 rv = reqCh->GetReferrerInfo(getter_AddRefs(referrerInfo));
1860 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1860); return rv; } } while (false)
;
1861 if (referrerInfo) {
1862 nsCOMPtr<nsIReferrerInfo> newReferrerInfo =
1863 static_cast<dom::ReferrerInfo*>(referrerInfo.get())->Clone();
1864 rv = preCh->SetReferrerInfo(newReferrerInfo);
1865 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1865); return rv; } } while (false)
;
1866 }
1867 }
1868
1869 // Start preflight
1870 rv = preflightChannel->AsyncOpen(preflightListener);
1871 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, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1871); return rv; } } while (false)
;
1872
1873 // Return newly created preflight channel
1874 preflightChannel.forget(aPreflightChannel);
1875
1876 return NS_OK;
1877}
1878
1879// static
1880void nsCORSListenerProxy::LogBlockedCORSRequest(
1881 uint64_t aInnerWindowID, bool aPrivateBrowsing, bool aFromChromeContext,
1882 const nsAString& aMessage, const nsACString& aCategory, bool aIsWarning) {
1883 nsresult rv = NS_OK;
1884
1885 // Build the error object and log it to the console
1886 nsCOMPtr<nsIConsoleService> console(
1887 mozilla::components::Console::Service(&rv));
1888 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1889 NS_WARNING("Failed to log blocked cross-site request (no console)")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to log blocked cross-site request (no console)"
, nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1889)
;
1890 return;
1891 }
1892
1893 nsCOMPtr<nsIScriptError> scriptError =
1894 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID"@mozilla.org/scripterror;1", &rv);
1895 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1896 NS_WARNING("Failed to log blocked cross-site request (no scriptError)")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to log blocked cross-site request (no scriptError)"
, nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1896)
;
1897 return;
1898 }
1899
1900 uint32_t errorFlag =
1901 aIsWarning ? nsIScriptError::warningFlag : nsIScriptError::errorFlag;
1902
1903 // query innerWindowID and log to web console, otherwise log to
1904 // the error to the browser console.
1905 if (aInnerWindowID > 0) {
1906 rv = scriptError->InitWithSanitizedSource(aMessage,
1907 ""_ns, // sourceName
1908 0, // lineNumber
1909 0, // columnNumber
1910 errorFlag, aCategory,
1911 aInnerWindowID);
1912 } else {
1913 rv = scriptError->Init(aMessage,
1914 ""_ns, // sourceName
1915 0, // lineNumber
1916 0, // columnNumber
1917 errorFlag, aCategory, aPrivateBrowsing,
1918 aFromChromeContext); // From chrome context
1919 }
1920 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1921 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Failed to log blocked cross-site request (scriptError init failed)"
, nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1922)
1922 "Failed to log blocked cross-site request (scriptError init failed)")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to log blocked cross-site request (scriptError init failed)"
, nullptr, "./../../../../netwerk/protocol/http/nsCORSListenerProxy.cpp"
, 1922)
;
1923 return;
1924 }
1925 console->LogMessage(scriptError);
1926}