Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/xhr/./../../../dom/xhr/XMLHttpRequestMainThread.cpp
Warning:line 2853, column 7
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_dom_xhr0.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/dom/xhr -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/xhr -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_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/dom/xhr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/xhr -I /root/firefox-clang/dom/base -I /root/firefox-clang/dom/file -I /root/firefox-clang/netwerk/base -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/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-10-17-231001-351276-1 -x c++ Unified_cpp_dom_xhr0.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 "XMLHttpRequestMainThread.h"
6
7#include <algorithm>
8#ifndef XP_WIN
9# include <unistd.h>
10#endif
11#include "GeckoProfiler.h"
12#include "MultipartBlobImpl.h"
13#include "XMLHttpRequestUpload.h"
14#include "js/ArrayBuffer.h" // JS::{Create,Release}MappedArrayBufferContents,New{,Mapped}ArrayBufferWithContents
15#include "js/JSON.h" // JS_ParseJSON
16#include "js/MemoryFunctions.h"
17#include "js/RootingAPI.h" // JS::{{,Mutable}Handle,Rooted}
18#include "js/Value.h" // JS::{,Undefined}Value
19#include "jsapi.h" // JS_ClearPendingException
20#include "mozilla/AppShutdown.h"
21#include "mozilla/BasePrincipal.h"
22#include "mozilla/CheckedInt.h"
23#include "mozilla/Components.h"
24#include "mozilla/Encoding.h"
25#include "mozilla/EventDispatcher.h"
26#include "mozilla/EventListenerManager.h"
27#include "mozilla/HoldDropJSObjects.h"
28#include "mozilla/LoadContext.h"
29#include "mozilla/LoadInfo.h"
30#include "mozilla/MemoryReporting.h"
31#include "mozilla/Preferences.h"
32#include "mozilla/PreloaderBase.h"
33#include "mozilla/ScopeExit.h"
34#include "mozilla/SpinEventLoopUntil.h"
35#include "mozilla/StaticPrefs_dom.h"
36#include "mozilla/StaticPrefs_network.h"
37#include "mozilla/StaticPrefs_privacy.h"
38#include "mozilla/dom/AutoSuppressEventHandlingAndSuspend.h"
39#include "mozilla/dom/BlobBinding.h"
40#include "mozilla/dom/BlobURLChannel.h"
41#include "mozilla/dom/BlobURLProtocolHandler.h"
42#include "mozilla/dom/DOMString.h"
43#include "mozilla/dom/DocGroup.h"
44#include "mozilla/dom/FetchUtil.h"
45#include "mozilla/dom/File.h"
46#include "mozilla/dom/FileBinding.h"
47#include "mozilla/dom/FileCreatorHelper.h"
48#include "mozilla/dom/FormData.h"
49#include "mozilla/dom/MutableBlobStorage.h"
50#include "mozilla/dom/ProgressEvent.h"
51#include "mozilla/dom/Promise.h"
52#include "mozilla/dom/PromiseNativeHandler.h"
53#include "mozilla/dom/ReferrerInfo.h"
54#include "mozilla/dom/ScriptSettings.h"
55#include "mozilla/dom/URLSearchParams.h"
56#include "mozilla/dom/UserActivation.h"
57#include "mozilla/dom/WorkerError.h"
58#include "mozilla/dom/XMLDocument.h"
59#include "mozilla/dom/XMLHttpRequestBinding.h"
60#include "mozilla/dom/quota/QuotaCommon.h"
61#include "mozilla/glean/DomMetrics.h"
62#include "mozilla/net/ContentRange.h"
63#include "nsAsyncRedirectVerifyHelper.h"
64#include "nsCharSeparatedTokenizer.h"
65#include "nsContentUtils.h"
66#include "nsCycleCollectionParticipant.h"
67#include "nsDataChannel.h"
68#include "nsError.h"
69#include "nsGlobalWindowInner.h"
70#include "nsIAuthPrompt.h"
71#include "nsIAuthPrompt2.h"
72#include "nsIBaseChannel.h"
73#include "nsICachingChannel.h"
74#include "nsIClassOfService.h"
75#include "nsIClassifiedChannel.h"
76#include "nsIContentPolicy.h"
77#include "nsICookieJarSettings.h"
78#include "nsIDOMEventListener.h"
79#include "nsIFileChannel.h"
80#include "nsIHttpChannel.h"
81#include "nsIHttpChannelInternal.h"
82#include "nsIInterfaceRequestorUtils.h"
83#include "nsIJARChannel.h"
84#include "nsIJARURI.h"
85#include "nsILoadGroup.h"
86#include "nsIPermissionManager.h"
87#include "nsIPromptFactory.h"
88#include "nsIScriptError.h"
89#include "nsISupportsPriority.h"
90#include "nsITimedChannel.h"
91#include "nsIURI.h"
92#include "nsIURIMutator.h"
93#include "nsIUploadChannel.h"
94#include "nsIUploadChannel2.h"
95#include "nsIWindowWatcher.h"
96#include "nsMimeTypes.h"
97#include "nsNetUtil.h"
98#include "nsPIDOMWindowInlines.h"
99#include "nsQueryObject.h"
100#include "nsReadableUtils.h"
101#include "nsSandboxFlags.h"
102#include "nsStreamListenerWrapper.h"
103#include "nsStreamUtils.h"
104#include "nsStringStream.h"
105#include "nsThreadUtils.h"
106#include "nsVariant.h"
107#include "nsWrapperCacheInlines.h"
108#include "nsXPCOM.h"
109#include "nsZipArchive.h"
110#include "private/pprio.h"
111#include "xpcpublic.h"
112
113// Undefine the macro of CreateFile to avoid FileCreatorHelper#CreateFile being
114// replaced by FileCreatorHelper#CreateFileW.
115#ifdef CreateFile
116# undef CreateFile
117#endif
118
119extern mozilla::LazyLogModule gXMLHttpRequestLog;
120
121using namespace mozilla::net;
122
123namespace mozilla::dom {
124
125using EventType = XMLHttpRequest::EventType;
126using Events = XMLHttpRequest::Events;
127
128// Maximum size that we'll grow an ArrayBuffer instead of doubling,
129// once doubling reaches this threshold
130const uint32_t XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH = 32 * 1024 * 1024;
131// start at 32k to avoid lots of doubling right at the start
132const uint32_t XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE = 32 * 1024;
133// the maximum Content-Length that we'll preallocate. 1GB. Must fit
134// in an int32_t!
135const int32_t XML_HTTP_REQUEST_MAX_CONTENT_LENGTH_PREALLOCATE =
136 1 * 1024 * 1024 * 1024LL;
137
138constexpr nsLiteralString kLiteralString_readystatechange =
139 u"readystatechange"_ns;
140// constexpr nsLiteralString kLiteralString_xmlhttprequest =
141// u"xmlhttprequest"_ns;
142constexpr nsLiteralString kLiteralString_DOMContentLoaded =
143 u"DOMContentLoaded"_ns;
144constexpr nsLiteralCString kLiteralString_charset = "charset"_ns;
145constexpr nsLiteralCString kLiteralString_UTF_8 = "UTF-8"_ns;
146
147#define NS_PROGRESS_EVENT_INTERVAL50 50
148#define MAX_SYNC_TIMEOUT_WHEN_UNLOADING10000 10000 /* 10 secs */
149
150NS_IMPL_ISUPPORTS(nsXHRParseEndListener, nsIDOMEventListener)MozExternalRefCountType nsXHRParseEndListener::AddRef(void) {
static_assert(!std::is_destructible_v<nsXHRParseEndListener
>, "Reference-counted class " "nsXHRParseEndListener" " 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" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 150
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsXHRParseEndListener" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsXHRParseEndListener" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsXHRParseEndListener\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsXHRParseEndListener\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 150); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsXHRParseEndListener" " not thread-safe"); nsrefcnt count =
++mRefCnt; NS_LogAddRef((this), (count), ("nsXHRParseEndListener"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsXHRParseEndListener::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"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 150)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 150
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsXHRParseEndListener" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsXHRParseEndListener" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsXHRParseEndListener\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsXHRParseEndListener\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 150); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsXHRParseEndListener" " not thread-safe"); const char* const
nametmp = "nsXHRParseEndListener"; nsrefcnt count = --mRefCnt
; NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
nsXHRParseEndListener::QueryInterface(const nsIID& aIID,
void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 150); 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<nsXHRParseEndListener, nsIDOMEventListener
>, int32_t( reinterpret_cast<char*>(static_cast<nsIDOMEventListener
*>((nsXHRParseEndListener*)0x1000)) - reinterpret_cast<
char*>((nsXHRParseEndListener*)0x1000))}, {&mozilla::detail
::kImplementedIID<nsXHRParseEndListener, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIDOMEventListener*>((nsXHRParseEndListener
*)0x1000))) - reinterpret_cast<char*>((nsXHRParseEndListener
*)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; }
151
152class nsResumeTimeoutsEvent : public Runnable {
153 public:
154 explicit nsResumeTimeoutsEvent(nsPIDOMWindowInner* aWindow)
155 : Runnable("dom::nsResumeTimeoutsEvent"), mWindow(aWindow) {}
156
157 NS_IMETHODvirtual nsresult Run() override {
158 mWindow->Resume();
159 return NS_OK;
160 }
161
162 private:
163 nsCOMPtr<nsPIDOMWindowInner> mWindow;
164};
165
166// This helper function adds the given load flags to the request's existing
167// load flags.
168static void AddLoadFlags(nsIRequest* request, nsLoadFlags newFlags) {
169 nsLoadFlags flags;
170 request->GetLoadFlags(&flags);
171 flags |= newFlags;
172 request->SetLoadFlags(flags);
173}
174
175// Returns the window whose event loop a sync XHR from aGlobal must block. For
176// content script sandboxes, this is the window set as the sandboxPrototype.
177static nsPIDOMWindowInner* GetWindowForSyncLoop(nsIGlobalObject* aGlobal) {
178 if (!aGlobal) {
179 return nullptr;
180 }
181 if (nsPIDOMWindowInner* window = aGlobal->GetAsInnerWindow()) {
182 return window;
183 }
184 JS::Rooted<JSObject*> scope(RootingCx(), aGlobal->GetGlobalJSObject());
185 if (!scope) {
186 return nullptr;
187 }
188 AutoJSAPI jsapi;
189 if (!jsapi.Init(scope)) {
190 return nullptr;
191 }
192 return xpc::SandboxWindowOrNull(scope, jsapi.cx());
193}
194
195// We are in a sync event loop.
196#define NOT_CALLABLE_IN_SYNC_SEND_RVif (mFlagSyncLooping || mEventDispatchingSuspended) { aRv.Throw
(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); return;
}
\
197 if (mFlagSyncLooping || mEventDispatchingSuspended) { \
198 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); \
199 return; \
200 }
201
202/////////////////////////////////////////////
203//
204//
205/////////////////////////////////////////////
206
207#ifdef DEBUG1
208
209// In debug mode, annotate WorkerRefs with the name of the function being
210// invoked for increased scrutability. Save the previous value on the stack.
211namespace {
212struct DebugWorkerRefs {
213 Mutex& mMutex;
214 RefPtr<ThreadSafeWorkerRef> mTSWorkerRef;
215 nsCString mPrev;
216
217 DebugWorkerRefs(XMLHttpRequestMainThread& aXHR, const std::string& aStatus)
218 : mMutex(aXHR.mTSWorkerRefMutex) {
219 MutexAutoLock lock(mMutex);
220
221 mTSWorkerRef = aXHR.mTSWorkerRef;
222
223 if (!mTSWorkerRef) {
224 return;
225 }
226
227 MOZ_ASSERT(mTSWorkerRef->Private())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTSWorkerRef->Private())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTSWorkerRef->Private()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mTSWorkerRef->Private()"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 227); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mTSWorkerRef->Private()" ")"); do { MOZ_CrashSequence
(__null, 227); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
228
229 nsCString status(aStatus.c_str());
230 mPrev = GET_WORKERREF_DEBUG_STATUS(mTSWorkerRef->Ref())((mTSWorkerRef->Ref())->DebugGetWorkerRefStatus());
231 SET_WORKERREF_DEBUG_STATUS(mTSWorkerRef->Ref(), status)((mTSWorkerRef->Ref())->DebugSetWorkerRefStatus(status)
)
;
232 }
233
234 ~DebugWorkerRefs() {
235 MutexAutoLock lock(mMutex);
236
237 if (!mTSWorkerRef) {
238 return;
239 }
240
241 MOZ_ASSERT(mTSWorkerRef->Private())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTSWorkerRef->Private())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTSWorkerRef->Private()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mTSWorkerRef->Private()"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 241); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mTSWorkerRef->Private()" ")"); do { MOZ_CrashSequence
(__null, 241); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
242
243 SET_WORKERREF_DEBUG_STATUS(mTSWorkerRef->Ref(), mPrev)((mTSWorkerRef->Ref())->DebugSetWorkerRefStatus(mPrev));
244
245 mTSWorkerRef = nullptr;
246 }
247};
248} // namespace
249
250# define STREAM_STRING(stuff)(((const std::ostringstream&)(std::ostringstream() <<
stuff)) .str())
\
251 (((const std::ostringstream&)(std::ostringstream() << stuff)) \
252 .str()) // NOLINT
253
254# if 1 // Disabling because bug 1855699
255# define DEBUG_WORKERREFSvoid() void()
256# define DEBUG_WORKERREFS1(x)void() void()
257# else
258
259# define DEBUG_WORKERREFSvoid() \
260 DebugWorkerRefs MOZ_UNIQUE_VAR(debugWR__)debugWR__9(*this, __func__)
261
262# define DEBUG_WORKERREFS1(x)void() \
263 DebugWorkerRefs MOZ_UNIQUE_VAR(debugWR__)debugWR__10( \
264 *this, STREAM_STRING(__func__ << ": " << x)(((const std::ostringstream&)(std::ostringstream() <<
__func__ << ": " << x)) .str())
) // NOLINT
265
266# endif
267
268#else
269# define DEBUG_WORKERREFSvoid() void()
270# define DEBUG_WORKERREFS1(x)void() void()
271#endif // DEBUG
272
273bool XMLHttpRequestMainThread::sDontWarnAboutSyncXHR = false;
274
275XMLHttpRequestMainThread::XMLHttpRequestMainThread(
276 nsIGlobalObject* aGlobalObject)
277 : XMLHttpRequest(aGlobalObject),
278#ifdef DEBUG1
279 mTSWorkerRefMutex("Debug WorkerRefs"),
280#endif
281 mResponseBodyDecodedPos(0),
282 mResponseType(XMLHttpRequestResponseType::_empty),
283 mState(XMLHttpRequest_Binding::UNSENT),
284 mFlagSynchronous(false),
285 mFlagAborted(false),
286 mFlagParseBody(false),
287 mFlagSyncLooping(false),
288 mFlagBackgroundRequest(false),
289 mFlagHadUploadListenersOnSend(false),
290 mFlagACwithCredentials(false),
291 mFlagTimedOut(false),
292 mFlagDeleted(false),
293 mFlagSend(false),
294 mUploadTransferred(0),
295 mUploadTotal(0),
296 mUploadComplete(true),
297 mProgressSinceLastProgressEvent(false),
298 mRequestSentTime(0),
299 mTimeoutMilliseconds(0),
300 mErrorLoad(ErrorType::eOK),
301 mErrorLoadDetail(NS_OK),
302 mErrorParsingXML(false),
303 mWaitingForOnStopRequest(false),
304 mProgressTimerIsActive(false),
305 mIsHtml(false),
306 mWarnAboutSyncHtml(false),
307 mLoadTotal(-1),
308 mLoadTransferred(0),
309 mIsSystem(false),
310 mIsAnon(false),
311 mAlreadyGotStopRequest(false),
312 mResultJSON(JS::UndefinedValue()),
313 mArrayBufferBuilder(new ArrayBufferBuilder()),
314 mResultArrayBuffer(nullptr),
315 mIsMappedArrayBuffer(false),
316 mXPCOMifier(nullptr),
317 mEventDispatchingSuspended(false),
318 mEofDecoded(false),
319 mDelayedDoneNotifier(nullptr) {
320 DEBUG_WORKERREFSvoid();
321 mozilla::HoldJSObjects(this);
322}
323
324XMLHttpRequestMainThread::~XMLHttpRequestMainThread() {
325 DEBUG_WORKERREFSvoid();
326 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDelayedDoneNotifier)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDelayedDoneNotifier))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!mDelayedDoneNotifier"
" (" "How can we have mDelayedDoneNotifier, which owns us, in destructor?"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 328)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDelayedDoneNotifier"
") (" "How can we have mDelayedDoneNotifier, which owns us, in destructor?"
")"); do { MOZ_CrashSequence(__null, 328); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
327 !mDelayedDoneNotifier,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDelayedDoneNotifier)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDelayedDoneNotifier))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!mDelayedDoneNotifier"
" (" "How can we have mDelayedDoneNotifier, which owns us, in destructor?"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 328)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDelayedDoneNotifier"
") (" "How can we have mDelayedDoneNotifier, which owns us, in destructor?"
")"); do { MOZ_CrashSequence(__null, 328); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
328 "How can we have mDelayedDoneNotifier, which owns us, in destructor?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDelayedDoneNotifier)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDelayedDoneNotifier))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!mDelayedDoneNotifier"
" (" "How can we have mDelayedDoneNotifier, which owns us, in destructor?"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 328)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDelayedDoneNotifier"
") (" "How can we have mDelayedDoneNotifier, which owns us, in destructor?"
")"); do { MOZ_CrashSequence(__null, 328); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
329
330 mFlagDeleted = true;
331
332 if ((mState == XMLHttpRequest_Binding::OPENED && mFlagSend) ||
333 mState == XMLHttpRequest_Binding::LOADING) {
334 Abort();
335 }
336
337 mParseEndListener = nullptr;
338
339 MOZ_ASSERT(!mFlagSyncLooping, "we rather crash than hang")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mFlagSyncLooping)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mFlagSyncLooping))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mFlagSyncLooping"
" (" "we rather crash than hang" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 339); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mFlagSyncLooping"
") (" "we rather crash than hang" ")"); do { MOZ_CrashSequence
(__null, 339); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
340 mFlagSyncLooping = false;
341
342 mozilla::DropJSObjects(this);
343}
344
345void XMLHttpRequestMainThread::Construct(
346 nsIPrincipal* aPrincipal, nsICookieJarSettings* aCookieJarSettings,
347 bool aForWorker, nsIURI* aBaseURI /* = nullptr */,
348 nsILoadGroup* aLoadGroup /* = nullptr */,
349 PerformanceStorage* aPerformanceStorage /* = nullptr */,
350 nsICSPEventListener* aCSPEventListener /* = nullptr */) {
351 DEBUG_WORKERREFSvoid();
352 MOZ_ASSERT(aPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrincipal))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPrincipal", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 352); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrincipal" ")"
); do { MOZ_CrashSequence(__null, 352); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
353 mPrincipal = aPrincipal;
354 mBaseURI = aBaseURI;
355 mLoadGroup = aLoadGroup;
356 mCookieJarSettings = aCookieJarSettings;
357 mForWorker = aForWorker;
358 mPerformanceStorage = aPerformanceStorage;
359 mCSPEventListener = aCSPEventListener;
360}
361
362void XMLHttpRequestMainThread::InitParameters(bool aAnon, bool aSystem) {
363 DEBUG_WORKERREFSvoid();
364 if (!aAnon && !aSystem) {
365 return;
366 }
367
368 // Check for permissions.
369 // Chrome is always allowed access, so do the permission check only
370 // for non-chrome pages.
371 if (!IsSystemXHR() && aSystem) {
372 nsIGlobalObject* global = GetRelevantGlobal();
373 if (NS_WARN_IF(!global)NS_warn_if_impl(!global, "!global", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 373)
) {
374 SetParameters(aAnon, false);
375 return;
376 }
377
378 nsIPrincipal* principal = global->PrincipalOrNull();
379 if (NS_WARN_IF(!principal)NS_warn_if_impl(!principal, "!principal", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 379)
) {
380 SetParameters(aAnon, false);
381 return;
382 }
383
384 nsCOMPtr<nsIPermissionManager> permMgr =
385 components::PermissionManager::Service();
386 if (NS_WARN_IF(!permMgr)NS_warn_if_impl(!permMgr, "!permMgr", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 386)
) {
387 SetParameters(aAnon, false);
388 return;
389 }
390
391 uint32_t permission;
392 nsresult rv = permMgr->TestPermissionFromPrincipal(
393 principal, "systemXHR"_ns, &permission);
394 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || permission != nsIPermissionManager::ALLOW_ACTION) {
395 SetParameters(aAnon, false);
396 return;
397 }
398 }
399
400 SetParameters(aAnon, aSystem);
401}
402
403void XMLHttpRequestMainThread::SetClientInfoAndController(
404 const ClientInfo& aClientInfo,
405 const Maybe<ServiceWorkerDescriptor>& aController) {
406 mClientInfo.emplace(aClientInfo);
407 mController = aController;
408}
409
410void XMLHttpRequestMainThread::SetAssociatedBrowsingContextID(uint64_t aId) {
411 mAssociatedBrowsingContextID = aId;
412}
413
414void XMLHttpRequestMainThread::ResetResponse() {
415 if (RefPtr<nsXHRParseEndListener> listener = mParseEndListener.forget()) {
416 if (mResponseXML) {
417 if (EventListenerManager* manager =
418 mResponseXML->GetExistingListenerManager()) {
419 manager->RemoveEventListenerByType(listener,
420 kLiteralString_DOMContentLoaded,
421 TrustedEventsAtSystemGroupBubble());
422 }
423 }
424 }
425 mResponseXML = nullptr;
426 mResponseBody.Truncate();
427 TruncateResponseText();
428 mResponseBlobImpl = nullptr;
429 mResponseBlob = nullptr;
430 mBlobStorage = nullptr;
431 mResultArrayBuffer = nullptr;
432 mArrayBufferBuilder = new ArrayBufferBuilder();
433 mResultJSON.setUndefined();
434 mLoadTransferred = 0;
435 mResponseBodyDecodedPos = 0;
436 mEofDecoded = false;
437}
438
439NS_IMPL_CYCLE_COLLECTION_CLASS(XMLHttpRequestMainThread)XMLHttpRequestMainThread::cycleCollection XMLHttpRequestMainThread
::_cycleCollectorGlobal;
440
441NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XMLHttpRequestMainThread,nsresult XMLHttpRequestMainThread::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { XMLHttpRequestMainThread
* tmp = DowncastCCParticipant<XMLHttpRequestMainThread>
(p); nsISupports* s = static_cast<nsISupports*>(p); if (
XMLHttpRequestEventTarget::cycleCollection::TraverseNative(s,
cb) == NS_SUCCESS_INTERRUPTED_TRAVERSE) { return NS_SUCCESS_INTERRUPTED_TRAVERSE
; }
442 XMLHttpRequestEventTarget)nsresult XMLHttpRequestMainThread::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { XMLHttpRequestMainThread
* tmp = DowncastCCParticipant<XMLHttpRequestMainThread>
(p); nsISupports* s = static_cast<nsISupports*>(p); if (
XMLHttpRequestEventTarget::cycleCollection::TraverseNative(s,
cb) == NS_SUCCESS_INTERRUPTED_TRAVERSE) { return NS_SUCCESS_INTERRUPTED_TRAVERSE
; }
443 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)ImplCycleCollectionTraverse(cb, tmp->mChannel, "mChannel",
0);
444 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseXML)ImplCycleCollectionTraverse(cb, tmp->mResponseXML, "mResponseXML"
, 0);
445
446 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXMLParserStreamListener)ImplCycleCollectionTraverse(cb, tmp->mXMLParserStreamListener
, "mXMLParserStreamListener", 0);
447
448 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseBlob)ImplCycleCollectionTraverse(cb, tmp->mResponseBlob, "mResponseBlob"
, 0);
449 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationCallbacks)ImplCycleCollectionTraverse(cb, tmp->mNotificationCallbacks
, "mNotificationCallbacks", 0);
450
451 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannelEventSink)ImplCycleCollectionTraverse(cb, tmp->mChannelEventSink, "mChannelEventSink"
, 0);
452 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProgressEventSink)ImplCycleCollectionTraverse(cb, tmp->mProgressEventSink, "mProgressEventSink"
, 0);
453
454 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUpload)ImplCycleCollectionTraverse(cb, tmp->mUpload, "mUpload", 0
);
455NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END(void)tmp; return NS_OK; }
456
457NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XMLHttpRequestMainThread,void XMLHttpRequestMainThread::cycleCollection::Unlink(void* p
) { XMLHttpRequestMainThread* tmp = DowncastCCParticipant<
XMLHttpRequestMainThread>(p); nsISupports* s = static_cast
<nsISupports*>(p); XMLHttpRequestEventTarget::cycleCollection
::Unlink(s);
458 XMLHttpRequestEventTarget)void XMLHttpRequestMainThread::cycleCollection::Unlink(void* p
) { XMLHttpRequestMainThread* tmp = DowncastCCParticipant<
XMLHttpRequestMainThread>(p); nsISupports* s = static_cast
<nsISupports*>(p); XMLHttpRequestEventTarget::cycleCollection
::Unlink(s);
459 tmp->mResultArrayBuffer = nullptr;
460 tmp->mArrayBufferBuilder = nullptr;
461 tmp->mResultJSON.setUndefined();
462 tmp->mResponseBlobImpl = nullptr;
463
464 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannel)ImplCycleCollectionUnlink(tmp->mChannel);
465 NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseXML)ImplCycleCollectionUnlink(tmp->mResponseXML);
466
467 NS_IMPL_CYCLE_COLLECTION_UNLINK(mXMLParserStreamListener)ImplCycleCollectionUnlink(tmp->mXMLParserStreamListener);
468
469 NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseBlob)ImplCycleCollectionUnlink(tmp->mResponseBlob);
470 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNotificationCallbacks)ImplCycleCollectionUnlink(tmp->mNotificationCallbacks);
471
472 NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannelEventSink)ImplCycleCollectionUnlink(tmp->mChannelEventSink);
473 NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressEventSink)ImplCycleCollectionUnlink(tmp->mProgressEventSink);
474
475 NS_IMPL_CYCLE_COLLECTION_UNLINK(mUpload)ImplCycleCollectionUnlink(tmp->mUpload);
476 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTRtmp->DetachWeakPtr();
477NS_IMPL_CYCLE_COLLECTION_UNLINK_END(void)tmp; }
478
479NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(XMLHttpRequestMainThread,void XMLHttpRequestMainThread::cycleCollection::Trace( void* p
, [[maybe_unused]] const TraceCallbacks& aCallbacks, [[maybe_unused
]] void* aClosure) { XMLHttpRequestMainThread* tmp = DowncastCCParticipant
<XMLHttpRequestMainThread>(p); nsISupports* s = static_cast
<nsISupports*>(p); XMLHttpRequestEventTarget::cycleCollection
::Trace(s, aCallbacks, aClosure);
480 XMLHttpRequestEventTarget)void XMLHttpRequestMainThread::cycleCollection::Trace( void* p
, [[maybe_unused]] const TraceCallbacks& aCallbacks, [[maybe_unused
]] void* aClosure) { XMLHttpRequestMainThread* tmp = DowncastCCParticipant
<XMLHttpRequestMainThread>(p); nsISupports* s = static_cast
<nsISupports*>(p); XMLHttpRequestEventTarget::cycleCollection
::Trace(s, aCallbacks, aClosure);
481 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultArrayBuffer)ImplCycleCollectionTrace(aCallbacks, tmp->mResultArrayBuffer
, "mResultArrayBuffer", aClosure);
482 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultJSON)ImplCycleCollectionTrace(aCallbacks, tmp->mResultJSON, "mResultJSON"
, aClosure);
483NS_IMPL_CYCLE_COLLECTION_TRACE_END(void)tmp; }
484
485bool XMLHttpRequestMainThread::IsCertainlyAliveForCC() const {
486 return mWaitingForOnStopRequest;
487}
488
489// QueryInterface implementation for XMLHttpRequestMainThread
490NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XMLHttpRequestMainThread)nsresult XMLHttpRequestMainThread::QueryInterface(const nsIID
& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 490); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::kIID), (nsCycleCollectionISupports::kIID)) && (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::kIID)) || LowWordEquals
(aIID, (nsCycleCollectionISupports::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::kIID))) { *aInstancePtr
= XMLHttpRequestMainThread::cycleCollection::GetParticipant(
); return NS_OK; } if (LowWordEquals(aIID, (nsCycleCollectionISupports
::kIID))) { *aInstancePtr = XMLHttpRequestMainThread::cycleCollection
::Upcast(this); return NS_OK; } foundInterface = nullptr; } else
491 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIRequestObserver>)) foundInterface
= static_cast<nsIRequestObserver*>(this); else
492 NS_INTERFACE_MAP_ENTRY(nsIStreamListener)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIStreamListener>)) foundInterface
= static_cast<nsIStreamListener*>(this); else
493 NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIChannelEventSink>)) foundInterface
= static_cast<nsIChannelEventSink*>(this); else
494 NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIProgressEventSink>)) foundInterface
= static_cast<nsIProgressEventSink*>(this); else
495 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIInterfaceRequestor>)) foundInterface
= static_cast<nsIInterfaceRequestor*>(this); else
496 NS_INTERFACE_MAP_ENTRY(nsITimerCallback)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsITimerCallback>)) foundInterface
= static_cast<nsITimerCallback*>(this); else
497 NS_INTERFACE_MAP_ENTRY(nsINamed)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsINamed>)) foundInterface = static_cast
<nsINamed*>(this); else
498 NS_INTERFACE_MAP_ENTRY(nsISizeOfEventTarget)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISizeOfEventTarget>)) foundInterface
= static_cast<nsISizeOfEventTarget*>(this); else
499NS_INTERFACE_MAP_END_INHERITING(XMLHttpRequestEventTarget)foundInterface = 0; nsresult status; if (!foundInterface) status
= XMLHttpRequestEventTarget::QueryInterface(aIID, (void**)&
foundInterface); else { (foundInterface)->AddRef(); status
= NS_OK; } *aInstancePtr = foundInterface; return status; }
500
501NS_IMPL_ADDREF_INHERITED(XMLHttpRequestMainThread, XMLHttpRequestEventTarget)MozExternalRefCountType XMLHttpRequestMainThread::AddRef(void
) { static_assert(!std::is_destructible_v<XMLHttpRequestMainThread
>, "Reference-counted class " "XMLHttpRequestMainThread" " should not have a public destructor. "
"Make this class's destructor non-public"); nsrefcnt r = XMLHttpRequestEventTarget
::AddRef(); if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt
<XMLHttpRequestMainThread>) { NS_LogAddRef((this), (r),
("XMLHttpRequestMainThread"), (uint32_t)(sizeof(*this))); } return
r; }
502NS_IMPL_RELEASE_INHERITED(XMLHttpRequestMainThread, XMLHttpRequestEventTarget)MozExternalRefCountType XMLHttpRequestMainThread::Release(void
) { nsrefcnt r = XMLHttpRequestEventTarget::Release(); if constexpr
(::mozilla::detail::ShouldLogInheritedRefcnt<XMLHttpRequestMainThread
>) { NS_LogRelease((this), (r), ("XMLHttpRequestMainThread"
)); } return r; }
503
504void XMLHttpRequestMainThread::DisconnectFromOwner() {
505 XMLHttpRequestEventTarget::DisconnectFromOwner();
506 // Worker-owned XHRs have their own complicated state machine that does not
507 // expect Abort() to be called here. The worker state machine cleanup will
508 // take care of ensuring the XHR is aborted in a timely fashion since the
509 // worker itself will inherently be canceled at the same time this is
510 // happening.
511 if (!mForWorker) {
512 Abort();
513 }
514}
515
516size_t XMLHttpRequestMainThread::SizeOfEventTargetIncludingThis(
517 MallocSizeOf aMallocSizeOf) const {
518 size_t n = aMallocSizeOf(this);
519 n += mResponseBody.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
520
521 // Why is this safe? Because no-one else will report this string. The
522 // other possible sharers of this string are as follows.
523 //
524 // - The JS engine could hold copies if the JS code holds references, e.g.
525 // |var text = XHR.responseText|. However, those references will be via JS
526 // external strings, for which the JS memory reporter does *not* report the
527 // chars.
528 //
529 // - Binary extensions, but they're *extremely* unlikely to do any memory
530 // reporting.
531 //
532 n += mResponseText.SizeOfThis(aMallocSizeOf);
533
534 return n;
535
536 // Measurement of the following members may be added later if DMD finds it is
537 // worthwhile:
538 // - lots
539}
540
541static void LogMessage(
542 const char* aWarning, nsPIDOMWindowInner* aWindow,
543 const nsTArray<nsString>& aParams = nsTArray<nsString>()) {
544 nsCOMPtr<Document> doc;
545 if (aWindow) {
546 doc = aWindow->GetExtantDoc();
547 }
548 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns, doc,
549 PropertiesFile::DOM_PROPERTIES, aWarning,
550 aParams);
551}
552
553Document* XMLHttpRequestMainThread::GetResponseXML(ErrorResult& aRv) {
554 if (mResponseType != XMLHttpRequestResponseType::_empty &&
555 mResponseType != XMLHttpRequestResponseType::Document) {
556 aRv.ThrowInvalidStateError(
557 "responseXML is only available if responseType is '' or 'document'.");
558 return nullptr;
559 }
560 if (mWarnAboutSyncHtml) {
561 mWarnAboutSyncHtml = false;
562 LogMessage("HTMLSyncXHRWarning", GetOwnerWindow());
563 }
564 if (mState != XMLHttpRequest_Binding::DONE) {
565 return nullptr;
566 }
567 return mResponseXML;
568}
569
570/*
571 * This piece copied from XMLDocument, we try to get the charset
572 * from HTTP headers.
573 */
574nsresult XMLHttpRequestMainThread::DetectCharset() {
575 DEBUG_WORKERREFSvoid();
576 mDecoder = nullptr;
577
578 if (mResponseType != XMLHttpRequestResponseType::_empty &&
579 mResponseType != XMLHttpRequestResponseType::Text &&
580 mResponseType != XMLHttpRequestResponseType::Json) {
581 return NS_OK;
582 }
583
584 nsAutoCString charsetVal;
585 const Encoding* encoding;
586 bool ok = mChannel && NS_SUCCEEDED(mChannel->GetContentCharset(charsetVal))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mChannel->GetContentCharset
(charsetVal))), 1)))
&&
587 (encoding = Encoding::ForLabel(charsetVal));
588 if (!ok) {
589 // MS documentation states UTF-8 is default for responseText
590 encoding = UTF_8_ENCODING;
591 }
592
593 if (mResponseType == XMLHttpRequestResponseType::Json &&
594 encoding != UTF_8_ENCODING) {
595 // The XHR spec says only UTF-8 is supported for responseType == "json"
596 LogMessage("JSONCharsetWarning", GetOwnerWindow());
597 encoding = UTF_8_ENCODING;
598 }
599
600 // Only sniff the BOM for non-JSON responseTypes
601 if (mResponseType == XMLHttpRequestResponseType::Json) {
602 mDecoder = encoding->NewDecoderWithBOMRemoval();
603 } else {
604 mDecoder = encoding->NewDecoder();
605 }
606
607 return NS_OK;
608}
609
610nsresult XMLHttpRequestMainThread::AppendToResponseText(
611 Span<const uint8_t> aBuffer, bool aLast) {
612 // Call this with an empty buffer to send the decoder the signal
613 // that we have hit the end of the stream.
614
615 NS_ENSURE_STATE(mDecoder)do { if ((__builtin_expect(!!(!(mDecoder)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDecoder" ") failed", nullptr
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 615); return
NS_ERROR_UNEXPECTED; } } while (false)
;
616
617 CheckedInt<size_t> destBufferLen =
618 mDecoder->MaxUTF16BufferLength(aBuffer.Length());
619
620 { // scope for holding the mutex that protects mResponseText
621 XMLHttpRequestStringWriterHelper helper(mResponseText);
622
623 uint32_t len = helper.Length();
624
625 destBufferLen += len;
626 if (!destBufferLen.isValid() || destBufferLen.value() > UINT32_MAX(4294967295U)) {
627 return NS_ERROR_OUT_OF_MEMORY;
628 }
629
630 auto handleOrErr = helper.BulkWrite(destBufferLen.value());
631 if (handleOrErr.isErr()) {
632 return handleOrErr.unwrapErr();
633 }
634
635 auto handle = handleOrErr.unwrap();
636
637 uint32_t result;
638 size_t read;
639 size_t written;
640 std::tie(result, read, written, std::ignore) =
641 mDecoder->DecodeToUTF16(aBuffer, handle.AsSpan().From(len), aLast);
642 MOZ_ASSERT(result == kInputEmpty)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(result == kInputEmpty)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(result == kInputEmpty))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("result == kInputEmpty"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 642); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "result == kInputEmpty" ")"); do { MOZ_CrashSequence
(__null, 642); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
643 MOZ_ASSERT(read == aBuffer.Length())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(read == aBuffer.Length())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(read == aBuffer.Length()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("read == aBuffer.Length()"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 643); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "read == aBuffer.Length()" ")"); do { MOZ_CrashSequence
(__null, 643); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
644 len += written;
645 MOZ_ASSERT(len <= destBufferLen.value())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(len <= destBufferLen.value())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(len <= destBufferLen.value
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("len <= destBufferLen.value()", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 645); AnnotateMozCrashReason("MOZ_ASSERT" "(" "len <= destBufferLen.value()"
")"); do { MOZ_CrashSequence(__null, 645); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
646 handle.Finish(len, false);
647 } // release mutex
648
649 if (aLast) {
650 // Drop the finished decoder to avoid calling into a decoder
651 // that has finished.
652 mDecoder = nullptr;
653 mEofDecoded = true;
654 }
655 return NS_OK;
656}
657
658void XMLHttpRequestMainThread::GetResponseText(DOMString& aResponseText,
659 ErrorResult& aRv) {
660 MOZ_DIAGNOSTIC_ASSERT(!mForWorker)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mForWorker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mForWorker))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mForWorker", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 660); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mForWorker"
")"); do { MOZ_CrashSequence(__null, 660); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
661
662 XMLHttpRequestStringSnapshot snapshot;
663 GetResponseText(snapshot, aRv);
664 if (aRv.Failed()) {
665 return;
666 }
667
668 if (!snapshot.GetAsString(aResponseText)) {
669 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
670 return;
671 }
672}
673
674void XMLHttpRequestMainThread::GetResponseText(
675 XMLHttpRequestStringSnapshot& aSnapshot, ErrorResult& aRv) {
676 aSnapshot.Reset();
677
678 if (mResponseType != XMLHttpRequestResponseType::_empty &&
679 mResponseType != XMLHttpRequestResponseType::Text) {
680 aRv.ThrowInvalidStateError(
681 "responseText is only available if responseType is '' or 'text'.");
682 return;
683 }
684
685 if (mState != XMLHttpRequest_Binding::LOADING &&
686 mState != XMLHttpRequest_Binding::DONE) {
687 return;
688 }
689
690 // Main Fetch step 18 requires to ignore body for head/connect methods.
691 if (mRequestMethod.EqualsLiteral("HEAD") ||
692 mRequestMethod.EqualsLiteral("CONNECT")) {
693 return;
694 }
695
696 // We only decode text lazily if we're also parsing to a doc.
697 // Also, if we've decoded all current data already, then no need to decode
698 // more.
699 if ((!mResponseXML && !mErrorParsingXML) ||
700 (mResponseBodyDecodedPos == mResponseBody.Length() &&
701 (mState != XMLHttpRequest_Binding::DONE || mEofDecoded))) {
702 mResponseText.CreateSnapshot(aSnapshot);
703 return;
704 }
705
706 MatchCharsetAndDecoderToResponseDocument();
707
708 MOZ_ASSERT(mResponseBodyDecodedPos < mResponseBody.Length() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mResponseBodyDecodedPos < mResponseBody.Length() ||
mState == XMLHttpRequest_Binding::DONE)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mResponseBodyDecodedPos <
mResponseBody.Length() || mState == XMLHttpRequest_Binding::
DONE))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mResponseBodyDecodedPos < mResponseBody.Length() || mState == XMLHttpRequest_Binding::DONE"
" (" "Unexpected mResponseBodyDecodedPos" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 710); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mResponseBodyDecodedPos < mResponseBody.Length() || mState == XMLHttpRequest_Binding::DONE"
") (" "Unexpected mResponseBodyDecodedPos" ")"); do { MOZ_CrashSequence
(__null, 710); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
709 mState == XMLHttpRequest_Binding::DONE,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mResponseBodyDecodedPos < mResponseBody.Length() ||
mState == XMLHttpRequest_Binding::DONE)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mResponseBodyDecodedPos <
mResponseBody.Length() || mState == XMLHttpRequest_Binding::
DONE))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mResponseBodyDecodedPos < mResponseBody.Length() || mState == XMLHttpRequest_Binding::DONE"
" (" "Unexpected mResponseBodyDecodedPos" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 710); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mResponseBodyDecodedPos < mResponseBody.Length() || mState == XMLHttpRequest_Binding::DONE"
") (" "Unexpected mResponseBodyDecodedPos" ")"); do { MOZ_CrashSequence
(__null, 710); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
710 "Unexpected mResponseBodyDecodedPos")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mResponseBodyDecodedPos < mResponseBody.Length() ||
mState == XMLHttpRequest_Binding::DONE)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mResponseBodyDecodedPos <
mResponseBody.Length() || mState == XMLHttpRequest_Binding::
DONE))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mResponseBodyDecodedPos < mResponseBody.Length() || mState == XMLHttpRequest_Binding::DONE"
" (" "Unexpected mResponseBodyDecodedPos" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 710); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mResponseBodyDecodedPos < mResponseBody.Length() || mState == XMLHttpRequest_Binding::DONE"
") (" "Unexpected mResponseBodyDecodedPos" ")"); do { MOZ_CrashSequence
(__null, 710); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
711 Span<const uint8_t> span = mResponseBody;
712 aRv = AppendToResponseText(span.From(mResponseBodyDecodedPos),
713 mState == XMLHttpRequest_Binding::DONE);
714 if (aRv.Failed()) {
715 return;
716 }
717
718 mResponseBodyDecodedPos = mResponseBody.Length();
719
720 if (mEofDecoded) {
721 // Free memory buffer which we no longer need
722 mResponseBody.Truncate();
723 mResponseBodyDecodedPos = 0;
724 }
725
726 mResponseText.CreateSnapshot(aSnapshot);
727}
728
729nsresult XMLHttpRequestMainThread::CreateResponseParsedJSON(JSContext* aCx) {
730 if (!aCx) {
731 return NS_ERROR_FAILURE;
732 }
733
734 nsAutoString string;
735 nsresult rv = GetResponseTextForJSON(string);
736 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 736)
) {
737 return rv;
738 }
739
740 // The Unicode converter has already zapped the BOM if there was one
741 JS::Rooted<JS::Value> value(aCx);
742 if (!JS_ParseJSON(aCx, string.BeginReading(), string.Length(), &value)) {
743 return NS_ERROR_FAILURE;
744 }
745
746 mResultJSON = value;
747 return NS_OK;
748}
749
750void XMLHttpRequestMainThread::SetResponseType(
751 XMLHttpRequestResponseType aResponseType, ErrorResult& aRv) {
752 NOT_CALLABLE_IN_SYNC_SEND_RVif (mFlagSyncLooping || mEventDispatchingSuspended) { aRv.Throw
(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); return;
}
753
754 if (mState == XMLHttpRequest_Binding::LOADING ||
755 mState == XMLHttpRequest_Binding::DONE) {
756 aRv.ThrowInvalidStateError(
757 "Cannot set 'responseType' property on XMLHttpRequest after 'send()' "
758 "(when its state is LOADING or DONE).");
759 return;
760 }
761
762 // sync request is not allowed setting responseType in window context
763 if (HasOrHasHadOwnerWindow() && mState != XMLHttpRequest_Binding::UNSENT &&
764 mFlagSynchronous) {
765 LogMessage("ResponseTypeSyncXHRWarning", GetOwnerWindow());
766 aRv.ThrowInvalidAccessError(
767 "synchronous XMLHttpRequests do not support timeout and responseType");
768 return;
769 }
770
771 // Set the responseType attribute's value to the given value.
772 SetResponseTypeRaw(aResponseType);
773}
774
775void XMLHttpRequestMainThread::GetResponse(
776 JSContext* aCx, JS::MutableHandle<JS::Value> aResponse, ErrorResult& aRv) {
777 MOZ_DIAGNOSTIC_ASSERT(!mForWorker)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mForWorker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mForWorker))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mForWorker", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 777); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mForWorker"
")"); do { MOZ_CrashSequence(__null, 777); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
778
779 switch (mResponseType) {
780 case XMLHttpRequestResponseType::_empty:
781 case XMLHttpRequestResponseType::Text: {
782 DOMString str;
783 GetResponseText(str, aRv);
784 if (aRv.Failed()) {
785 return;
786 }
787 if (!xpc::StringToJsval(aCx, str, aResponse)) {
788 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
789 }
790 return;
791 }
792
793 case XMLHttpRequestResponseType::Arraybuffer: {
794 if (mState != XMLHttpRequest_Binding::DONE) {
795 aResponse.setNull();
796 return;
797 }
798
799 if (!mResultArrayBuffer) {
800 mResultArrayBuffer = mArrayBufferBuilder->TakeArrayBuffer(aCx);
801 if (!mResultArrayBuffer) {
802 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
803 return;
804 }
805 }
806 aResponse.setObject(*mResultArrayBuffer);
807 return;
808 }
809 case XMLHttpRequestResponseType::Blob: {
810 if (mState != XMLHttpRequest_Binding::DONE) {
811 aResponse.setNull();
812 return;
813 }
814
815 if (!mResponseBlobImpl) {
816 aResponse.setNull();
817 return;
818 }
819
820 if (!mResponseBlob) {
821 mResponseBlob = Blob::Create(GetRelevantGlobal(), mResponseBlobImpl);
822 }
823
824 if (!GetOrCreateDOMReflector(aCx, mResponseBlob, aResponse)) {
825 aResponse.setNull();
826 }
827
828 return;
829 }
830 case XMLHttpRequestResponseType::Document: {
831 if (!mResponseXML || mState != XMLHttpRequest_Binding::DONE) {
832 aResponse.setNull();
833 return;
834 }
835
836 aRv =
837 nsContentUtils::WrapNative(aCx, ToSupports(mResponseXML), aResponse);
838 return;
839 }
840 case XMLHttpRequestResponseType::Json: {
841 if (mState != XMLHttpRequest_Binding::DONE) {
842 aResponse.setNull();
843 return;
844 }
845
846 if (mResultJSON.isUndefined()) {
847 aRv = CreateResponseParsedJSON(aCx);
848 TruncateResponseText();
849 if (aRv.Failed()) {
850 // Per spec, errors aren't propagated. null is returned instead.
851 aRv = NS_OK;
852 // It would be nice to log the error to the console. That's hard to
853 // do without calling window.onerror as a side effect, though.
854 JS_ClearPendingException(aCx);
855 mResultJSON.setNull();
856 }
857 }
858 aResponse.set(mResultJSON);
859 return;
860 }
861 default:
862 NS_ERROR("Should not happen")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Should not happen", "Error"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 862); MOZ_PretendNoReturn
(); } while (0)
;
863 }
864
865 aResponse.setNull();
866}
867
868already_AddRefed<BlobImpl> XMLHttpRequestMainThread::GetResponseBlobImpl() {
869 MOZ_DIAGNOSTIC_ASSERT(mForWorker)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mForWorker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mForWorker))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mForWorker", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 869); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mForWorker"
")"); do { MOZ_CrashSequence(__null, 869); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
870 MOZ_DIAGNOSTIC_ASSERT(mResponseType == XMLHttpRequestResponseType::Blob)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mResponseType == XMLHttpRequestResponseType::Blob)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mResponseType == XMLHttpRequestResponseType::Blob)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mResponseType == XMLHttpRequestResponseType::Blob"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 870); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "mResponseType == XMLHttpRequestResponseType::Blob"
")"); do { MOZ_CrashSequence(__null, 870); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
871
872 if (mState != XMLHttpRequest_Binding::DONE) {
873 return nullptr;
874 }
875
876 RefPtr<BlobImpl> blobImpl = mResponseBlobImpl;
877 return blobImpl.forget();
878}
879
880already_AddRefed<ArrayBufferBuilder>
881XMLHttpRequestMainThread::GetResponseArrayBufferBuilder() {
882 MOZ_DIAGNOSTIC_ASSERT(mForWorker)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mForWorker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mForWorker))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mForWorker", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 882); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mForWorker"
")"); do { MOZ_CrashSequence(__null, 882); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
883 MOZ_DIAGNOSTIC_ASSERT(mResponseType ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mResponseType == XMLHttpRequestResponseType::Arraybuffer
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mResponseType == XMLHttpRequestResponseType::Arraybuffer
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mResponseType == XMLHttpRequestResponseType::Arraybuffer", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 884); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mResponseType == XMLHttpRequestResponseType::Arraybuffer"
")"); do { MOZ_CrashSequence(__null, 884); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
884 XMLHttpRequestResponseType::Arraybuffer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mResponseType == XMLHttpRequestResponseType::Arraybuffer
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mResponseType == XMLHttpRequestResponseType::Arraybuffer
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mResponseType == XMLHttpRequestResponseType::Arraybuffer", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 884); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mResponseType == XMLHttpRequestResponseType::Arraybuffer"
")"); do { MOZ_CrashSequence(__null, 884); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
885
886 if (mState != XMLHttpRequest_Binding::DONE) {
887 return nullptr;
888 }
889
890 RefPtr<ArrayBufferBuilder> builder = mArrayBufferBuilder;
891 return builder.forget();
892}
893
894nsresult XMLHttpRequestMainThread::GetResponseTextForJSON(nsAString& aString) {
895 if (mState != XMLHttpRequest_Binding::DONE) {
896 aString.SetIsVoid(true);
897 return NS_OK;
898 }
899
900 if (!mResponseText.GetAsString(aString)) {
901 return NS_ERROR_OUT_OF_MEMORY;
902 }
903
904 return NS_OK;
905}
906
907bool XMLHttpRequestMainThread::IsCrossSiteCORSRequest() const {
908 if (!mChannel) {
909 return false;
910 }
911
912 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
913 return loadInfo->GetTainting() == LoadTainting::CORS;
914}
915
916bool XMLHttpRequestMainThread::IsDeniedCrossSiteCORSRequest() {
917 if (IsCrossSiteCORSRequest()) {
918 nsresult rv;
919 mChannel->GetStatus(&rv);
920 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
921 return true;
922 }
923 }
924 return false;
925}
926
927bool XMLHttpRequestMainThread::BadContentRangeRequested() {
928 if (!mChannel) {
929 return false;
930 }
931 // Only BlobURLChannel supports this
932 RefPtr<BlobURLChannel> blobChan = do_QueryObject(mChannel);
933 if (!blobChan) {
934 return false;
935 }
936 // A bad range was requested if the channel has no content range
937 // despite the request specifying a range header.
938 return !blobChan->GetResponseContentRange() &&
939 mAuthorRequestHeaders.Has("range");
940}
941
942RefPtr<mozilla::net::ContentRange>
943XMLHttpRequestMainThread::GetRequestedContentRange() const {
944 MOZ_ASSERT(mChannel)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChannel)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mChannel))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mChannel", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 944); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel" ")"
); do { MOZ_CrashSequence(__null, 944); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
945 RefPtr<BlobURLChannel> blobChan = do_QueryObject(mChannel);
946 if (!blobChan) {
947 return nullptr;
948 }
949 return blobChan->GetResponseContentRange();
950}
951
952void XMLHttpRequestMainThread::GetContentRangeHeader(nsACString& out) const {
953 if (!IsBlobURI(mRequestURL)) {
954 out.SetIsVoid(true);
955 return;
956 }
957 RefPtr<mozilla::net::ContentRange> range = GetRequestedContentRange();
958 if (range) {
959 range->AsHeader(out);
960 } else {
961 out.SetIsVoid(true);
962 }
963}
964
965void XMLHttpRequestMainThread::GetResponseURL(nsACString& aUrl) {
966 aUrl.Truncate();
967
968 if ((mState == XMLHttpRequest_Binding::UNSENT ||
969 mState == XMLHttpRequest_Binding::OPENED) ||
970 !mChannel) {
971 return;
972 }
973
974 // Make sure we don't leak responseURL information from denied cross-site
975 // requests.
976 if (IsDeniedCrossSiteCORSRequest()) {
977 return;
978 }
979
980 nsCOMPtr<nsIURI> responseUrl;
981 if (NS_FAILED(NS_GetFinalChannelURI(mChannel, getter_AddRefs(responseUrl)))((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_GetFinalChannelURI
(mChannel, getter_AddRefs(responseUrl)))), 0)))
) {
982 return;
983 }
984
985 responseUrl->GetSpecIgnoringRef(aUrl);
986}
987
988uint32_t XMLHttpRequestMainThread::GetStatus(ErrorResult& aRv) {
989 // Make sure we don't leak status information from denied cross-site
990 // requests.
991 if (IsDeniedCrossSiteCORSRequest()) {
992 return 0;
993 }
994
995 if (mState == XMLHttpRequest_Binding::UNSENT ||
996 mState == XMLHttpRequest_Binding::OPENED) {
997 return 0;
998 }
999
1000 if (mErrorLoad != ErrorType::eOK) {
1001 // Let's simulate the http protocol for jar/app requests:
1002 nsCOMPtr<nsIJARChannel> jarChannel = GetCurrentJARChannel();
1003 if (jarChannel) {
1004 nsresult status;
1005 mChannel->GetStatus(&status);
1006
1007 if (status == NS_ERROR_FILE_NOT_FOUND) {
1008 return 404; // Not Found
1009 } else {
1010 return 500; // Internal Error
1011 }
1012 }
1013
1014 return 0;
1015 }
1016
1017 nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
1018 if (!httpChannel) {
1019 // Pretend like we got a 200/206 response, since our load was successful
1020 return GetRequestedContentRange() ? 206 : 200;
1021 }
1022
1023 uint32_t status;
1024 nsresult rv = httpChannel->GetResponseStatus(&status);
1025 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1026 status = 0;
1027 }
1028
1029 return status;
1030}
1031
1032void XMLHttpRequestMainThread::GetStatusText(nsACString& aStatusText,
1033 ErrorResult& aRv) {
1034 // Return an empty status text on all error loads.
1035 aStatusText.Truncate();
1036
1037 // Make sure we don't leak status information from denied cross-site
1038 // requests.
1039 if (IsDeniedCrossSiteCORSRequest()) {
1040 return;
1041 }
1042
1043 // Check the current XHR state to see if it is valid to obtain the statusText
1044 // value. This check is to prevent the status text for redirects from being
1045 // available before all the redirects have been followed and HTTP headers have
1046 // been received.
1047 if (mState == XMLHttpRequest_Binding::UNSENT ||
1048 mState == XMLHttpRequest_Binding::OPENED) {
1049 return;
1050 }
1051
1052 if (mErrorLoad != ErrorType::eOK) {
1053 return;
1054 }
1055
1056 nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
1057 if (httpChannel) {
1058 (void)httpChannel->GetResponseStatusText(aStatusText);
1059 } else {
1060 aStatusText.AssignLiteral("OK");
1061 }
1062}
1063
1064void XMLHttpRequestMainThread::TerminateOngoingFetch(nsresult detail) {
1065 DEBUG_WORKERREFSvoid();
1066 if ((mState == XMLHttpRequest_Binding::OPENED && mFlagSend) ||
1067 mState == XMLHttpRequest_Binding::HEADERS_RECEIVED ||
1068 mState == XMLHttpRequest_Binding::LOADING) {
1069 MOZ_LOG(gXMLHttpRequestLog, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "%p TerminateOngoingFetch(0x%" "x" ")", this
, static_cast<uint32_t>(detail)); } } while (0)
1070 ("%p TerminateOngoingFetch(0x%" PRIx32 ")", this,do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "%p TerminateOngoingFetch(0x%" "x" ")", this
, static_cast<uint32_t>(detail)); } } while (0)
1071 static_cast<uint32_t>(detail)))do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "%p TerminateOngoingFetch(0x%" "x" ")", this
, static_cast<uint32_t>(detail)); } } while (0)
;
1072 CloseRequest(detail);
1073 }
1074}
1075
1076void XMLHttpRequestMainThread::CloseRequest(nsresult detail) {
1077 DEBUG_WORKERREFSvoid();
1078 mWaitingForOnStopRequest = false;
1079 mErrorLoad = ErrorType::eTerminated;
1080 mErrorLoadDetail = detail;
1081 if (mChannel) {
1082 mChannel->CancelWithReason(NS_BINDING_ABORTED,
1083 "XMLHttpRequestMainThread::CloseRequest"_ns);
1084 }
1085 CancelTimeoutTimer();
1086 if (mResponseXML) {
1087 mResponseXML->StopDocumentLoad();
1088 }
1089}
1090
1091void XMLHttpRequestMainThread::CloseRequestWithError(
1092 const ErrorProgressEventType& aType) {
1093 DEBUG_WORKERREFSvoid();
1094 MOZ_LOG(gXMLHttpRequestLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p CloseRequestWithError(%s)", this, aType
.cStr); } } while (0)
1095 ("%p CloseRequestWithError(%s)", this, aType.cStr))do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p CloseRequestWithError(%s)", this, aType
.cStr); } } while (0)
;
1096
1097 CloseRequest(aType.errorCode);
1098
1099 ResetResponse();
1100
1101 // If we're in the destructor, don't risk dispatching an event.
1102 if (mFlagDeleted) {
1103 mFlagSyncLooping = false;
1104 return;
1105 }
1106
1107 if (mState != XMLHttpRequest_Binding::UNSENT &&
1108 !(mState == XMLHttpRequest_Binding::OPENED && !mFlagSend) &&
1109 mState != XMLHttpRequest_Binding::DONE) {
1110 ChangeState(XMLHttpRequest_Binding::DONE, true);
1111
1112 if (!mFlagSyncLooping) {
1113 if (mUpload && !mUploadComplete) {
1114 mUploadComplete = true;
1115 DispatchProgressEvent(mUpload, aType, 0, -1);
1116 }
1117 DispatchProgressEvent(this, aType, 0, -1);
1118 }
1119 }
1120
1121 // The ChangeState call above calls onreadystatechange handlers which
1122 // if they load a new url will cause XMLHttpRequestMainThread::Open to clear
1123 // the abort state bit. If this occurs we're not uninitialized (bug 361773).
1124 if (mFlagAborted) {
1125 ChangeState(XMLHttpRequest_Binding::UNSENT, false); // IE seems to do it
1126 }
1127
1128 mFlagSyncLooping = false;
1129}
1130
1131void XMLHttpRequestMainThread::RequestErrorSteps(
1132 const ProgressEventType aEventType, const nsresult aOptionalException,
1133 ErrorResult& aRv) {
1134 MOZ_LOG(gXMLHttpRequestLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p RequestErrorSteps(%s,0x%" "x" ")", this
, aEventType.cStr, static_cast<uint32_t>(aOptionalException
)); } } while (0)
1135 ("%p RequestErrorSteps(%s,0x%" PRIx32 ")", this, aEventType.cStr,do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p RequestErrorSteps(%s,0x%" "x" ")", this
, aEventType.cStr, static_cast<uint32_t>(aOptionalException
)); } } while (0)
1136 static_cast<uint32_t>(aOptionalException)))do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p RequestErrorSteps(%s,0x%" "x" ")", this
, aEventType.cStr, static_cast<uint32_t>(aOptionalException
)); } } while (0)
;
1137
1138 // Cancel our timers first before setting our state to done, so we don't
1139 // trip any assertions if one fires and asserts that state != done.
1140 CancelTimeoutTimer();
1141 CancelSyncTimeoutTimer();
1142 StopProgressEventTimer();
1143
1144 // Step 1
1145 mState = XMLHttpRequest_Binding::DONE;
1146
1147 // Step 2
1148 mFlagSend = false;
1149
1150 // Step 3
1151 ResetResponse();
1152
1153 // If we're in the destructor, don't risk dispatching an event.
1154 if (mFlagDeleted) {
1155 mFlagSyncLooping = false;
1156 return;
1157 }
1158
1159 // Step 4
1160 if (mFlagSynchronous && NS_FAILED(aOptionalException)((bool)(__builtin_expect(!!(NS_FAILED_impl(aOptionalException
)), 0)))
) {
1161 aRv.Throw(aOptionalException);
1162 return;
1163 }
1164
1165 // Step 5
1166 FireReadystatechangeEvent();
1167
1168 // Step 6
1169 if (mUpload && !mUploadComplete) {
1170 // Step 6-1
1171 mUploadComplete = true;
1172
1173 // Step 6-2
1174 if (mFlagHadUploadListenersOnSend) {
1175 // Steps 6-3, 6-4 (loadend is fired for us)
1176 DispatchProgressEvent(mUpload, aEventType, 0, -1);
1177 }
1178 }
1179
1180 // Steps 7 and 8 (loadend is fired for us)
1181 DispatchProgressEvent(this, aEventType, 0, -1);
1182}
1183
1184void XMLHttpRequestMainThread::Abort(ErrorResult& aRv) {
1185 NOT_CALLABLE_IN_SYNC_SEND_RVif (mFlagSyncLooping || mEventDispatchingSuspended) { aRv.Throw
(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); return;
}
1186 MOZ_LOG(gXMLHttpRequestLog, LogLevel::Debug, ("%p Abort()", this))do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p Abort()", this); } } while (0)
;
1187 AbortInternal(aRv);
1188}
1189
1190void XMLHttpRequestMainThread::AbortInternal(ErrorResult& aRv) {
1191 MOZ_LOG(gXMLHttpRequestLog, LogLevel::Debug, ("%p AbortInternal()", this))do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p AbortInternal()", this); } } while (0)
;
1192 mFlagAborted = true;
1193 DisconnectDoneNotifier();
1194
1195 // Step 1
1196 TerminateOngoingFetch(NS_ERROR_DOM_ABORT_ERR);
1197
1198 // Step 2
1199 if ((mState == XMLHttpRequest_Binding::OPENED && mFlagSend) ||
1200 mState == XMLHttpRequest_Binding::HEADERS_RECEIVED ||
1201 mState == XMLHttpRequest_Binding::LOADING) {
1202 RequestErrorSteps(Events::abort, NS_ERROR_DOM_ABORT_ERR, aRv);
1203 }
1204
1205 // Step 3
1206 if (mState == XMLHttpRequest_Binding::DONE) {
1207 ChangeState(XMLHttpRequest_Binding::UNSENT,
1208 false); // no ReadystateChange event
1209 }
1210
1211 mFlagSyncLooping = false;
1212}
1213
1214/*Method that checks if it is safe to expose a header value to the client.
1215It is used to check what headers are exposed for CORS requests.*/
1216bool XMLHttpRequestMainThread::IsSafeHeader(
1217 const nsACString& aHeader, NotNull<nsIHttpChannel*> aHttpChannel) const {
1218 // See bug #380418. Hide "Set-Cookie" headers from non-chrome scripts.
1219 if (!IsSystemXHR() && nsContentUtils::IsForbiddenResponseHeader(aHeader)) {
1220 NS_WARNING("blocked access to response header")NS_DebugBreak(NS_DEBUG_WARNING, "blocked access to response header"
, nullptr, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp",
1220)
;
1221 return false;
1222 }
1223 // if this is not a CORS call all headers are safe
1224 if (!IsCrossSiteCORSRequest()) {
1225 return true;
1226 }
1227 // Check for dangerous headers
1228 // Make sure we don't leak header information from denied cross-site
1229 // requests.
1230 if (mChannel) {
1231 nsresult status;
1232 mChannel->GetStatus(&status);
1233 if (NS_FAILED(status)((bool)(__builtin_expect(!!(NS_FAILED_impl(status)), 0)))) {
1234 return false;
1235 }
1236 }
1237 const char* kCrossOriginSafeHeaders[] = {
1238 "cache-control", "content-language", "content-type", "content-length",
1239 "expires", "last-modified", "pragma"};
1240 for (auto& kCrossOriginSafeHeader : kCrossOriginSafeHeaders) {
1241 if (aHeader.LowerCaseEqualsASCII(kCrossOriginSafeHeader)) {
1242 return true;
1243 }
1244 }
1245 nsAutoCString headerVal;
1246 // The "Access-Control-Expose-Headers" header contains a comma separated
1247 // list of method names.
1248 (void)aHttpChannel->GetResponseHeader("Access-Control-Expose-Headers"_ns,
1249 headerVal);
1250 bool isSafe = false;
1251 for (const nsACString& token :
1252 nsCCharSeparatedTokenizer(headerVal, ',').ToRange()) {
1253 if (token.IsEmpty()) {
1254 continue;
1255 }
1256 if (!NS_IsValidHTTPToken(token)) {
1257 return false;
1258 }
1259
1260 if (token.EqualsLiteral("*") && !mFlagACwithCredentials) {
1261 isSafe = true;
1262 } else if (aHeader.Equals(token, nsCaseInsensitiveCStringComparator)) {
1263 isSafe = true;
1264 }
1265 }
1266
1267 return isSafe;
1268}
1269
1270bool XMLHttpRequestMainThread::GetContentType(nsACString& aValue) const {
1271 MOZ_ASSERT(mChannel)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChannel)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mChannel))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mChannel", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1271); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel" ")"
); do { MOZ_CrashSequence(__null, 1271); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1272 nsCOMPtr<nsIBaseChannel> baseChan = do_QueryInterface(mChannel);
1273 if (baseChan) {
1274 RefPtr<CMimeType> fullMimeType(baseChan->FullMimeType());
1275 if (fullMimeType) {
1276 fullMimeType->Serialize(aValue);
1277 return true;
1278 }
1279 }
1280 if (NS_SUCCEEDED(mChannel->GetContentType(aValue))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mChannel->GetContentType
(aValue))), 1)))
) {
1281 nsCString value;
1282 if (NS_SUCCEEDED(mChannel->GetContentCharset(value))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mChannel->GetContentCharset
(value))), 1)))
&& !value.IsEmpty()) {
1283 aValue.AppendLiteral(";charset=");
1284 aValue.Append(value);
1285 }
1286 return true;
1287 }
1288 return false;
1289}
1290void XMLHttpRequestMainThread::GetAllResponseHeaders(
1291 nsACString& aResponseHeaders, ErrorResult& aRv) {
1292 NOT_CALLABLE_IN_SYNC_SEND_RVif (mFlagSyncLooping || mEventDispatchingSuspended) { aRv.Throw
(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); return;
}
1293
1294 aResponseHeaders.Truncate();
1295
1296 // If the state is UNSENT or OPENED,
1297 // return the empty string and terminate these steps.
1298 if (mState == XMLHttpRequest_Binding::UNSENT ||
1299 mState == XMLHttpRequest_Binding::OPENED) {
1300 return;
1301 }
1302
1303 if (mErrorLoad != ErrorType::eOK) {
1304 return;
1305 }
1306
1307 if (nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel()) {
1308 RefPtr<nsHeaderVisitor> visitor =
1309 new nsHeaderVisitor(*this, WrapNotNull(httpChannel));
1310 if (NS_SUCCEEDED(httpChannel->VisitResponseHeaders(visitor))((bool)(__builtin_expect(!!(!NS_FAILED_impl(httpChannel->VisitResponseHeaders
(visitor))), 1)))
) {
1311 aResponseHeaders = visitor->Headers();
1312 }
1313 return;
1314 }
1315
1316 if (!mChannel) {
1317 return;
1318 }
1319
1320 // Even non-http channels supply content type.
1321 nsAutoCString value;
1322 if (GetContentType(value)) {
1323 aResponseHeaders.AppendLiteral("Content-Type: ");
1324 aResponseHeaders.Append(value);
1325 aResponseHeaders.AppendLiteral("\r\n");
1326 }
1327
1328 // Don't provide Content-Length for data URIs
1329 nsCOMPtr<nsIURI> uri;
1330 if (NS_FAILED(mChannel->GetURI(getter_AddRefs(uri)))((bool)(__builtin_expect(!!(NS_FAILED_impl(mChannel->GetURI
(getter_AddRefs(uri)))), 0)))
||
1331 !uri->SchemeIs("data")) {
1332 int64_t length;
1333 if (NS_SUCCEEDED(mChannel->GetContentLength(&length))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mChannel->GetContentLength
(&length))), 1)))
) {
1334 aResponseHeaders.AppendLiteral("Content-Length: ");
1335 aResponseHeaders.AppendInt(length);
1336 aResponseHeaders.AppendLiteral("\r\n");
1337 }
1338 }
1339
1340 // Should set a Content-Range header for blob scheme.
1341 // From https://fetch.spec.whatwg.org/#scheme-fetch 3.blob.9.20:
1342 // "Set response’s header list to «(`Content-Length`, serializedSlicedLength),
1343 // (`Content-Type`, type), (`Content-Range`, contentRange)»."
1344 GetContentRangeHeader(value);
1345 if (!value.IsVoid()) {
1346 aResponseHeaders.AppendLiteral("Content-Range: ");
1347 aResponseHeaders.Append(value);
1348 aResponseHeaders.AppendLiteral("\r\n");
1349 }
1350}
1351
1352void XMLHttpRequestMainThread::GetResponseHeader(const nsACString& header,
1353 nsACString& _retval,
1354 ErrorResult& aRv) {
1355 NOT_CALLABLE_IN_SYNC_SEND_RVif (mFlagSyncLooping || mEventDispatchingSuspended) { aRv.Throw
(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); return;
}
1356
1357 _retval.SetIsVoid(true);
1358
1359 nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
1360
1361 if (!httpChannel) {
1362 // If the state is UNSENT or OPENED,
1363 // return null and terminate these steps.
1364 if (mState == XMLHttpRequest_Binding::UNSENT ||
1365 mState == XMLHttpRequest_Binding::OPENED) {
1366 return;
1367 }
1368
1369 // Even non-http channels supply content type and content length.
1370 // Remember we don't leak header information from denied cross-site
1371 // requests. However, we handle file: and blob: URLs for blob response
1372 // types by canceling them with a specific error, so we have to allow
1373 // them to pass through this check.
1374 nsresult status;
1375 if (!mChannel || NS_FAILED(mChannel->GetStatus(&status))((bool)(__builtin_expect(!!(NS_FAILED_impl(mChannel->GetStatus
(&status))), 0)))
||
1376 (NS_FAILED(status)((bool)(__builtin_expect(!!(NS_FAILED_impl(status)), 0))) && status != NS_ERROR_FILE_ALREADY_EXISTS)) {
1377 return;
1378 }
1379
1380 // Content Type:
1381 if (header.LowerCaseEqualsASCII("content-type")) {
1382 if (!GetContentType(_retval)) {
1383 // Means no content type
1384 _retval.SetIsVoid(true);
1385 return;
1386 }
1387 }
1388
1389 // Content Length:
1390 else if (header.LowerCaseEqualsASCII("content-length")) {
1391 int64_t length;
1392 if (NS_SUCCEEDED(mChannel->GetContentLength(&length))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mChannel->GetContentLength
(&length))), 1)))
) {
1393 _retval.AppendInt(length);
1394 }
1395 }
1396
1397 // Content Range:
1398 else if (header.LowerCaseEqualsASCII("content-range")) {
1399 GetContentRangeHeader(_retval);
1400 }
1401
1402 return;
1403 }
1404
1405 // Check for dangerous headers
1406 if (!IsSafeHeader(header, WrapNotNull(httpChannel))) {
1407 return;
1408 }
1409
1410 aRv = httpChannel->GetResponseHeader(header, _retval);
1411 if (aRv.ErrorCodeIs(NS_ERROR_NOT_AVAILABLE)) {
1412 // Means no header
1413 _retval.SetIsVoid(true);
1414 aRv.SuppressException();
1415 }
1416}
1417
1418already_AddRefed<nsILoadGroup> XMLHttpRequestMainThread::GetLoadGroup() const {
1419 if (mFlagBackgroundRequest) {
1420 return nullptr;
1421 }
1422
1423 if (mLoadGroup) {
1424 nsCOMPtr<nsILoadGroup> ref = mLoadGroup;
1425 return ref.forget();
1426 }
1427
1428 Document* doc = GetDocumentIfCurrent();
1429 if (doc) {
1430 return doc->GetDocumentLoadGroup();
1431 }
1432
1433 return nullptr;
1434}
1435
1436nsresult XMLHttpRequestMainThread::FireReadystatechangeEvent() {
1437 MOZ_ASSERT(mState != XMLHttpRequest_Binding::UNSENT)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mState != XMLHttpRequest_Binding::UNSENT)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mState != XMLHttpRequest_Binding::UNSENT))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mState != XMLHttpRequest_Binding::UNSENT"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1437); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mState != XMLHttpRequest_Binding::UNSENT" ")"
); do { MOZ_CrashSequence(__null, 1437); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1438 RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
1439 event->InitEvent(kLiteralString_readystatechange, false, false);
1440 // We assume anyone who managed to call CreateReadystatechangeEvent is trusted
1441 event->SetTrusted(true);
1442 DispatchOrStoreEvent(this, event);
1443 return NS_OK;
1444}
1445
1446void XMLHttpRequestMainThread::DispatchProgressEvent(
1447 DOMEventTargetHelper* aTarget, const ProgressEventType& aType,
1448 int64_t aLoaded, int64_t aTotal) {
1449 DEBUG_WORKERREFSvoid();
1450 NS_ASSERTION(aTarget, "null target")do { if (!(aTarget)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "null target"
, "aTarget", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1450); MOZ_PretendNoReturn(); } } while (0)
;
1451
1452 if (NS_FAILED(CheckCurrentGlobalCorrectness())((bool)(__builtin_expect(!!(NS_FAILED_impl(CheckCurrentGlobalCorrectness
())), 0)))
||
1453 (!AllowUploadProgress() && aTarget == mUpload)) {
1454 return;
1455 }
1456
1457 // If blocked by CORS, zero-out the stats on progress events
1458 // and never fire "progress" or "load" events at all.
1459 if (IsDeniedCrossSiteCORSRequest()) {
1460 if (aType == Events::progress || aType == Events::load) {
1461 return;
1462 }
1463 aLoaded = 0;
1464 aTotal = -1;
1465 }
1466
1467 ProgressEventInit init;
1468 init.mBubbles = false;
1469 init.mCancelable = false;
1470 init.mLengthComputable = aTotal != -1; // XHR spec step 6.1
1471 init.mLoaded = aLoaded;
1472 init.mTotal = (aTotal == -1) ? 0 : aTotal;
1473
1474 RefPtr<ProgressEvent> event =
1475 ProgressEvent::Constructor(aTarget, aType, init);
1476 event->SetTrusted(true);
1477
1478 MOZ_LOG(do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "firing %s event (%u,%u,%" "l" "u" ",%" "l"
"u" ")", aType.cStr, aTarget == mUpload, aTotal != -1, aLoaded
, (aTotal == -1) ? 0 : aTotal); } } while (0)
1479 gXMLHttpRequestLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "firing %s event (%u,%u,%" "l" "u" ",%" "l"
"u" ")", aType.cStr, aTarget == mUpload, aTotal != -1, aLoaded
, (aTotal == -1) ? 0 : aTotal); } } while (0)
1480 ("firing %s event (%u,%u,%" PRIu64 ",%" PRIu64 ")", aType.cStr,do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "firing %s event (%u,%u,%" "l" "u" ",%" "l"
"u" ")", aType.cStr, aTarget == mUpload, aTotal != -1, aLoaded
, (aTotal == -1) ? 0 : aTotal); } } while (0)
1481 aTarget == mUpload, aTotal != -1, aLoaded, (aTotal == -1) ? 0 : aTotal))do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "firing %s event (%u,%u,%" "l" "u" ",%" "l"
"u" ")", aType.cStr, aTarget == mUpload, aTotal != -1, aLoaded
, (aTotal == -1) ? 0 : aTotal); } } while (0)
;
1482
1483 DispatchOrStoreEvent(aTarget, event);
1484
1485 // If we're sending a load, error, timeout or abort event, then
1486 // also dispatch the subsequent loadend event.
1487 if (aType == Events::load || aType == Events::error ||
1488 aType == Events::timeout || aType == Events::abort) {
1489 DispatchProgressEvent(aTarget, Events::loadend, aLoaded, aTotal);
1490 }
1491}
1492
1493void XMLHttpRequestMainThread::DispatchOrStoreEvent(
1494 DOMEventTargetHelper* aTarget, Event* aEvent) {
1495 DEBUG_WORKERREFSvoid();
1496 MOZ_ASSERT(aTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTarget))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aTarget", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1496); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTarget" ")"
); do { MOZ_CrashSequence(__null, 1496); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1497 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { MOZ_CrashSequence(__null, 1497); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1498
1499 if (NS_FAILED(CheckCurrentGlobalCorrectness())((bool)(__builtin_expect(!!(NS_FAILED_impl(CheckCurrentGlobalCorrectness
())), 0)))
) {
1500 return;
1501 }
1502
1503 if (mEventDispatchingSuspended) {
1504 PendingEvent* event = mPendingEvents.AppendElement();
1505 event->mTarget = aTarget;
1506 event->mEvent = aEvent;
1507 return;
1508 }
1509
1510 aTarget->DispatchEvent(*aEvent);
1511}
1512
1513void XMLHttpRequestMainThread::SuspendEventDispatching() {
1514 MOZ_ASSERT(!mEventDispatchingSuspended)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mEventDispatchingSuspended)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mEventDispatchingSuspended)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mEventDispatchingSuspended"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1514); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mEventDispatchingSuspended" ")"); do { MOZ_CrashSequence
(__null, 1514); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1515 mEventDispatchingSuspended = true;
1516}
1517
1518void XMLHttpRequestMainThread::ResumeEventDispatching() {
1519 MOZ_ASSERT(mEventDispatchingSuspended)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mEventDispatchingSuspended)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mEventDispatchingSuspended))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mEventDispatchingSuspended"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1519); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mEventDispatchingSuspended" ")"); do { MOZ_CrashSequence
(__null, 1519); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1520 mEventDispatchingSuspended = false;
1521
1522 nsTArray<PendingEvent> pendingEvents = std::move(mPendingEvents);
1523
1524 if (NS_FAILED(CheckCurrentGlobalCorrectness())((bool)(__builtin_expect(!!(NS_FAILED_impl(CheckCurrentGlobalCorrectness
())), 0)))
) {
1525 return;
1526 }
1527
1528 for (uint32_t i = 0; i < pendingEvents.Length(); ++i) {
1529 pendingEvents[i].mTarget->DispatchEvent(*pendingEvents[i].mEvent);
1530 }
1531}
1532
1533already_AddRefed<nsIHttpChannel>
1534XMLHttpRequestMainThread::GetCurrentHttpChannel() {
1535 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
1536 return httpChannel.forget();
1537}
1538
1539already_AddRefed<nsIJARChannel>
1540XMLHttpRequestMainThread::GetCurrentJARChannel() {
1541 nsCOMPtr<nsIJARChannel> appChannel = do_QueryInterface(mChannel);
1542 return appChannel.forget();
1543}
1544
1545bool XMLHttpRequestMainThread::IsSystemXHR() const {
1546 return mIsSystem || mPrincipal->IsSystemPrincipal();
1547}
1548
1549bool XMLHttpRequestMainThread::InUploadPhase() const {
1550 // We're in the upload phase while our state is OPENED.
1551 return mState == XMLHttpRequest_Binding::OPENED;
1552}
1553
1554// This case is hit when the async parameter is outright omitted, which
1555// should set it to true (and the username and password to null).
1556void XMLHttpRequestMainThread::Open(const nsACString& aMethod,
1557 const nsACString& aUrl, ErrorResult& aRv) {
1558 Open(aMethod, aUrl, true, VoidCString(), VoidCString(), aRv);
1559}
1560
1561// This case is hit when the async parameter is specified, even if the
1562// JS value was "undefined" (which due to legacy reasons should be
1563// treated as true, which is how it will already be passed in here).
1564void XMLHttpRequestMainThread::Open(const nsACString& aMethod,
1565 const nsACString& aUrl, bool aAsync,
1566 const nsACString& aUsername,
1567 const nsACString& aPassword,
1568 ErrorResult& aRv) {
1569 DEBUG_WORKERREFS1(aMethod << " " << aUrl)void();
1570 NOT_CALLABLE_IN_SYNC_SEND_RVif (mFlagSyncLooping || mEventDispatchingSuspended) { aRv.Throw
(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); return;
}
1571
1572 // Gecko-specific
1573 if (!aAsync && !DontWarnAboutSyncXHR() && GetOwnerWindow() &&
1574 GetOwnerWindow()->GetExtantDoc()) {
1575 GetOwnerWindow()->GetExtantDoc()->WarnOnceAndReportAbout(
1576 DeprecatedOperations::eSyncXMLHttpRequestDeprecated);
1577 }
1578
1579 glean::dom::xmlhttprequest_async_or_sync
1580 .EnumGet(static_cast<glean::dom::XmlhttprequestAsyncOrSyncLabel>(
1581 aAsync ? 0 : 1))
1582 .Add();
1583
1584 // Step 1
1585 nsCOMPtr<Document> responsibleDocument = GetDocumentIfCurrent();
1586 if (!responsibleDocument) {
1587 // This could be because we're no longer current or because we're in some
1588 // non-window context...
1589 if (NS_WARN_IF(NS_FAILED(CheckCurrentGlobalCorrectness()))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(CheckCurrentGlobalCorrectness
())), 0))), "NS_FAILED(CheckCurrentGlobalCorrectness())", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1589)
) {
1590 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT);
1591 return;
1592 }
1593 }
1594 if (!mPrincipal) {
1595 aRv.Throw(NS_ERROR_NOT_INITIALIZED);
1596 return;
1597 }
1598
1599 if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
1600 aRv.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
1601 return;
1602 }
1603
1604 // Gecko-specific
1605 if (!aAsync && responsibleDocument && GetOwnerWindow()) {
1606 // We have no extant document during unload, so the above general
1607 // syncXHR warning will not display. But we do want to display a
1608 // recommendation to use sendBeacon instead of syncXHR during unload.
1609 nsCOMPtr<nsIDocShell> shell = responsibleDocument->GetDocShell();
1610 if (shell) {
1611 bool inUnload = false;
1612 shell->GetIsInUnload(&inUnload);
1613 if (inUnload) {
1614 LogMessage("UseSendBeaconDuringUnloadAndPagehideWarning",
1615 GetOwnerWindow());
1616 }
1617 }
1618 }
1619
1620 // Steps 2-4
1621 nsAutoCString method;
1622 aRv = FetchUtil::GetValidRequestMethod(aMethod, method);
1623 if (NS_WARN_IF(aRv.Failed())NS_warn_if_impl(aRv.Failed(), "aRv.Failed()", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1623)
) {
1624 return;
1625 }
1626
1627 // Steps 5-6
1628 nsIURI* baseURI = nullptr;
1629 if (mBaseURI) {
1630 baseURI = mBaseURI;
1631 } else if (responsibleDocument) {
1632 baseURI = responsibleDocument->GetBaseURI();
1633 }
1634
1635 // Use the responsible document's encoding for the URL if we have one,
1636 // except for dedicated workers. Use UTF-8 otherwise.
1637 NotNull<const Encoding*> originCharset = UTF_8_ENCODING;
1638 if (responsibleDocument &&
1639 responsibleDocument->NodePrincipal() == mPrincipal) {
1640 originCharset = responsibleDocument->GetDocumentCharacterSet();
1641 }
1642
1643 nsCOMPtr<nsIURI> parsedURL;
1644 nsresult rv =
1645 NS_NewURI(getter_AddRefs(parsedURL), aUrl, originCharset, baseURI);
1646 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1647 aRv.ThrowSyntaxError("'"_ns + aUrl + "' is not a valid URL."_ns);
1648 return;
1649 }
1650 if (NS_WARN_IF(NS_FAILED(CheckCurrentGlobalCorrectness()))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(CheckCurrentGlobalCorrectness
())), 0))), "NS_FAILED(CheckCurrentGlobalCorrectness())", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1650)
) {
1651 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT);
1652 return;
1653 }
1654
1655 // Step 7
1656 // This is already handled by the other Open() method, which passes
1657 // username and password in as NullStrings.
1658
1659 // Step 8
1660 nsAutoCString host;
1661 parsedURL->GetHost(host);
1662 if (!host.IsEmpty() && (!aUsername.IsVoid() || !aPassword.IsVoid())) {
1663 auto mutator = NS_MutateURI(parsedURL);
1664 if (!aUsername.IsVoid()) {
1665 mutator.SetUsername(aUsername);
1666 }
1667 if (!aPassword.IsVoid()) {
1668 mutator.SetPassword(aPassword);
1669 }
1670 (void)mutator.Finalize(parsedURL);
1671 }
1672
1673 // Step 9
1674 if (!aAsync && HasOrHasHadOwnerWindow() &&
1675 (mTimeoutMilliseconds ||
1676 mResponseType != XMLHttpRequestResponseType::_empty)) {
1677 if (mTimeoutMilliseconds) {
1678 LogMessage("TimeoutSyncXHRWarning", GetOwnerWindow());
1679 }
1680 if (mResponseType != XMLHttpRequestResponseType::_empty) {
1681 LogMessage("ResponseTypeSyncXHRWarning", GetOwnerWindow());
1682 }
1683 aRv.ThrowInvalidAccessError(
1684 "synchronous XMLHttpRequests do not support timeout and responseType");
1685 return;
1686 }
1687
1688 // Step 10
1689 TerminateOngoingFetch(NS_OK);
1690
1691 // Step 11
1692 // timeouts are handled without a flag
1693 DisconnectDoneNotifier();
1694 mFlagSend = false;
1695 mRequestMethod.Assign(method);
1696 mRequestURL = std::move(parsedURL);
1697 mFlagSynchronous = !aAsync;
1698 mAuthorRequestHeaders.Clear();
1699 ResetResponse();
1700
1701 // Gecko-specific
1702 mFlagHadUploadListenersOnSend = false;
1703 mFlagAborted = false;
1704 mFlagTimedOut = false;
1705 mDecoder = nullptr;
1706
1707 // Per spec we should only create the channel on send(), but we have internal
1708 // code that relies on the channel being created now, and that code is not
1709 // always IsSystemXHR(). However, we're not supposed to throw channel-creation
1710 // errors during open(), so we silently ignore those here.
1711 CreateChannel();
1712
1713 // Step 12
1714 if (mState != XMLHttpRequest_Binding::OPENED) {
1715 mState = XMLHttpRequest_Binding::OPENED;
1716 FireReadystatechangeEvent();
1717 }
1718}
1719
1720void XMLHttpRequestMainThread::SetOriginAttributes(
1721 const OriginAttributesDictionary& aAttrs) {
1722 MOZ_ASSERT((mState == XMLHttpRequest_Binding::OPENED) && !mFlagSend)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((mState == XMLHttpRequest_Binding::OPENED) &&
!mFlagSend)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!((mState == XMLHttpRequest_Binding
::OPENED) && !mFlagSend))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("(mState == XMLHttpRequest_Binding::OPENED) && !mFlagSend"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1722); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "(mState == XMLHttpRequest_Binding::OPENED) && !mFlagSend"
")"); do { MOZ_CrashSequence(__null, 1722); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1723
1724 OriginAttributes attrs(aAttrs);
1725
1726 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
1727 loadInfo->SetOriginAttributes(attrs);
1728}
1729
1730/*
1731 * "Copy" from a stream.
1732 */
1733nsresult XMLHttpRequestMainThread::StreamReaderFunc(
1734 nsIInputStream* in, void* closure, const char* fromRawSegment,
1735 uint32_t toOffset, uint32_t count, uint32_t* writeCount) {
1736 XMLHttpRequestMainThread* xmlHttpRequest =
1737 static_cast<XMLHttpRequestMainThread*>(closure);
1738 if (!xmlHttpRequest || !writeCount) {
1739 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "XMLHttpRequest cannot read from stream: no closure or writeCount"
, nullptr, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp",
1740)
1740 "XMLHttpRequest cannot read from stream: no closure or writeCount")NS_DebugBreak(NS_DEBUG_WARNING, "XMLHttpRequest cannot read from stream: no closure or writeCount"
, nullptr, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp",
1740)
;
1741 return NS_ERROR_FAILURE;
1742 }
1743
1744 nsresult rv = NS_OK;
1745
1746 if (xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Blob) {
1747 xmlHttpRequest->MaybeCreateBlobStorage();
1748 rv = xmlHttpRequest->mBlobStorage->Append(fromRawSegment, count);
1749 } else if (xmlHttpRequest->mResponseType ==
1750 XMLHttpRequestResponseType::Arraybuffer &&
1751 !xmlHttpRequest->mIsMappedArrayBuffer) {
1752 // get the initial capacity to something reasonable to avoid a bunch of
1753 // reallocs right at the start
1754 if (xmlHttpRequest->mArrayBufferBuilder->Capacity() == 0)
1755 xmlHttpRequest->mArrayBufferBuilder->SetCapacity(
1756 std::max(count, XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE));
1757
1758 if (NS_WARN_IF(!xmlHttpRequest->mArrayBufferBuilder->Append(NS_warn_if_impl(!xmlHttpRequest->mArrayBufferBuilder->Append
( reinterpret_cast<const uint8_t*>(fromRawSegment), count
, XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH), "!xmlHttpRequest->mArrayBufferBuilder->Append( reinterpret_cast<const uint8_t*>(fromRawSegment), count, XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH)"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1760)
1759 reinterpret_cast<const uint8_t*>(fromRawSegment), count,NS_warn_if_impl(!xmlHttpRequest->mArrayBufferBuilder->Append
( reinterpret_cast<const uint8_t*>(fromRawSegment), count
, XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH), "!xmlHttpRequest->mArrayBufferBuilder->Append( reinterpret_cast<const uint8_t*>(fromRawSegment), count, XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH)"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1760)
1760 XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH))NS_warn_if_impl(!xmlHttpRequest->mArrayBufferBuilder->Append
( reinterpret_cast<const uint8_t*>(fromRawSegment), count
, XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH), "!xmlHttpRequest->mArrayBufferBuilder->Append( reinterpret_cast<const uint8_t*>(fromRawSegment), count, XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH)"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1760)
) {
1761 return NS_ERROR_OUT_OF_MEMORY;
1762 }
1763
1764 } else if (xmlHttpRequest->mResponseType ==
1765 XMLHttpRequestResponseType::_empty &&
1766 xmlHttpRequest->mResponseXML) {
1767 // Copy for our own use
1768 if (!xmlHttpRequest->mResponseBody.Append(fromRawSegment, count,
1769 fallible)) {
1770 return NS_ERROR_OUT_OF_MEMORY;
1771 }
1772 } else if (xmlHttpRequest->mResponseType ==
1773 XMLHttpRequestResponseType::_empty ||
1774 xmlHttpRequest->mResponseType ==
1775 XMLHttpRequestResponseType::Text ||
1776 xmlHttpRequest->mResponseType ==
1777 XMLHttpRequestResponseType::Json) {
1778 MOZ_ASSERT(!xmlHttpRequest->mResponseXML,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!xmlHttpRequest->mResponseXML)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!xmlHttpRequest->mResponseXML
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!xmlHttpRequest->mResponseXML" " (" "We shouldn't be parsing a doc here"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1779
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!xmlHttpRequest->mResponseXML"
") (" "We shouldn't be parsing a doc here" ")"); do { MOZ_CrashSequence
(__null, 1779); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1779 "We shouldn't be parsing a doc here")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!xmlHttpRequest->mResponseXML)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!xmlHttpRequest->mResponseXML
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!xmlHttpRequest->mResponseXML" " (" "We shouldn't be parsing a doc here"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1779
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!xmlHttpRequest->mResponseXML"
") (" "We shouldn't be parsing a doc here" ")"); do { MOZ_CrashSequence
(__null, 1779); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1780 rv = xmlHttpRequest->AppendToResponseText(
1781 AsBytes(Span(fromRawSegment, count)));
1782 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1782)
) {
1783 return rv;
1784 }
1785 }
1786
1787 if (xmlHttpRequest->mFlagParseBody) {
1788 // Give the same data to the parser.
1789
1790 // We need to wrap the data in a new lightweight stream and pass that
1791 // to the parser, because calling ReadSegments() recursively on the same
1792 // stream is not supported.
1793 nsCOMPtr<nsIInputStream> copyStream;
1794 rv = NS_NewByteInputStream(getter_AddRefs(copyStream),
1795 Span(fromRawSegment, count),
1796 NS_ASSIGNMENT_DEPEND);
1797
1798 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && xmlHttpRequest->mXMLParserStreamListener) {
1799 NS_ASSERTION(copyStream, "NS_NewByteInputStream lied")do { if (!(copyStream)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "NS_NewByteInputStream lied"
, "copyStream", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1799); MOZ_PretendNoReturn(); } } while (0)
;
1800 nsCOMPtr<nsIStreamListener> listener =
1801 xmlHttpRequest->mXMLParserStreamListener;
1802 nsresult parsingResult = listener->OnDataAvailable(
1803 xmlHttpRequest->mChannel, copyStream, toOffset, count);
1804
1805 // No use to continue parsing if we failed here, but we
1806 // should still finish reading the stream
1807 if (NS_FAILED(parsingResult)((bool)(__builtin_expect(!!(NS_FAILED_impl(parsingResult)), 0
)))
) {
1808 xmlHttpRequest->mFlagParseBody = false;
1809 }
1810 }
1811 }
1812
1813 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1814 *writeCount = count;
1815 } else {
1816 *writeCount = 0;
1817 }
1818
1819 return rv;
1820}
1821
1822namespace {
1823
1824nsresult GetLocalFileFromChannel(nsIRequest* aRequest, nsIFile** aFile) {
1825 MOZ_ASSERT(aRequest)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRequest)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRequest))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aRequest", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1825); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRequest" ")"
); do { MOZ_CrashSequence(__null, 1825); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1826 MOZ_ASSERT(aFile)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aFile)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aFile))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aFile", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1826); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aFile" ")")
; do { MOZ_CrashSequence(__null, 1826); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1827
1828 *aFile = nullptr;
1829
1830 nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(aRequest);
1831 if (!fc) {
1832 return NS_OK;
1833 }
1834
1835 nsCOMPtr<nsIFile> file;
1836 nsresult rv = fc->GetFile(getter_AddRefs(file));
1837 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1837)
) {
1838 return rv;
1839 }
1840
1841 file.forget(aFile);
1842 return NS_OK;
1843}
1844
1845nsresult DummyStreamReaderFunc(nsIInputStream* aInputStream, void* aClosure,
1846 const char* aFromRawSegment, uint32_t aToOffset,
1847 uint32_t aCount, uint32_t* aWriteCount) {
1848 *aWriteCount = aCount;
1849 return NS_OK;
1850}
1851
1852class FileCreationHandler final : public PromiseNativeHandler {
1853 public:
1854 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:
1855
1856 static void Create(Promise* aPromise, XMLHttpRequestMainThread* aXHR) {
1857 MOZ_ASSERT(aPromise)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPromise)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPromise))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aPromise", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1857); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPromise" ")"
); do { MOZ_CrashSequence(__null, 1857); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1858
1859 RefPtr<FileCreationHandler> handler = new FileCreationHandler(aXHR);
1860 aPromise->AppendNativeHandler(handler);
1861 }
1862
1863 MOZ_CAN_RUN_SCRIPT_BOUNDARY void ResolvedCallback(
1864 JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv) override {
1865 if (NS_WARN_IF(!aValue.isObject())NS_warn_if_impl(!aValue.isObject(), "!aValue.isObject()", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1865)
) {
1866 mXHR->LocalFileToBlobCompleted(nullptr);
1867 return;
1868 }
1869
1870 RefPtr<Blob> blob;
1871 if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Blob, &aValue.toObject(), blob)))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(mozilla
::dom::binding_detail::UnwrapObjectWithCrossOriginAsserts<
mozilla::dom::prototypes::id::Blob, mozilla::dom::Blob_Binding
::NativeType>(&aValue.toObject(), blob))), 0))), "NS_FAILED(UNWRAP_OBJECT(Blob, &aValue.toObject(), blob))"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1871)
) {
1872 mXHR->LocalFileToBlobCompleted(nullptr);
1873 return;
1874 }
1875
1876 const RefPtr<BlobImpl> blobImpl = blob->Impl();
1877 mXHR->LocalFileToBlobCompleted(blobImpl);
1878 }
1879
1880 MOZ_CAN_RUN_SCRIPT_BOUNDARY void RejectedCallback(
1881 JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv) override {
1882 mXHR->LocalFileToBlobCompleted(nullptr);
1883 }
1884
1885 private:
1886 explicit FileCreationHandler(XMLHttpRequestMainThread* aXHR) : mXHR(aXHR) {
1887 MOZ_ASSERT(aXHR)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aXHR)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aXHR))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aXHR", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1887); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aXHR" ")");
do { MOZ_CrashSequence(__null, 1887); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1888 }
1889
1890 ~FileCreationHandler() = default;
1891
1892 MOZ_KNOWN_LIVE const RefPtr<XMLHttpRequestMainThread> mXHR;
1893};
1894
1895NS_IMPL_ISUPPORTS0(FileCreationHandler)MozExternalRefCountType FileCreationHandler::AddRef(void) { static_assert
(!std::is_destructible_v<FileCreationHandler>, "Reference-counted class "
"FileCreationHandler" " 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" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1895); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("FileCreationHandler" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("FileCreationHandler" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"FileCreationHandler\" != nullptr" " (" "Must specify a name"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1895
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FileCreationHandler\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1895); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("FileCreationHandler" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("FileCreationHandler"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
FileCreationHandler::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"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1895
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1895
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("FileCreationHandler" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("FileCreationHandler" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"FileCreationHandler\" != nullptr" " (" "Must specify a name"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1895
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FileCreationHandler\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1895); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("FileCreationHandler" " not thread-safe"); const
char* const nametmp = "FileCreationHandler"; nsrefcnt count =
--mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult FileCreationHandler::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1895); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<FileCreationHandler, nsISupports>, int32_t
( reinterpret_cast<char*>(static_cast<nsISupports*>
((FileCreationHandler*)0x1000)) - reinterpret_cast<char*>
((FileCreationHandler*)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; }
1896
1897} // namespace
1898
1899void XMLHttpRequestMainThread::LocalFileToBlobCompleted(BlobImpl* aBlobImpl) {
1900 MOZ_ASSERT(mState != XMLHttpRequest_Binding::DONE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mState != XMLHttpRequest_Binding::DONE)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mState != XMLHttpRequest_Binding::DONE))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mState != XMLHttpRequest_Binding::DONE"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1900); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mState != XMLHttpRequest_Binding::DONE" ")"
); do { MOZ_CrashSequence(__null, 1900); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1901
1902 mResponseBlobImpl = aBlobImpl;
1903 mBlobStorage = nullptr;
1904 NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty")do { if (!(mResponseBody.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "mResponseBody should be empty", "mResponseBody.IsEmpty()",
"./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1904); MOZ_PretendNoReturn
(); } } while (0)
;
1905
1906 ChangeStateToDone(mFlagSyncLooping);
1907}
1908
1909NS_IMETHODIMPnsresult
1910XMLHttpRequestMainThread::OnDataAvailable(nsIRequest* request,
1911 nsIInputStream* inStr,
1912 uint64_t sourceOffset,
1913 uint32_t count) {
1914 DEBUG_WORKERREFSvoid();
1915 NS_ENSURE_ARG_POINTER(inStr)do { if ((__builtin_expect(!!(!(inStr)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "inStr" ") failed", nullptr
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1915); return
NS_ERROR_INVALID_POINTER; } } while (false)
;
1916
1917 mProgressSinceLastProgressEvent = true;
1918 XMLHttpRequest_Binding::ClearCachedResponseTextValue(this);
1919
1920 nsresult rv;
1921
1922 if (mResponseType == XMLHttpRequestResponseType::Blob) {
1923 nsCOMPtr<nsIFile> localFile;
1924 if (RefPtr<BlobURLChannel> blobChan = do_QueryObject(request)) {
1925 RefPtr<BlobImpl> blobImpl;
1926 rv = blobChan->GetBackingBlob(getter_AddRefs(blobImpl));
1927 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1928 mResponseBlobImpl = blobImpl;
1929 }
1930 } else {
1931 rv = GetLocalFileFromChannel(request, getter_AddRefs(localFile));
1932 }
1933 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1933)
) {
1934 return rv;
1935 }
1936
1937 if (mResponseBlobImpl || localFile) {
1938 mBlobStorage = nullptr;
1939 NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty")do { if (!(mResponseBody.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "mResponseBody should be empty", "mResponseBody.IsEmpty()",
"./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 1939); MOZ_PretendNoReturn
(); } } while (0)
;
1940
1941 // The nsIStreamListener contract mandates us to read from the stream
1942 // before returning.
1943 uint32_t totalRead;
1944 rv = inStr->ReadSegments(DummyStreamReaderFunc, nullptr, count,
1945 &totalRead);
1946 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1946); return rv; } } while (false)
;
1947
1948 ChangeState(XMLHttpRequest_Binding::LOADING);
1949
1950 // Cancel() must be called with an error. We use
1951 // NS_ERROR_FILE_ALREADY_EXISTS to know that we've aborted the operation
1952 // just because we can retrieve the File from the channel directly.
1953 return request->Cancel(NS_ERROR_FILE_ALREADY_EXISTS);
1954 }
1955 }
1956
1957 uint32_t totalRead;
1958 rv = inStr->ReadSegments(XMLHttpRequestMainThread::StreamReaderFunc,
1959 (void*)this, count, &totalRead);
1960 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 1960); return rv; } } while (false)
;
1961
1962 // Fire the first progress event/loading state change
1963 if (mState == XMLHttpRequest_Binding::HEADERS_RECEIVED) {
1964 ChangeState(XMLHttpRequest_Binding::LOADING);
1965 if (!mFlagSynchronous) {
1966 DispatchProgressEvent(this, Events::progress, mLoadTransferred,
1967 mLoadTotal);
1968 }
1969 mProgressSinceLastProgressEvent = false;
1970 }
1971
1972 if (!mFlagSynchronous && !mProgressTimerIsActive) {
1973 StartProgressEventTimer();
1974 }
1975
1976 return NS_OK;
1977}
1978
1979NS_IMETHODIMPnsresult
1980XMLHttpRequestMainThread::OnStartRequest(nsIRequest* request) {
1981 DEBUG_WORKERREFSvoid();
1982 AUTO_PROFILER_LABEL("XMLHttpRequestMainThread::OnStartRequest", NETWORK)mozilla::AutoProfilerLabel raiiObject1982( "XMLHttpRequestMainThread::OnStartRequest"
, nullptr, JS::ProfilingCategoryPair::NETWORK)
;
1983
1984 nsresult rv = NS_OK;
1985
1986 if (request != mChannel) {
1987 // Can this still happen?
1988 return NS_OK;
1989 }
1990
1991 // Don't do anything if we have been aborted
1992 if (mState == XMLHttpRequest_Binding::UNSENT) {
1993 return NS_OK;
1994 }
1995
1996 // Don't do anything if we're in mid-abort, but let the request
1997 // know (this can happen due to race conditions in valid XHRs,
1998 // see bz1070763 for info).
1999 if (mFlagAborted) {
2000 return NS_BINDING_ABORTED;
2001 }
2002
2003 // Don't do anything if we have timed out.
2004 if (mFlagTimedOut) {
2005 return NS_OK;
2006 }
2007
2008 // If we were asked for a bad range on a blob URL, but we're async,
2009 // we should throw now in order to fire an error progress event.
2010 if (BadContentRangeRequested()) {
2011 return NS_ERROR_NET_PARTIAL_TRANSFER;
2012 }
2013
2014 nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
2015 NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(channel)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "channel" ") failed", nullptr
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2015); return
NS_ERROR_UNEXPECTED; } } while (false)
;
2016
2017 nsresult status;
2018 request->GetStatus(&status);
2019 if (mErrorLoad == ErrorType::eOK && NS_FAILED(status)((bool)(__builtin_expect(!!(NS_FAILED_impl(status)), 0)))) {
2020 mErrorLoad = ErrorType::eRequest;
2021 mErrorLoadDetail = status;
2022 }
2023
2024 // Upload phase is now over. If we were uploading anything,
2025 // stop the timer and fire any final progress events.
2026 if (mUpload && !mUploadComplete && mErrorLoad == ErrorType::eOK &&
2027 !mFlagSynchronous) {
2028 StopProgressEventTimer();
2029
2030 mUploadTransferred = mUploadTotal;
2031
2032 if (mProgressSinceLastProgressEvent) {
2033 DispatchProgressEvent(mUpload, Events::progress, mUploadTransferred,
2034 mUploadTotal);
2035 mProgressSinceLastProgressEvent = false;
2036 }
2037
2038 mUploadComplete = true;
2039 DispatchProgressEvent(mUpload, Events::load, mUploadTotal, mUploadTotal);
2040 }
2041
2042 mFlagParseBody = true;
2043 if (mErrorLoad == ErrorType::eOK) {
2044 ChangeState(XMLHttpRequest_Binding::HEADERS_RECEIVED);
2045 }
2046
2047 // Re-run earlier check after scripts may have changed the state.
2048
2049 if (request != mChannel) {
2050 // Can this still happen?
2051 return NS_OK;
2052 }
2053
2054 // Don't do anything if we have been aborted
2055 if (mState == XMLHttpRequest_Binding::UNSENT) {
2056 return NS_OK;
2057 }
2058
2059 // Don't do anything if we're in mid-abort, but let the request
2060 // know (this can happen due to race conditions in valid XHRs,
2061 // see bz1070763 for info).
2062 if (mFlagAborted) {
2063 return NS_BINDING_ABORTED;
2064 }
2065
2066 // Don't do anything if we have timed out.
2067 if (mFlagTimedOut) {
2068 return NS_OK;
2069 }
2070
2071 ResetResponse();
2072
2073 if (!mOverrideMimeType.IsEmpty()) {
2074 channel->SetContentType(NS_ConvertUTF16toUTF8(mOverrideMimeType));
2075 }
2076
2077 // Fallback to 'application/octet-stream' (leaving data URLs alone)
2078 if (!IsBlobURI(mRequestURL)) {
2079 nsAutoCString type;
2080 channel->GetContentType(type);
2081 if (type.IsEmpty() || type.EqualsLiteral(UNKNOWN_CONTENT_TYPE"application/x-unknown-content-type")) {
2082 channel->SetContentType(nsLiteralCString(APPLICATION_OCTET_STREAM"application/octet-stream"));
2083 }
2084 }
2085
2086 DetectCharset();
2087
2088 // Set up arraybuffer
2089 if (mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
2090 NS_SUCCEEDED(status)((bool)(__builtin_expect(!!(!NS_FAILED_impl(status)), 1)))) {
2091 if (mIsMappedArrayBuffer) {
2092 nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(channel);
2093 if (jarChannel) {
2094 nsCOMPtr<nsIURI> uri;
2095 rv = channel->GetURI(getter_AddRefs(uri));
2096 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2097 nsAutoCString file;
2098 nsAutoCString scheme;
2099 uri->GetScheme(scheme);
2100 if (scheme.LowerCaseEqualsLiteral("jar")) {
2101 nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(uri);
2102 if (jarURI) {
2103 jarURI->GetJAREntry(file);
2104 }
2105 }
2106 nsCOMPtr<nsIFile> jarFile;
2107 jarChannel->GetJarFile(getter_AddRefs(jarFile));
2108 if (!jarFile) {
2109 mIsMappedArrayBuffer = false;
2110 } else {
2111 rv = mArrayBufferBuilder->MapToFileInPackage(file, jarFile);
2112 // This can happen legitimately if there are compressed files
2113 // in the jarFile. See bug #1357219. No need to warn on the error.
2114 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2115 mIsMappedArrayBuffer = false;
2116 } else {
2117 channel->SetContentType("application/mem-mapped"_ns);
2118 }
2119 }
2120 }
2121 }
2122 }
2123 // If memory mapping failed, mIsMappedArrayBuffer would be set to false,
2124 // and we want it fallback to the malloc way.
2125 if (!mIsMappedArrayBuffer) {
2126 int64_t contentLength;
2127 rv = channel->GetContentLength(&contentLength);
2128 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && contentLength > 0 &&
2129 contentLength < XML_HTTP_REQUEST_MAX_CONTENT_LENGTH_PREALLOCATE) {
2130 mArrayBufferBuilder->SetCapacity(static_cast<int32_t>(contentLength));
2131 }
2132 }
2133 }
2134
2135 // Set up responseXML
2136 // Fetch spec Main Fetch step 21: ignore body for head/connect methods.
2137 bool parseBody = (mResponseType == XMLHttpRequestResponseType::_empty ||
2138 mResponseType == XMLHttpRequestResponseType::Document) &&
2139 !(mRequestMethod.EqualsLiteral("HEAD") ||
2140 mRequestMethod.EqualsLiteral("CONNECT"));
2141
2142 if (parseBody) {
2143 // Do not try to parse documents if content-length = 0
2144 int64_t contentLength;
2145 if (NS_SUCCEEDED(mChannel->GetContentLength(&contentLength))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mChannel->GetContentLength
(&contentLength))), 1)))
&&
2146 contentLength == 0) {
2147 parseBody = false;
2148 }
2149 }
2150
2151 mIsHtml = false;
2152 mWarnAboutSyncHtml = false;
2153 if (parseBody && NS_SUCCEEDED(status)((bool)(__builtin_expect(!!(!NS_FAILED_impl(status)), 1)))) {
2154 // We can gain a huge performance win by not even trying to
2155 // parse non-XML data. This also protects us from the situation
2156 // where we have an XML document and sink, but HTML (or other)
2157 // parser, which can produce unreliable results.
2158 nsAutoCString type;
2159 channel->GetContentType(type);
2160
2161 if ((mResponseType == XMLHttpRequestResponseType::Document) &&
2162 type.EqualsLiteral("text/html")) {
2163 // HTML parsing is only supported for responseType == "document" to
2164 // avoid running the parser and, worse, populating responseXML for
2165 // legacy users of XHR who use responseType == "" for retrieving the
2166 // responseText of text/html resources. This legacy case is so common
2167 // that it's not useful to emit a warning about it.
2168 if (mFlagSynchronous) {
2169 // We don't make cool new features available in the bad synchronous
2170 // mode. The synchronous mode is for legacy only.
2171 mWarnAboutSyncHtml = true;
2172 mFlagParseBody = false;
2173 } else {
2174 mIsHtml = true;
2175 }
2176 } else if (!type.IsEmpty() && (!(type.EqualsLiteral("text/xml") ||
2177 type.EqualsLiteral("application/xml") ||
2178 StringEndsWith(type, "+xml"_ns)))) {
2179 // Follow https://xhr.spec.whatwg.org/
2180 // If final MIME type is not null, text/html, text/xml, application/xml,
2181 // or does not end in +xml, return null.
2182 mFlagParseBody = false;
2183 }
2184 } else {
2185 // The request failed, so we shouldn't be parsing anyway
2186 mFlagParseBody = false;
2187 }
2188
2189 if (mFlagParseBody) {
2190 nsCOMPtr<nsIURI> baseURI, docURI;
2191 rv = mChannel->GetURI(getter_AddRefs(docURI));
2192 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2192); return rv; } } while (false)
;
2193 baseURI = docURI;
2194
2195 nsCOMPtr<Document> doc = GetDocumentIfCurrent();
2196 nsCOMPtr<nsIURI> chromeXHRDocURI, chromeXHRDocBaseURI;
2197 if (doc) {
2198 chromeXHRDocURI = doc->GetDocumentURI();
2199 chromeXHRDocBaseURI = doc->GetBaseURI();
2200 } else {
2201 // If we're no longer current, just kill the load, though it really should
2202 // have been killed already.
2203 if (NS_WARN_IF(NS_FAILED(CheckCurrentGlobalCorrectness()))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(CheckCurrentGlobalCorrectness
())), 0))), "NS_FAILED(CheckCurrentGlobalCorrectness())", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2203)
) {
2204 return NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT;
2205 }
2206 }
2207
2208 // Create an empty document from it.
2209 const auto& emptyStr = u""_ns;
2210 nsIGlobalObject* global = DOMEventTargetHelper::GetParentObject();
2211
2212 nsCOMPtr<nsIPrincipal> requestingPrincipal;
2213 rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
2214 channel, getter_AddRefs(requestingPrincipal));
2215 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2215); return rv; } } while (false)
;
2216
2217 rv = NS_NewDOMDocument(
2218 getter_AddRefs(mResponseXML), emptyStr, emptyStr, nullptr, docURI,
2219 baseURI, requestingPrincipal, LoadedAsData::AsData, global,
2220 mIsHtml ? DocumentFlavor::HTML : DocumentFlavor::LegacyGuess);
2221 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2221); return rv; } } while (false)
;
2222 mResponseXML->SetChromeXHRDocURI(chromeXHRDocURI);
2223 mResponseXML->SetChromeXHRDocBaseURI(chromeXHRDocBaseURI);
2224
2225 // suppress parsing failure messages to console for statuses which
2226 // can have empty bodies (see bug 884693).
2227 IgnoredErrorResult rv2;
2228 uint32_t responseStatus = GetStatus(rv2);
2229 if (!rv2.Failed() && (responseStatus == 201 || responseStatus == 202 ||
2230 responseStatus == 204 || responseStatus == 205 ||
2231 responseStatus == 304)) {
2232 mResponseXML->SetSuppressParserErrorConsoleMessages(true);
2233 }
2234
2235 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
2236 bool isCrossSite = false;
2237 isCrossSite = loadInfo->GetTainting() != LoadTainting::Basic;
2238
2239 if (isCrossSite) {
2240 mResponseXML->DisableCookieAccess();
2241 }
2242
2243 nsCOMPtr<nsIStreamListener> listener;
2244 nsCOMPtr<nsILoadGroup> loadGroup;
2245 channel->GetLoadGroup(getter_AddRefs(loadGroup));
2246
2247 // suppress <parsererror> nodes on XML document parse failure, but only
2248 // for non-privileged code (including Web Extensions). See bug 289714.
2249 if (!IsSystemXHR()) {
2250 mResponseXML->SetSuppressParserErrorElement(true);
2251 }
2252
2253 rv = mResponseXML->StartDocumentLoad(kLoadAsData, channel, loadGroup,
2254 nullptr, getter_AddRefs(listener),
2255 !isCrossSite);
2256 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2256); return rv; } } while (false)
;
2257
2258 // the spec requires the response document.referrer to be the empty string
2259 nsCOMPtr<nsIReferrerInfo> referrerInfo =
2260 new ReferrerInfo(nullptr, mResponseXML->ReferrerPolicy());
2261 mResponseXML->SetReferrerInfo(referrerInfo);
2262
2263 mXMLParserStreamListener = listener;
2264 nsCOMPtr<nsIStreamListener> parserListener = mXMLParserStreamListener;
2265 rv = parserListener->OnStartRequest(request);
2266 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2266); return rv; } } while (false)
;
2267 }
2268
2269 // Download phase beginning; start the progress event timer if necessary.
2270 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && HasListenersFor(nsGkAtoms::onprogress)) {
2271 StartProgressEventTimer();
2272 }
2273
2274 return NS_OK;
2275}
2276
2277NS_IMETHODIMPnsresult
2278XMLHttpRequestMainThread::OnStopRequest(nsIRequest* request, nsresult status)
2279 MOZ_CAN_RUN_SCRIPT_BOUNDARY {
2280 DEBUG_WORKERREFSvoid();
2281 AUTO_PROFILER_LABEL("XMLHttpRequestMainThread::OnStopRequest", NETWORK)mozilla::AutoProfilerLabel raiiObject2281( "XMLHttpRequestMainThread::OnStopRequest"
, nullptr, JS::ProfilingCategoryPair::NETWORK)
;
2282
2283 if (request != mChannel) {
2284 // This can happen when we have already faked an OnStopRequest earlier
2285 // when synchronously canceling a sync XHR.
2286 return NS_OK;
2287 }
2288
2289 if (mAlreadyGotStopRequest) {
2290 // This is needed to filter out the real, second call after faking one in
2291 // SendInternal.
2292 return NS_OK;
2293 }
2294 mAlreadyGotStopRequest = true;
2295
2296 // Send the decoder the signal that we've hit the end of the stream,
2297 // but only when decoding text eagerly.
2298 if (mDecoder && ((mResponseType == XMLHttpRequestResponseType::Text) ||
2299 (mResponseType == XMLHttpRequestResponseType::Json) ||
2300 (mResponseType == XMLHttpRequestResponseType::_empty &&
2301 !mResponseXML))) {
2302 AppendToResponseText(Span<const uint8_t>(), true);
2303 }
2304
2305 mWaitingForOnStopRequest = false;
2306
2307 // make sure to notify the listener if we were aborted
2308 // XXX in fact, why don't we do the cleanup below in this case??
2309 // UNSENT is for abort calls. See OnStartRequest above.
2310 if (mState == XMLHttpRequest_Binding::UNSENT || mFlagTimedOut) {
2311 if (mXMLParserStreamListener) {
2312 nsCOMPtr<nsIStreamListener> parserListener = mXMLParserStreamListener;
2313 (void)parserListener->OnStopRequest(request, status);
2314 }
2315 return NS_OK;
2316 }
2317
2318 // Is this good enough here?
2319 if (mXMLParserStreamListener && mFlagParseBody) {
2320 nsCOMPtr<nsIStreamListener> parserListener = mXMLParserStreamListener;
2321 parserListener->OnStopRequest(request, status);
2322 }
2323
2324 mXMLParserStreamListener = nullptr;
2325
2326 // If window.stop() or other aborts were issued, handle as an abort.
2327 // Navigation-caused aborts suppress the abort event and only fire loadend,
2328 // matching Chrome/Safari behavior (bug 1505389).
2329 if (status == NS_BINDING_ABORTED) {
2330 mFlagParseBody = false;
2331
2332 nsAutoCString cancelReason;
2333 if (mChannel) {
2334 mChannel->GetCanceledReason(cancelReason);
2335 }
2336
2337 if (cancelReason.EqualsLiteral("navigation")) {
2338 CancelTimeoutTimer();
2339 CancelSyncTimeoutTimer();
2340 StopProgressEventTimer();
2341
2342 mState = XMLHttpRequest_Binding::DONE;
2343 mFlagSend = false;
2344 ResetResponse();
2345
2346 if (!mFlagDeleted) {
2347 FireReadystatechangeEvent();
2348 if (mUpload && !mUploadComplete) {
2349 mUploadComplete = true;
2350 if (mFlagHadUploadListenersOnSend) {
2351 DispatchProgressEvent(mUpload, Events::loadend, 0, -1);
2352 }
2353 }
2354 DispatchProgressEvent(this, Events::loadend, 0, -1);
2355 }
2356 } else {
2357 IgnoredErrorResult rv;
2358 RequestErrorSteps(Events::abort, NS_ERROR_DOM_ABORT_ERR, rv);
2359 }
2360
2361 ChangeState(XMLHttpRequest_Binding::UNSENT, false);
2362 return NS_OK;
2363 }
2364
2365 // If we were just reading a blob URL, we're already done
2366 if (status == NS_ERROR_FILE_ALREADY_EXISTS && mResponseBlobImpl) {
2367 ChangeStateToDone(mFlagSyncLooping);
2368 return NS_OK;
2369 }
2370
2371 bool waitingForBlobCreation = false;
2372
2373 // If we have this error, we have to deal with a file: URL + responseType =
2374 // blob. We have this error because we canceled the channel. The status will
2375 // be set to NS_OK.
2376 if (!mResponseBlobImpl && status == NS_ERROR_FILE_ALREADY_EXISTS &&
2377 mResponseType == XMLHttpRequestResponseType::Blob) {
2378 nsCOMPtr<nsIFile> file;
2379 nsresult rv = GetLocalFileFromChannel(request, getter_AddRefs(file));
2380 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2380)
) {
2381 return rv;
2382 }
2383
2384 if (file) {
2385 nsAutoCString contentType;
2386 rv = mChannel->GetContentType(contentType);
2387 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2387)
) {
2388 return rv;
2389 }
2390
2391 ChromeFilePropertyBag bag;
2392 CopyUTF8toUTF16(contentType, bag.mType);
2393
2394 nsCOMPtr<nsIGlobalObject> global = GetRelevantGlobal();
2395
2396 ErrorResult error;
2397 RefPtr<Promise> promise =
2398 FileCreatorHelper::CreateFile(global, file, bag, true, error);
2399 if (NS_WARN_IF(error.Failed())NS_warn_if_impl(error.Failed(), "error.Failed()", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2399)
) {
2400 return error.StealNSResult();
2401 }
2402
2403 FileCreationHandler::Create(promise, this);
2404 waitingForBlobCreation = true;
2405 status = NS_OK;
2406
2407 NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty")do { if (!(mResponseBody.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "mResponseBody should be empty", "mResponseBody.IsEmpty()",
"./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2407); MOZ_PretendNoReturn
(); } } while (0)
;
2408 NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty")do { if (!(mResponseText.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "mResponseText should be empty", "mResponseText.IsEmpty()",
"./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2408); MOZ_PretendNoReturn
(); } } while (0)
;
2409 }
2410 }
2411
2412 if (NS_SUCCEEDED(status)((bool)(__builtin_expect(!!(!NS_FAILED_impl(status)), 1))) &&
2413 mResponseType == XMLHttpRequestResponseType::Blob &&
2414 !waitingForBlobCreation) {
2415 // Smaller files may be written in cache map instead of separate files.
2416 // Also, no-store response cannot be written in persistent cache.
2417 nsAutoCString contentType;
2418 if (!mOverrideMimeType.IsEmpty()) {
2419 contentType.Assign(NS_ConvertUTF16toUTF8(mOverrideMimeType));
2420 } else {
2421 mChannel->GetContentType(contentType);
2422 }
2423
2424 // mBlobStorage can be null if the channel is non-file non-cacheable
2425 // and if the response length is zero.
2426 MaybeCreateBlobStorage();
2427 mBlobStorage->GetBlobImplWhenReady(contentType, this);
2428 waitingForBlobCreation = true;
2429
2430 NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty")do { if (!(mResponseBody.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "mResponseBody should be empty", "mResponseBody.IsEmpty()",
"./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2430); MOZ_PretendNoReturn
(); } } while (0)
;
2431 NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty")do { if (!(mResponseText.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "mResponseText should be empty", "mResponseText.IsEmpty()",
"./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2431); MOZ_PretendNoReturn
(); } } while (0)
;
2432 } else if (NS_SUCCEEDED(status)((bool)(__builtin_expect(!!(!NS_FAILED_impl(status)), 1))) && !mIsMappedArrayBuffer &&
2433 mResponseType == XMLHttpRequestResponseType::Arraybuffer) {
2434 // set the capacity down to the actual length, to realloc back
2435 // down to the actual size
2436 if (!mArrayBufferBuilder->SetCapacity(mArrayBufferBuilder->Length())) {
2437 // this should never happen!
2438 status = NS_ERROR_UNEXPECTED;
2439 }
2440 }
2441
2442 nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
2443 NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(channel)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "channel" ") failed", nullptr
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2443); return
NS_ERROR_UNEXPECTED; } } while (false)
;
2444
2445 channel->SetNotificationCallbacks(nullptr);
2446 mNotificationCallbacks = nullptr;
2447 mChannelEventSink = nullptr;
2448 mProgressEventSink = nullptr;
2449
2450 bool wasSync = mFlagSyncLooping;
2451 mFlagSyncLooping = false;
2452 mRequestSentTime = 0;
2453
2454 // update our charset and decoder to match mResponseXML,
2455 // before it is possibly nulled out
2456 MatchCharsetAndDecoderToResponseDocument();
2457
2458 if (NS_FAILED(status)((bool)(__builtin_expect(!!(NS_FAILED_impl(status)), 0)))) {
2459 // This can happen if the server is unreachable. Other possible
2460 // reasons are that the user leaves the page or hits the ESC key.
2461
2462 mErrorLoad = ErrorType::eUnreachable;
2463 mErrorLoadDetail = status;
2464 mResponseXML = nullptr;
2465
2466 // Handle network errors specifically per spec.
2467 if (NS_ERROR_GET_MODULE(status) == NS_ERROR_MODULE_NETWORK6) {
2468 MOZ_LOG(gXMLHttpRequestLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p detected networking error 0x%" "x" "\n"
, this, static_cast<uint32_t>(status)); } } while (0)
2469 ("%p detected networking error 0x%" PRIx32 "\n", this,do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p detected networking error 0x%" "x" "\n"
, this, static_cast<uint32_t>(status)); } } while (0)
2470 static_cast<uint32_t>(status)))do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p detected networking error 0x%" "x" "\n"
, this, static_cast<uint32_t>(status)); } } while (0)
;
2471 IgnoredErrorResult rv;
2472 mFlagParseBody = false;
2473 RequestErrorSteps(Events::error, NS_ERROR_DOM_NETWORK_ERR, rv);
2474 // RequestErrorSteps will not call ChangeStateToDone for sync XHRs, so we
2475 // do so here to ensure progress events are sent and our state is sane.
2476 if (mFlagSynchronous) {
2477 ChangeStateToDone(wasSync);
2478 }
2479 return NS_OK;
2480 }
2481
2482 MOZ_LOG(gXMLHttpRequestLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p detected unreachable error 0x%" "x" "\n"
, this, static_cast<uint32_t>(status)); } } while (0)
2483 ("%p detected unreachable error 0x%" PRIx32 "\n", this,do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p detected unreachable error 0x%" "x" "\n"
, this, static_cast<uint32_t>(status)); } } while (0)
2484 static_cast<uint32_t>(status)))do { const ::mozilla::LogModule* moz_real_module = gXMLHttpRequestLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "%p detected unreachable error 0x%" "x" "\n"
, this, static_cast<uint32_t>(status)); } } while (0)
;
2485 }
2486
2487 // If we're uninitialized at this point, we encountered an error
2488 // earlier and listeners have already been notified. Also we do
2489 // not want to do this if we already completed.
2490 if (mState == XMLHttpRequest_Binding::UNSENT ||
2491 mState == XMLHttpRequest_Binding::DONE) {
2492 return NS_OK;
2493 }
2494
2495 if (!mResponseXML) {
2496 mFlagParseBody = false;
2497
2498 // We postpone the 'done' until the creation of the Blob is completed.
2499 if (!waitingForBlobCreation) {
2500 ChangeStateToDone(wasSync);
2501 }
2502
2503 return NS_OK;
2504 }
2505
2506 if (mIsHtml) {
2507 NS_ASSERTION(!mFlagSyncLooping,do { if (!(!mFlagSyncLooping)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We weren't supposed to support HTML parsing with XHR!", "!mFlagSyncLooping"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2508); MOZ_PretendNoReturn
(); } } while (0)
2508 "We weren't supposed to support HTML parsing with XHR!")do { if (!(!mFlagSyncLooping)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "We weren't supposed to support HTML parsing with XHR!", "!mFlagSyncLooping"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2508); MOZ_PretendNoReturn
(); } } while (0)
;
2509 mParseEndListener = new nsXHRParseEndListener(this);
2510 RefPtr<EventTarget> eventTarget = mResponseXML;
2511 EventListenerManager* manager = eventTarget->GetOrCreateListenerManager();
2512 manager->AddEventListenerByType(mParseEndListener,
2513 kLiteralString_DOMContentLoaded,
2514 TrustedEventsAtSystemGroupBubble());
2515 return NS_OK;
2516 } else {
2517 mFlagParseBody = false;
2518 }
2519
2520 // We might have been sent non-XML data. If that was the case,
2521 // we should null out the document member. The idea in this
2522 // check here is that if there is no document element it is not
2523 // an XML document. We might need a fancier check...
2524 if (!mResponseXML->GetRootElement()) {
2525 mErrorParsingXML = true;
2526 mResponseXML = nullptr;
2527 }
2528 ChangeStateToDone(wasSync);
2529 return NS_OK;
2530}
2531
2532void XMLHttpRequestMainThread::OnBodyParseEnd() {
2533 mFlagParseBody = false;
2534 mParseEndListener = nullptr;
2535 ChangeStateToDone(mFlagSyncLooping);
2536}
2537
2538void XMLHttpRequestMainThread::MatchCharsetAndDecoderToResponseDocument() {
2539 if (mResponseXML &&
2540 (!mDecoder ||
2541 mDecoder->Encoding() != mResponseXML->GetDocumentCharacterSet())) {
2542 TruncateResponseText();
2543 mResponseBodyDecodedPos = 0;
2544 mEofDecoded = false;
2545 mDecoder = mResponseXML->GetDocumentCharacterSet()->NewDecoder();
2546 }
2547}
2548
2549void XMLHttpRequestMainThread::DisconnectDoneNotifier() {
2550 if (mDelayedDoneNotifier) {
2551 // Disconnect may release the last reference to 'this'.
2552 RefPtr<XMLHttpRequestMainThread> kungfuDeathGrip = this;
2553 mDelayedDoneNotifier->Disconnect();
2554 mDelayedDoneNotifier = nullptr;
2555 }
2556}
2557
2558void XMLHttpRequestMainThread::ChangeStateToDone(bool aWasSync) {
2559 DEBUG_WORKERREFSvoid();
2560 DisconnectDoneNotifier();
2561
2562 if (!mForWorker && !aWasSync && mChannel) {
2563 // If the top level page is loading, try to postpone the handling of the
2564 // final events.
2565 nsLoadFlags loadFlags = 0;
2566 mChannel->GetLoadFlags(&loadFlags);
2567 MOZ_DIAGNOSTIC_ASSERT(loadFlags & nsIRequest::LOAD_BACKGROUND)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(loadFlags & nsIRequest::LOAD_BACKGROUND)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(loadFlags & nsIRequest::LOAD_BACKGROUND))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("loadFlags & nsIRequest::LOAD_BACKGROUND"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2567); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "loadFlags & nsIRequest::LOAD_BACKGROUND"
")"); do { MOZ_CrashSequence(__null, 2567); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2568 nsPIDOMWindowInner* owner = GetOwnerWindow();
2569 BrowsingContext* bc = owner ? owner->GetBrowsingContext() : nullptr;
2570 bc = bc ? bc->Top() : nullptr;
2571 if (bc && bc->IsLoading()) {
2572 MOZ_ASSERT(!mDelayedDoneNotifier)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDelayedDoneNotifier)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDelayedDoneNotifier))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!mDelayedDoneNotifier"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2572); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mDelayedDoneNotifier" ")"); do { MOZ_CrashSequence
(__null, 2572); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2573 RefPtr<XMLHttpRequestDoneNotifier> notifier =
2574 new XMLHttpRequestDoneNotifier(this);
2575 mDelayedDoneNotifier = notifier;
2576 bc->AddDeprioritizedLoadRunner(notifier);
2577 return;
2578 }
2579 }
2580
2581 ChangeStateToDoneInternal();
2582}
2583
2584void XMLHttpRequestMainThread::ChangeStateToDoneInternal() {
2585 DEBUG_WORKERREFSvoid();
2586 RefPtr<XMLHttpRequestMainThread> kungfuDeathGrip(this);
2587 DisconnectDoneNotifier();
2588 StopProgressEventTimer();
2589
2590 MOZ_ASSERT(!mFlagParseBody,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mFlagParseBody)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mFlagParseBody))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mFlagParseBody"
" (" "ChangeStateToDone() called before async HTML parsing is done."
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2591
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mFlagParseBody" ") ("
"ChangeStateToDone() called before async HTML parsing is done."
")"); do { MOZ_CrashSequence(__null, 2591); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2591 "ChangeStateToDone() called before async HTML parsing is done.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mFlagParseBody)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mFlagParseBody))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mFlagParseBody"
" (" "ChangeStateToDone() called before async HTML parsing is done."
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 2591
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mFlagParseBody" ") ("
"ChangeStateToDone() called before async HTML parsing is done."
")"); do { MOZ_CrashSequence(__null, 2591); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2592
2593 mFlagSend = false;
2594
2595 CancelTimeoutTimer();
2596
2597 // Per spec, fire the last download progress event, if any,
2598 // before readystatechange=4/done. (Note that 0-sized responses
2599 // will have not sent a progress event yet, so one must be sent here).
2600 if (!mFlagSynchronous &&
2601 (!mLoadTransferred || mProgressSinceLastProgressEvent)) {
2602 DispatchProgressEvent(this, Events::progress, mLoadTransferred, mLoadTotal);
2603 mProgressSinceLastProgressEvent = false;
2604 }
2605
2606 // Notify the document when an XHR request completes successfully.
2607 // This is used by the password manager as a hint to observe DOM mutations.
2608 // Call this prior to changing state to DONE to ensure we set up the
2609 // observer before mutations occur.
2610 if (mErrorLoad == ErrorType::eOK) {
2611 if (const RefPtr<Document> doc = GetDocumentIfCurrent()) {
2612 doc->NotifyFetchOrXHRSuccess();
2613 }
2614 }
2615
2616 // Per spec, fire readystatechange=4/done before final error events.
2617 ChangeState(XMLHttpRequest_Binding::DONE, true);
2618
2619 // Per spec, if we failed in the upload phase, fire a final error
2620 // and loadend events for the upload after readystatechange=4/done.
2621 if (!mFlagSynchronous && mUpload && !mUploadComplete) {
2622 DispatchProgressEvent(mUpload, Events::error, 0, -1);
2623 }
2624
2625 // Per spec, fire download's load/error and loadend events after
2626 // readystatechange=4/done (and of course all upload events).
2627 if (mErrorLoad != ErrorType::eOK) {
2628 DispatchProgressEvent(this, Events::error, 0, -1);
2629 } else {
2630 DispatchProgressEvent(this, Events::load, mLoadTransferred, mLoadTotal);
2631 }
2632
2633 if (mErrorLoad != ErrorType::eOK) {
2634 // By nulling out channel here we make it so that Send() can test
2635 // for that and throw. Also calling the various status
2636 // methods/members will not throw.
2637 // This matches what IE does.
2638 mChannel = nullptr;
2639 }
2640}
2641
2642nsresult XMLHttpRequestMainThread::CreateChannel() {
2643 DEBUG_WORKERREFSvoid();
2644 // When we are called from JS we can find the load group for the page,
2645 // and add ourselves to it. This way any pending requests
2646 // will be automatically aborted if the user leaves the page.
2647 nsCOMPtr<nsILoadGroup> loadGroup = GetLoadGroup();
2648
2649 nsSecurityFlags secFlags;
2650 nsLoadFlags loadFlags = nsIRequest::LOAD_BACKGROUND;
2651 uint32_t sandboxFlags = 0;
2652 if (mPrincipal->IsSystemPrincipal()) {
2653 // When chrome is loading we want to make sure to sandbox any potential
2654 // result document. We also want to allow cross-origin loads.
2655 secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL;
2656 sandboxFlags = SANDBOXED_ORIGIN;
2657 } else if (IsSystemXHR()) {
2658 // For pages that have appropriate permissions, we want to still allow
2659 // cross-origin loads, but make sure that the any potential result
2660 // documents get the same principal as the loader.
2661 secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT |
2662 nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
2663 loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
2664 } else {
2665 // Otherwise use CORS. Again, make sure that potential result documents
2666 // use the same principal as the loader.
2667 secFlags = nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT |
2668 nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
2669 }
2670
2671 if (mIsAnon) {
2672 secFlags |= nsILoadInfo::SEC_COOKIES_OMIT;
2673 }
2674
2675 // Use the responsibleDocument if we have it, except for dedicated workers
2676 // where it will be the parent document, which is not the one we want to use.
2677 nsresult rv;
2678 nsCOMPtr<Document> responsibleDocument = GetDocumentIfCurrent();
2679 auto contentPolicyType =
2680 mFlagSynchronous ? nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST_SYNC
2681 : nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST_ASYNC;
2682 if (responsibleDocument &&
2683 responsibleDocument->NodePrincipal() == mPrincipal) {
2684 rv = NS_NewChannel(getter_AddRefs(mChannel), mRequestURL,
2685 responsibleDocument, secFlags, contentPolicyType,
2686 nullptr, // aPerformanceStorage
2687 loadGroup,
2688 nullptr, // aCallbacks
2689 loadFlags, nullptr, sandboxFlags);
2690 } else if (mClientInfo.isSome()) {
2691 rv = NS_NewChannel(
2692 getter_AddRefs(mChannel), mRequestURL, mPrincipal, mClientInfo.ref(),
2693 mController, secFlags, contentPolicyType, mCookieJarSettings,
2694 mPerformanceStorage, // aPerformanceStorage
2695 loadGroup,
2696 nullptr, // aCallbacks
2697 loadFlags, nullptr, sandboxFlags, mAssociatedBrowsingContextID);
2698 } else {
2699 // Otherwise use the principal.
2700 rv = NS_NewChannel(getter_AddRefs(mChannel), mRequestURL, mPrincipal,
2701 secFlags, contentPolicyType, mCookieJarSettings,
2702 mPerformanceStorage, // aPerformanceStorage
2703 loadGroup,
2704 nullptr, // aCallbacks
2705 loadFlags, nullptr, sandboxFlags);
2706 }
2707 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2707); return rv; } } while (false)
;
2708
2709 if (mAssociatedBrowsingContextID) {
2710 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
2711 rv = loadInfo->SetAssociatedBrowsingContextID(mAssociatedBrowsingContextID);
2712 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2712); return rv; } } while (false)
;
2713 }
2714
2715 mAlreadyGotStopRequest = false;
2716
2717 if (mCSPEventListener) {
2718 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
2719 rv = loadInfo->SetCspEventListener(mCSPEventListener);
2720 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2720); return rv; } } while (false)
;
2721 }
2722
2723 if (nsCOMPtr<Document> doc = GetDocumentIfCurrent()) {
2724 net::ClassificationFlags flags = doc->GetScriptTrackingFlags();
2725 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
2726
2727 loadInfo->SetTriggeringFirstPartyClassificationFlags(flags.firstPartyFlags);
2728 loadInfo->SetTriggeringThirdPartyClassificationFlags(flags.thirdPartyFlags);
2729 }
2730
2731 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
2732 if (httpChannel) {
2733 rv = httpChannel->SetRequestMethod(mRequestMethod);
2734 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2734); return rv; } } while (false)
;
2735
2736 httpChannel->SetSource(profiler_capture_backtrace());
2737
2738 // Set the initiator type
2739 nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
2740 if (timedChannel) {
2741 timedChannel->SetInitiatorType(u"xmlhttprequest"_ns);
2742 }
2743 }
2744
2745 return NS_OK;
2746}
2747
2748void XMLHttpRequestMainThread::MaybeLowerChannelPriority() {
2749 nsCOMPtr<Document> doc = GetDocumentIfCurrent();
2750 if (!doc) {
2751 return;
2752 }
2753
2754 AutoJSAPI jsapi;
2755 if (!jsapi.Init(GetRelevantGlobal())) {
2756 return;
2757 }
2758
2759 JSContext* cx = jsapi.cx();
2760
2761 if (!doc->IsScriptTracking(cx)) {
2762 return;
2763 }
2764
2765 if (StaticPrefs::network_http_tailing_enabled()) {
2766 nsCOMPtr<nsIClassOfService> cos = do_QueryInterface(mChannel);
2767 if (cos) {
2768 // Adding TailAllowed to overrule the Unblocked flag, but to preserve
2769 // the effect of Unblocked when tailing is off.
2770 cos->AddClassFlags(nsIClassOfService::Throttleable |
2771 nsIClassOfService::Tail |
2772 nsIClassOfService::TailAllowed);
2773 }
2774 }
2775
2776 nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mChannel);
2777 if (p) {
2778 p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
2779 }
2780}
2781
2782nsresult XMLHttpRequestMainThread::InitiateFetch(
2783 already_AddRefed<nsIInputStream> aUploadStream, int64_t aUploadLength,
2784 nsACString& aUploadContentType) {
2785 DEBUG_WORKERREFSvoid();
2786 nsresult rv;
2787 nsCOMPtr<nsIInputStream> uploadStream = std::move(aUploadStream);
2788
2789 if (IsSystemXHR() && mFlagSynchronous &&
2790 StaticPrefs::network_xhr_block_sync_system_requests()) {
2791 mState = XMLHttpRequest_Binding::DONE;
2792 return NS_ERROR_DOM_NETWORK_ERR;
2793 }
2794
2795 if (!uploadStream) {
2796 RefPtr<PreloaderBase> preload = FindPreload();
2797 if (preload) {
2798 // Because of bug 682305, we can't let listener be the XHR object itself
2799 // because JS wouldn't be able to use it. So create a listener around
2800 // 'this'. Make sure to hold a strong reference so that we don't leak the
2801 // wrapper.
2802 nsCOMPtr<nsIStreamListener> listener =
2803 new net::nsStreamListenerWrapper(this);
2804 rv = preload->AsyncConsume(listener);
2805 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2806 mFromPreload = true;
2807
2808 // May be null when the preload has already finished, but the XHR code
2809 // is safe to live with it.
2810 mChannel = preload->Channel();
2811 MOZ_ASSERT(mChannel)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChannel)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mChannel))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mChannel", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2811); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel" ")"
); do { MOZ_CrashSequence(__null, 2811); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2812 EnsureChannelContentType();
2813 return NS_OK;
2814 }
2815
2816 preload = nullptr;
2817 }
2818 }
2819
2820 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
2821 if (httpChannel) {
2822 // If the user hasn't overridden the Accept header, set it to */* per spec.
2823 if (!mAuthorRequestHeaders.Has("accept")) {
2824 mAuthorRequestHeaders.Set("accept", "*/*"_ns);
2825 }
2826
2827 mAuthorRequestHeaders.ApplyToChannel(httpChannel, false, false);
2828
2829 if (!IsSystemXHR()) {
2830 nsCOMPtr<nsPIDOMWindowInner> owner = GetOwnerWindow();
2831 nsCOMPtr<Document> doc = owner ? owner->GetExtantDoc() : nullptr;
2832 nsCOMPtr<nsIReferrerInfo> referrerInfo =
2833 ReferrerInfo::CreateForFetch(mPrincipal, doc);
2834 (void)httpChannel->SetReferrerInfoWithoutClone(referrerInfo);
2835 }
2836
2837 if (uploadStream) {
2838 // If necessary, wrap the stream in a buffered stream so as to guarantee
2839 // support for our upload when calling ExplicitSetUploadStream.
2840 if (!NS_InputStreamIsBuffered(uploadStream)) {
2841 nsCOMPtr<nsIInputStream> bufferedStream;
2842 rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
2843 uploadStream.forget(), 4096);
2844 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2844); return rv; } } while (false)
;
2845
2846 uploadStream = bufferedStream;
2847 }
2848
2849 // We want to use a newer version of the upload channel that won't
2850 // ignore the necessary headers for an empty Content-Type.
2851 nsCOMPtr<nsIUploadChannel2> uploadChannel(do_QueryInterface(httpChannel));
2852 NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel")do { if (!(uploadChannel)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "http must support nsIUploadChannel", "uploadChannel", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2852); MOZ_PretendNoReturn(); } } while (0)
;
2853 rv = uploadChannel->ExplicitSetUploadStream(
Value stored to 'rv' is never read
2854 uploadStream, aUploadContentType, mUploadTotal, mRequestMethod);
2855 }
2856 }
2857
2858 // Should set a Content-Range header for blob scheme, and also slice the
2859 // blob appropriately, so we process the Range header here for later use.
2860 RefPtr<BlobURLChannel> blobChan = do_QueryObject(mChannel);
2861 if (blobChan) {
2862 nsAutoCString range;
2863 mAuthorRequestHeaders.Get("range", range);
2864 if (!range.IsVoid()) {
2865 rv = blobChan->SetRequestContentRangeHeader(range);
2866 if (mFlagSynchronous && NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2867 // We later fire an error progress event for non-sync
2868 mState = XMLHttpRequest_Binding::DONE;
2869 return NS_ERROR_DOM_NETWORK_ERR;
2870 }
2871 }
2872 }
2873
2874 // Due to the chrome-only XHR.channel API, we need a hacky way to set the
2875 // SEC_COOKIES_INCLUDE *after* the channel has been has been created, since
2876 // .withCredentials can be called after open() is called.
2877 // Not doing this for privileged system XHRs since those don't use CORS.
2878 if (!IsSystemXHR() && !mIsAnon && mFlagACwithCredentials) {
2879 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
2880 static_cast<net::LoadInfo*>(loadInfo.get())->SetIncludeCookiesSecFlag();
2881 }
2882
2883 // We never let XHR be blocked by head CSS/JS loads to avoid potential
2884 // deadlock where server generation of CSS/JS requires an XHR signal.
2885 nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
2886 if (cos) {
2887 cos->AddClassFlags(nsIClassOfService::Unblocked);
2888
2889 // Mark channel as urgent-start if the XHR is triggered by user input
2890 // events.
2891 if (UserActivation::IsHandlingUserInput()) {
2892 cos->AddClassFlags(nsIClassOfService::UrgentStart);
2893 }
2894 }
2895
2896 // Disable Necko-internal response timeouts.
2897 nsCOMPtr<nsIHttpChannelInternal> internalHttpChannel(
2898 do_QueryInterface(mChannel));
2899 if (internalHttpChannel) {
2900 rv = internalHttpChannel->SetResponseTimeoutEnabled(false);
2901 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2901); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2901); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2902 }
2903
2904 if (!mIsAnon) {
2905 AddLoadFlags(mChannel, nsIChannel::LOAD_EXPLICIT_CREDENTIALS);
2906 }
2907
2908 // Bypass the network cache in cases where it makes no sense:
2909 // POST responses are always unique, and we provide no API that would
2910 // allow our consumers to specify a "cache key" to access old POST
2911 // responses, so they are not worth caching.
2912 if (mRequestMethod.EqualsLiteral("POST")) {
2913 AddLoadFlags(mChannel, nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE |
2914 nsIRequest::INHIBIT_CACHING);
2915 } else {
2916 // When we are sync loading, we need to bypass the local cache when it would
2917 // otherwise block us waiting for exclusive access to the cache. If we
2918 // don't do this, then we could dead lock in some cases (see bug 309424).
2919 //
2920 // Also don't block on the cache entry on async if it is busy - favoring
2921 // parallelism over cache hit rate for xhr. This does not disable the cache
2922 // everywhere - only in cases where more than one channel for the same URI
2923 // is accessed simultanously.
2924 AddLoadFlags(mChannel, nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
2925 }
2926
2927 EnsureChannelContentType();
2928
2929 // Set up the preflight if needed
2930 if (!IsSystemXHR()) {
2931 nsTArray<nsCString> CORSUnsafeHeaders;
2932 mAuthorRequestHeaders.GetCORSUnsafeHeaders(CORSUnsafeHeaders);
2933 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
2934 loadInfo->SetCorsPreflightInfo(CORSUnsafeHeaders,
2935 mFlagHadUploadListenersOnSend);
2936 }
2937
2938 // Hook us up to listen to redirects and the like. Only do this very late
2939 // since this creates a cycle between the channel and us. This cycle has
2940 // to be manually broken if anything below fails.
2941 mChannel->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks));
2942 mChannel->SetNotificationCallbacks(this);
2943
2944 if (internalHttpChannel) {
2945 internalHttpChannel->SetBlockAuthPrompt(ShouldBlockAuthPrompt());
2946 }
2947
2948 // Because of bug 682305, we can't let listener be the XHR object itself
2949 // because JS wouldn't be able to use it. So create a listener around 'this'.
2950 // Make sure to hold a strong reference so that we don't leak the wrapper.
2951 nsCOMPtr<nsIStreamListener> listener = new net::nsStreamListenerWrapper(this);
2952
2953 // Check if this XHR is created from a tracking script.
2954 // If yes, lower the channel's priority.
2955 if (StaticPrefs::privacy_trackingprotection_lower_network_priority()) {
2956 MaybeLowerChannelPriority();
2957 }
2958
2959 // Associate any originating stack with the channel.
2960 NotifyNetworkMonitorAlternateStack(mChannel, std::move(mOriginStack));
2961
2962 // Start reading from the channel
2963 rv = mChannel->AsyncOpen(listener);
2964 listener = nullptr;
2965 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 2965)
) {
2966 // Drop our ref to the channel to avoid cycles. Also drop channel's
2967 // ref to us to be extra safe.
2968 mChannel->SetNotificationCallbacks(mNotificationCallbacks);
2969 mChannel = nullptr;
2970
2971 mErrorLoad = ErrorType::eChannelOpen;
2972 mErrorLoadDetail = rv;
2973
2974 // Per spec, we throw on sync errors, but not async.
2975 if (mFlagSynchronous) {
2976 mState = XMLHttpRequest_Binding::DONE;
2977 return NS_ERROR_DOM_NETWORK_ERR;
2978 }
2979 }
2980
2981 return NS_OK;
2982}
2983
2984already_AddRefed<PreloaderBase> XMLHttpRequestMainThread::FindPreload() {
2985 Document* doc = GetDocumentIfCurrent();
2986 if (!doc) {
2987 return nullptr;
2988 }
2989 if (mPrincipal->IsSystemPrincipal() || IsSystemXHR()) {
2990 return nullptr;
2991 }
2992 if (!mRequestMethod.EqualsLiteral("GET")) {
2993 // Preload can only do GET.
2994 return nullptr;
2995 }
2996 if (!mAuthorRequestHeaders.IsEmpty()) {
2997 // Preload can't set headers.
2998 return nullptr;
2999 }
3000
3001 // mIsAnon overrules mFlagACwithCredentials.
3002 CORSMode cors = (mIsAnon || !mFlagACwithCredentials)
3003 ? CORSMode::CORS_ANONYMOUS
3004 : CORSMode::CORS_USE_CREDENTIALS;
3005 nsCOMPtr<nsIReferrerInfo> referrerInfo =
3006 ReferrerInfo::CreateForFetch(mPrincipal, doc);
3007 auto key = PreloadHashKey::CreateAsFetch(mRequestURL, cors);
3008 RefPtr<PreloaderBase> preload = doc->Preloads().LookupPreload(key);
3009 if (!preload) {
3010 return nullptr;
3011 }
3012
3013 preload->RemoveSelf(doc);
3014 preload->NotifyUsage(doc, PreloaderBase::LoadBackground::Keep);
3015
3016 return preload.forget();
3017}
3018
3019void XMLHttpRequestMainThread::EnsureChannelContentType() {
3020 MOZ_ASSERT(mChannel)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChannel)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mChannel))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mChannel", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 3020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel" ")"
); do { MOZ_CrashSequence(__null, 3020); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3021
3022 // We don't mess with the content type of a blob URL.
3023 if (IsBlobURI(mRequestURL)) {
3024 return;
3025 }
3026
3027 // Since we expect XML data, set the type hint accordingly
3028 // if the channel doesn't know any content type.
3029 // This means that we always try to parse local files as XML
3030 // ignoring return value, as this is not critical. Use text/xml as fallback
3031 // MIME type.
3032 nsAutoCString contentType;
3033 if (NS_FAILED(mChannel->GetContentType(contentType))((bool)(__builtin_expect(!!(NS_FAILED_impl(mChannel->GetContentType
(contentType))), 0)))
||
3034 contentType.IsEmpty() ||
3035 contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE"application/x-unknown-content-type")) {
3036 mChannel->SetContentType("text/xml"_ns);
3037 }
3038}
3039
3040void XMLHttpRequestMainThread::ResumeTimeout() {
3041 DEBUG_WORKERREFSvoid();
3042 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()"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3042); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 3042); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3043 MOZ_ASSERT(mFlagSynchronous)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFlagSynchronous)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFlagSynchronous))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mFlagSynchronous"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3043); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mFlagSynchronous" ")"); do { MOZ_CrashSequence
(__null, 3043); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3044
3045 if (mResumeTimeoutRunnable) {
3046 DispatchToMainThread(mResumeTimeoutRunnable.forget());
3047 mResumeTimeoutRunnable = nullptr;
3048 }
3049}
3050
3051void XMLHttpRequestMainThread::Send(
3052 const Nullable<
3053 DocumentOrBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString>&
3054 aData,
3055 ErrorResult& aRv) {
3056 DEBUG_WORKERREFS1(mRequestURL)void();
3057 NOT_CALLABLE_IN_SYNC_SEND_RVif (mFlagSyncLooping || mEventDispatchingSuspended) { aRv.Throw
(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); return;
}
3058
3059 if (!CanSend(aRv)) {
3060 return;
3061 }
3062
3063 if (aData.IsNull()) {
3064 SendInternal(nullptr, false, aRv);
3065 return;
3066 }
3067
3068 if (aData.Value().IsDocument()) {
3069 BodyExtractor<Document> body(&aData.Value().GetAsDocument());
3070 SendInternal(&body, true, aRv);
3071 return;
3072 }
3073
3074 if (aData.Value().IsBlob()) {
3075 BodyExtractor<const Blob> body(&aData.Value().GetAsBlob());
3076 SendInternal(&body, false, aRv);
3077 return;
3078 }
3079
3080 if (aData.Value().IsArrayBuffer()) {
3081 BodyExtractor<const ArrayBuffer> body(&aData.Value().GetAsArrayBuffer());
3082 SendInternal(&body, false, aRv);
3083 return;
3084 }
3085
3086 if (aData.Value().IsArrayBufferView()) {
3087 BodyExtractor<const ArrayBufferView> body(
3088 &aData.Value().GetAsArrayBufferView());
3089 SendInternal(&body, false, aRv);
3090 return;
3091 }
3092
3093 if (aData.Value().IsFormData()) {
3094 BodyExtractor<const FormData> body(&aData.Value().GetAsFormData());
3095 SendInternal(&body, false, aRv);
3096 return;
3097 }
3098
3099 if (aData.Value().IsURLSearchParams()) {
3100 BodyExtractor<const URLSearchParams> body(
3101 &aData.Value().GetAsURLSearchParams());
3102 SendInternal(&body, false, aRv);
3103 return;
3104 }
3105
3106 if (aData.Value().IsUSVString()) {
3107 BodyExtractor<const nsAString> body(&aData.Value().GetAsUSVString());
3108 SendInternal(&body, true, aRv);
3109 return;
3110 }
3111}
3112
3113nsresult XMLHttpRequestMainThread::MaybeSilentSendFailure(nsresult aRv) {
3114 // Per spec, silently fail on async request failures; throw for sync.
3115 if (mFlagSynchronous) {
3116 mState = XMLHttpRequest_Binding::DONE;
3117 return NS_ERROR_DOM_NETWORK_ERR;
3118 }
3119
3120 // Defer the actual sending of async events just in case listeners
3121 // are attached after the send() method is called.
3122 (void)NS_WARN_IF(NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(DispatchToMainThread
(NewRunnableMethod<ErrorProgressEventType>( "dom::XMLHttpRequestMainThread::CloseRequestWithError"
, this, &XMLHttpRequestMainThread::CloseRequestWithError,
Events::error)))), 0))), "NS_FAILED(DispatchToMainThread(NewRunnableMethod<ErrorProgressEventType>( \"dom::XMLHttpRequestMainThread::CloseRequestWithError\", this, &XMLHttpRequestMainThread::CloseRequestWithError, Events::error)))"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3125)
3123 NS_FAILED(DispatchToMainThread(NewRunnableMethod<ErrorProgressEventType>(NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(DispatchToMainThread
(NewRunnableMethod<ErrorProgressEventType>( "dom::XMLHttpRequestMainThread::CloseRequestWithError"
, this, &XMLHttpRequestMainThread::CloseRequestWithError,
Events::error)))), 0))), "NS_FAILED(DispatchToMainThread(NewRunnableMethod<ErrorProgressEventType>( \"dom::XMLHttpRequestMainThread::CloseRequestWithError\", this, &XMLHttpRequestMainThread::CloseRequestWithError, Events::error)))"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3125)
3124 "dom::XMLHttpRequestMainThread::CloseRequestWithError", this,NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(DispatchToMainThread
(NewRunnableMethod<ErrorProgressEventType>( "dom::XMLHttpRequestMainThread::CloseRequestWithError"
, this, &XMLHttpRequestMainThread::CloseRequestWithError,
Events::error)))), 0))), "NS_FAILED(DispatchToMainThread(NewRunnableMethod<ErrorProgressEventType>( \"dom::XMLHttpRequestMainThread::CloseRequestWithError\", this, &XMLHttpRequestMainThread::CloseRequestWithError, Events::error)))"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3125)
3125 &XMLHttpRequestMainThread::CloseRequestWithError, Events::error))))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(DispatchToMainThread
(NewRunnableMethod<ErrorProgressEventType>( "dom::XMLHttpRequestMainThread::CloseRequestWithError"
, this, &XMLHttpRequestMainThread::CloseRequestWithError,
Events::error)))), 0))), "NS_FAILED(DispatchToMainThread(NewRunnableMethod<ErrorProgressEventType>( \"dom::XMLHttpRequestMainThread::CloseRequestWithError\", this, &XMLHttpRequestMainThread::CloseRequestWithError, Events::error)))"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3125)
;
3126 return NS_OK;
3127}
3128
3129bool XMLHttpRequestMainThread::CanSend(ErrorResult& aRv) {
3130 if (!mPrincipal) {
3131 aRv.Throw(NS_ERROR_NOT_INITIALIZED);
3132 return false;
3133 }
3134
3135 // Step 1
3136 if (mState != XMLHttpRequest_Binding::OPENED) {
3137 aRv.ThrowInvalidStateError("XMLHttpRequest state must be OPENED.");
3138 return false;
3139 }
3140
3141 // Step 2
3142 if (mFlagSend) {
3143 aRv.ThrowInvalidStateError("XMLHttpRequest must not be sending.");
3144 return false;
3145 }
3146
3147 if (NS_FAILED(CheckCurrentGlobalCorrectness())((bool)(__builtin_expect(!!(NS_FAILED_impl(CheckCurrentGlobalCorrectness
())), 0)))
) {
3148 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT);
3149 return false;
3150 }
3151
3152 // Backstop against late workers.
3153 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) {
3154 aRv.Throw(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
3155 return false;
3156 }
3157
3158 return true;
3159}
3160
3161void XMLHttpRequestMainThread::SendInternal(const BodyExtractorBase* aBody,
3162 bool aBodyIsDocumentOrString,
3163 ErrorResult& aRv) {
3164 DEBUG_WORKERREFSvoid();
3165 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()"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3165); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 3165); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3166
3167 // We expect that CanSend has been called before we get here!
3168 // We cannot move the remaining two checks below there because
3169 // MaybeSilentSendFailure can cause unexpected side effects if called
3170 // too early.
3171
3172 // If open() failed to create the channel, then throw a network error
3173 // as per spec. We really should create the channel here in send(), but
3174 // we have internal code relying on the channel being created in open().
3175 if (!mChannel) {
3176 mErrorLoad = ErrorType::eChannelOpen;
3177 mErrorLoadDetail = NS_ERROR_DOM_NETWORK_ERR;
3178 mFlagSend = true; // so CloseRequestWithError sets us to DONE.
3179 aRv = MaybeSilentSendFailure(mErrorLoadDetail);
3180 return;
3181 }
3182
3183 // non-GET requests aren't allowed for blob.
3184 if (IsBlobURI(mRequestURL) && !mRequestMethod.EqualsLiteral("GET")) {
3185 mErrorLoad = ErrorType::eChannelOpen;
3186 mErrorLoadDetail = NS_ERROR_DOM_NETWORK_ERR;
3187 mFlagSend = true; // so CloseRequestWithError sets us to DONE.
3188 aRv = MaybeSilentSendFailure(mErrorLoadDetail);
3189 return;
3190 }
3191
3192 // https://fetch.spec.whatwg.org/#concept-fetch
3193 // XHR uses the Fetch algorithm; MIME sniffing does not apply to fetch
3194 // requests, only to browsing contexts.
3195 // Exception: when responseType is "document", XHR needs the content type
3196 // to parse the response as HTML/XML, so allow sniffing as a fallback.
3197 if (mResponseType != XMLHttpRequestResponseType::Document) {
3198 nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
3199 loadInfo->SetSkipContentSniffing(true);
3200 }
3201
3202 // XXX We should probably send a warning to the JS console
3203 // if there are no event listeners set and we are doing
3204 // an asynchronous call.
3205
3206 mUploadTransferred = 0;
3207 mUploadTotal = 0;
3208 // By default we don't have any upload, so mark upload complete.
3209 mUploadComplete = true;
3210 mErrorLoad = ErrorType::eOK;
3211 mErrorLoadDetail = NS_OK;
3212 mLoadTotal = -1;
3213 nsCOMPtr<nsIInputStream> uploadStream;
3214 nsAutoCString uploadContentType;
3215 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
3216 if (aBody && httpChannel && !mRequestMethod.EqualsLiteral("GET") &&
3217 !mRequestMethod.EqualsLiteral("HEAD")) {
3218 nsAutoCString charset;
3219 nsAutoCString defaultContentType;
3220 uint64_t size_u64;
3221 aRv = aBody->GetAsStream(getter_AddRefs(uploadStream), &size_u64,
3222 defaultContentType, charset);
3223 if (aRv.Failed()) {
3224 return;
3225 }
3226
3227 // make sure it fits within js MAX_SAFE_INTEGER
3228 mUploadTotal =
3229 net::InScriptableRange(size_u64) ? static_cast<int64_t>(size_u64) : -1;
3230
3231 if (uploadStream) {
3232 // If author set no Content-Type, use the default from GetAsStream().
3233 mAuthorRequestHeaders.Get("content-type", uploadContentType);
3234 if (uploadContentType.IsVoid()) {
3235 uploadContentType = defaultContentType;
3236 } else if (aBodyIsDocumentOrString) {
3237 RefPtr<CMimeType> contentTypeRecord =
3238 CMimeType::Parse(uploadContentType);
3239 nsAutoCString charset;
3240 if (contentTypeRecord &&
3241 contentTypeRecord->GetParameterValue(kLiteralString_charset,
3242 charset) &&
3243 !charset.EqualsIgnoreCase("utf-8")) {
3244 contentTypeRecord->SetParameterValue(kLiteralString_charset,
3245 kLiteralString_UTF_8);
3246 contentTypeRecord->Serialize(uploadContentType);
3247 }
3248 } else if (!charset.IsEmpty()) {
3249 // We don't want to set a charset for streams.
3250 // Replace all case-insensitive matches of the charset in the
3251 // content-type with the correct case.
3252 RequestHeaders::CharsetIterator iter(uploadContentType);
3253 while (iter.Next()) {
3254 if (!iter.Equals(charset, nsCaseInsensitiveCStringComparator)) {
3255 iter.Replace(charset);
3256 }
3257 }
3258 }
3259
3260 mUploadComplete = false;
3261 }
3262 }
3263
3264 ResetResponse();
3265
3266 // Check if we should enable cross-origin upload listeners.
3267 if (mUpload && mUpload->HasListeners()) {
3268 mFlagHadUploadListenersOnSend = true;
3269 }
3270
3271 mIsMappedArrayBuffer = false;
3272 if (mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
3273 StaticPrefs::dom_mapped_arraybuffer_enabled()) {
3274 nsCOMPtr<nsIURI> uri;
3275 nsAutoCString scheme;
3276
3277 aRv = mChannel->GetURI(getter_AddRefs(uri));
3278 if (!aRv.Failed()) {
3279 uri->GetScheme(scheme);
3280 if (scheme.LowerCaseEqualsLiteral("jar")) {
3281 mIsMappedArrayBuffer = true;
3282 }
3283 }
3284 }
3285
3286 aRv = InitiateFetch(uploadStream.forget(), mUploadTotal, uploadContentType);
3287 if (aRv.Failed()) {
3288 return;
3289 }
3290
3291 // Start our timeout
3292 mRequestSentTime = PR_Now();
3293 StartTimeoutTimer();
3294
3295 mWaitingForOnStopRequest = true;
3296
3297 // Step 8
3298 mFlagSend = true;
3299
3300 // If we're synchronous, spin an event loop here and wait
3301 RefPtr<Document> suspendedDoc;
3302 if (mFlagSynchronous) {
3303 auto scopeExit = MakeScopeExit([&] {
3304 CancelSyncTimeoutTimer();
3305 ResumeTimeout();
3306 ResumeEventDispatching();
3307 });
3308 Maybe<AutoSuppressEventHandling> autoSuppress;
3309
3310 mFlagSyncLooping = true;
3311
3312 nsCOMPtr<nsPIDOMWindowInner> window =
3313 GetWindowForSyncLoop(GetRelevantGlobal());
3314 if (window && window->GetOuterWindow()) {
3315 if (nsCOMPtr<nsPIDOMWindowOuter> topWindow =
3316 window->GetOuterWindow()->GetInProcessTop()) {
3317 if (nsCOMPtr<nsPIDOMWindowInner> topInner =
3318 topWindow->GetCurrentInnerWindow()) {
3319 suspendedDoc = topWindow->GetExtantDoc();
3320 autoSuppress.emplace(topWindow->GetBrowsingContext());
3321 topInner->Suspend();
3322 mResumeTimeoutRunnable = new nsResumeTimeoutsEvent(topInner);
3323 }
3324 }
3325 }
3326
3327 SuspendEventDispatching();
3328 StopProgressEventTimer();
3329
3330 SyncTimeoutType syncTimeoutType = MaybeStartSyncTimeoutTimer();
3331 if (syncTimeoutType == eErrorOrExpired) {
3332 Abort();
3333 aRv.Throw(NS_ERROR_DOM_NETWORK_ERR);
3334 return;
3335 }
3336
3337 nsresult channelStatus = NS_OK;
3338 nsAutoSyncOperation sync(suspendedDoc,
3339 SyncOperationBehavior::eSuspendInput);
3340 if (!SpinEventLoopUntil("XMLHttpRequestMainThread::SendInternal"_ns, [&]() {
3341 if (mFlagSyncLooping && mChannel) {
3342 // The purpose of this check is to enable XHR channel cancelation
3343 // upon navigating away from the page that is doing sync XHR
3344 // to genuinely make the sync XHR go away within the same task.
3345 mChannel->GetStatus(&channelStatus);
3346 // Can't change mFlagSyncLooping to false, because other
3347 // end-of-request code expects to be able to see it as true
3348 // still even if we exit the loop early due to the channel
3349 // getting canceled.
3350 }
3351 return !mFlagSyncLooping || NS_FAILED(channelStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(channelStatus)), 0
)))
;
3352 })) {
3353 aRv.Throw(NS_ERROR_UNEXPECTED);
3354 return;
3355 }
3356 if (NS_FAILED(channelStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(channelStatus)), 0
)))
) {
3357 MOZ_ASSERT(mFlagSyncLooping)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFlagSyncLooping)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFlagSyncLooping))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mFlagSyncLooping"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3357); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mFlagSyncLooping" ")"); do { MOZ_CrashSequence
(__null, 3357); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3358 // As mentioned above, when navigating away, we want channel cancelation
3359 // to make the sync XHR go away within the same task. This also requires
3360 // us to set the correct error result and dispatch events. So call
3361 // OnStopRequest explicitly instead of the channel calling it after
3362 // SendInternal has already completed.
3363 // Consecutive OnStopRequests are blocked due to mAlreadyGotStopRequest
3364 OnStopRequest(mChannel, channelStatus);
3365 }
3366
3367 // Time expired... We should throw.
3368 if (syncTimeoutType == eTimerStarted && !mSyncTimeoutTimer) {
3369 aRv.Throw(NS_ERROR_DOM_NETWORK_ERR);
3370 return;
3371 }
3372 } else {
3373 // Now that we've successfully opened the channel, we can change state. Note
3374 // that this needs to come after the AsyncOpen() and rv check, because this
3375 // can run script that would try to restart this request, and that could end
3376 // up doing our AsyncOpen on a null channel if the reentered AsyncOpen
3377 // fails.
3378 StopProgressEventTimer();
3379
3380 // Upload phase beginning; start the progress event timer if necessary.
3381 if (mUpload && mUpload->HasListenersFor(nsGkAtoms::onprogress)) {
3382 StartProgressEventTimer();
3383 }
3384 // Dispatch loadstart events
3385 DispatchProgressEvent(this, Events::loadstart, 0, -1);
3386 if (mUpload && !mUploadComplete) {
3387 DispatchProgressEvent(mUpload, Events::loadstart, 0, mUploadTotal);
3388 }
3389 }
3390
3391 if (!mChannel) {
3392 aRv = MaybeSilentSendFailure(NS_ERROR_DOM_NETWORK_ERR);
3393 }
3394}
3395
3396// http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader
3397void XMLHttpRequestMainThread::SetRequestHeader(const nsACString& aName,
3398 const nsACString& aValue,
3399 ErrorResult& aRv) {
3400 NOT_CALLABLE_IN_SYNC_SEND_RVif (mFlagSyncLooping || mEventDispatchingSuspended) { aRv.Throw
(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); return;
}
3401
3402 // Step 1
3403 if (mState != XMLHttpRequest_Binding::OPENED) {
3404 aRv.ThrowInvalidStateError("XMLHttpRequest state must be OPENED.");
3405 return;
3406 }
3407
3408 // Step 2
3409 if (mFlagSend) {
3410 aRv.ThrowInvalidStateError("XMLHttpRequest must not be sending.");
3411 return;
3412 }
3413
3414 // Step 3
3415 nsAutoCString value;
3416 NS_TrimHTTPWhitespace(aValue, value);
3417
3418 // Step 4
3419 if (!NS_IsValidHTTPToken(aName) || !NS_IsReasonableHTTPHeaderValue(value)) {
3420 aRv.Throw(NS_ERROR_DOM_INVALID_HEADER_NAME);
3421 return;
3422 }
3423
3424 // Step 5
3425 bool isPrivilegedCaller = IsSystemXHR();
3426 bool isForbiddenHeader =
3427 nsContentUtils::IsForbiddenRequestHeader(aName, aValue);
3428 if (!isPrivilegedCaller && isForbiddenHeader) {
3429 AutoTArray<nsString, 1> params;
3430 CopyUTF8toUTF16(aName, *params.AppendElement());
3431 LogMessage("ForbiddenHeaderWarning", GetOwnerWindow(), params);
3432 return;
3433 }
3434
3435 // Step 6.1
3436 // Skipping for now, as normalizing the case of header names may not be
3437 // web-compatible. See bug 1285036.
3438
3439 // Step 6.2-6.3
3440 // Gecko-specific: invalid headers can be set by privileged
3441 // callers, but will not merge.
3442 if (isPrivilegedCaller && isForbiddenHeader) {
3443 mAuthorRequestHeaders.Set(aName, value);
3444 } else {
3445 mAuthorRequestHeaders.MergeOrSet(aName, value);
3446 }
3447}
3448
3449void XMLHttpRequestMainThread::SetTimeout(uint32_t aTimeout, ErrorResult& aRv) {
3450 NOT_CALLABLE_IN_SYNC_SEND_RVif (mFlagSyncLooping || mEventDispatchingSuspended) { aRv.Throw
(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); return;
}
3451
3452 if (mFlagSynchronous && mState != XMLHttpRequest_Binding::UNSENT &&
3453 HasOrHasHadOwnerWindow()) {
3454 /* Timeout is not supported for synchronous requests with an owning window,
3455 per XHR2 spec. */
3456 LogMessage("TimeoutSyncXHRWarning", GetOwnerWindow());
3457 aRv.ThrowInvalidAccessError(
3458 "synchronous XMLHttpRequests do not support timeout and responseType");
3459 return;
3460 }
3461
3462 mTimeoutMilliseconds = aTimeout;
3463 if (mRequestSentTime) {
3464 StartTimeoutTimer();
3465 }
3466}
3467
3468nsIEventTarget* XMLHttpRequestMainThread::GetTimerEventTarget() {
3469 if (nsIGlobalObject* global = GetRelevantGlobal()) {
3470 return global->SerialEventTarget();
3471 }
3472 return nullptr;
3473}
3474
3475nsresult XMLHttpRequestMainThread::DispatchToMainThread(
3476 already_AddRefed<nsIRunnable> aRunnable) {
3477 DEBUG_WORKERREFSvoid();
3478 if (nsIGlobalObject* global = GetRelevantGlobal()) {
3479 return global->Dispatch(std::move(aRunnable));
3480 }
3481 return NS_DispatchToMainThread(std::move(aRunnable));
3482}
3483
3484void XMLHttpRequestMainThread::StartTimeoutTimer() {
3485 DEBUG_WORKERREFSvoid();
3486 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRequestSentTime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRequestSentTime))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mRequestSentTime"
" (" "StartTimeoutTimer mustn't be called before the request was sent!"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3488
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRequestSentTime"
") (" "StartTimeoutTimer mustn't be called before the request was sent!"
")"); do { MOZ_CrashSequence(__null, 3488); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3487 mRequestSentTime,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRequestSentTime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRequestSentTime))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mRequestSentTime"
" (" "StartTimeoutTimer mustn't be called before the request was sent!"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3488
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRequestSentTime"
") (" "StartTimeoutTimer mustn't be called before the request was sent!"
")"); do { MOZ_CrashSequence(__null, 3488); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3488 "StartTimeoutTimer mustn't be called before the request was sent!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRequestSentTime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRequestSentTime))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mRequestSentTime"
" (" "StartTimeoutTimer mustn't be called before the request was sent!"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3488
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRequestSentTime"
") (" "StartTimeoutTimer mustn't be called before the request was sent!"
")"); do { MOZ_CrashSequence(__null, 3488); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3489 if (mState == XMLHttpRequest_Binding::DONE) {
3490 // do nothing!
3491 return;
3492 }
3493
3494 CancelTimeoutTimer();
3495
3496 if (!mTimeoutMilliseconds) {
3497 return;
3498 }
3499
3500 if (!mTimeoutTimer) {
3501 mTimeoutTimer = NS_NewTimer(GetTimerEventTarget());
3502 }
3503 uint32_t elapsed =
3504 (uint32_t)((PR_Now() - mRequestSentTime) / PR_USEC_PER_MSEC1000L);
3505 mTimeoutTimer->InitWithCallback(
3506 this, mTimeoutMilliseconds > elapsed ? mTimeoutMilliseconds - elapsed : 0,
3507 nsITimer::TYPE_ONE_SHOT);
3508}
3509
3510uint16_t XMLHttpRequestMainThread::ReadyState() const { return mState; }
3511
3512void XMLHttpRequestMainThread::OverrideMimeType(const nsAString& aMimeType,
3513 ErrorResult& aRv) {
3514 NOT_CALLABLE_IN_SYNC_SEND_RVif (mFlagSyncLooping || mEventDispatchingSuspended) { aRv.Throw
(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); return;
}
3515
3516 if (mState == XMLHttpRequest_Binding::LOADING ||
3517 mState == XMLHttpRequest_Binding::DONE) {
3518 aRv.ThrowInvalidStateError(
3519 "Cannot call 'overrideMimeType()' on XMLHttpRequest after 'send()' "
3520 "(when its state is LOADING or DONE).");
3521 return;
3522 }
3523
3524 RefPtr<MimeType> parsed = MimeType::Parse(aMimeType);
3525 if (parsed) {
3526 parsed->Serialize(mOverrideMimeType);
3527 } else {
3528 mOverrideMimeType.AssignLiteral(APPLICATION_OCTET_STREAM"application/octet-stream");
3529 }
3530}
3531
3532bool XMLHttpRequestMainThread::MozBackgroundRequest() const {
3533 return mFlagBackgroundRequest;
3534}
3535
3536void XMLHttpRequestMainThread::SetMozBackgroundRequestExternal(
3537 bool aMozBackgroundRequest, ErrorResult& aRv) {
3538 if (!IsSystemXHR()) {
3539 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
3540 return;
3541 }
3542
3543 if (mState != XMLHttpRequest_Binding::UNSENT) {
3544 // Can't change this while we're in the middle of something.
3545 aRv.ThrowInvalidStateError("XMLHttpRequest must not be sending.");
3546 return;
3547 }
3548
3549 mFlagBackgroundRequest = aMozBackgroundRequest;
3550}
3551
3552void XMLHttpRequestMainThread::SetMozBackgroundRequest(
3553 bool aMozBackgroundRequest, ErrorResult& aRv) {
3554 // No errors for this webIDL method on main-thread.
3555 SetMozBackgroundRequestExternal(aMozBackgroundRequest, IgnoreErrors());
3556}
3557
3558void XMLHttpRequestMainThread::SetOriginStack(
3559 UniquePtr<SerializedStackHolder> aOriginStack) {
3560 mOriginStack = std::move(aOriginStack);
3561}
3562
3563void XMLHttpRequestMainThread::SetSource(
3564 UniquePtr<ProfileChunkedBuffer> aSource) {
3565 if (!mChannel) {
3566 return;
3567 }
3568 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
3569
3570 if (httpChannel) {
3571 httpChannel->SetSource(std::move(aSource));
3572 }
3573}
3574
3575bool XMLHttpRequestMainThread::WithCredentials() const {
3576 return mFlagACwithCredentials;
3577}
3578
3579void XMLHttpRequestMainThread::SetWithCredentials(bool aWithCredentials,
3580 ErrorResult& aRv) {
3581 NOT_CALLABLE_IN_SYNC_SEND_RVif (mFlagSyncLooping || mEventDispatchingSuspended) { aRv.Throw
(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT); return;
}
3582
3583 // Return error if we're already processing a request. Note that we can't use
3584 // ReadyState() here, because it can't differentiate between "opened" and
3585 // "sent", so we use mState directly.
3586
3587 if ((mState != XMLHttpRequest_Binding::UNSENT &&
3588 mState != XMLHttpRequest_Binding::OPENED) ||
3589 mFlagSend || mIsAnon) {
3590 aRv.ThrowInvalidStateError("XMLHttpRequest must not be sending.");
3591 return;
3592 }
3593
3594 mFlagACwithCredentials = aWithCredentials;
3595}
3596
3597nsresult XMLHttpRequestMainThread::ChangeState(uint16_t aState,
3598 bool aBroadcast) {
3599 mState = aState;
3600 nsresult rv = NS_OK;
3601
3602 if (aState != XMLHttpRequest_Binding::HEADERS_RECEIVED &&
3603 aState != XMLHttpRequest_Binding::LOADING) {
3604 StopProgressEventTimer();
3605 }
3606
3607 if (aBroadcast &&
3608 (!mFlagSynchronous || aState == XMLHttpRequest_Binding::OPENED ||
3609 aState == XMLHttpRequest_Binding::DONE)) {
3610 rv = FireReadystatechangeEvent();
3611 }
3612
3613 return rv;
3614}
3615
3616/////////////////////////////////////////////////////
3617// nsIChannelEventSink methods:
3618//
3619NS_IMETHODIMPnsresult
3620XMLHttpRequestMainThread::AsyncOnChannelRedirect(
3621 nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags,
3622 nsIAsyncVerifyRedirectCallback* callback) {
3623 DEBUG_WORKERREFSvoid();
3624 MOZ_ASSERT(aNewChannel, "Redirect without a channel?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewChannel)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewChannel))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aNewChannel" " ("
"Redirect without a channel?" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 3624); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewChannel"
") (" "Redirect without a channel?" ")"); do { MOZ_CrashSequence
(__null, 3624); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3625
3626 // Prepare to receive callback
3627 mRedirectCallback = callback;
3628 mNewRedirectChannel = aNewChannel;
3629
3630 if (mChannelEventSink) {
3631 nsCOMPtr<nsIAsyncVerifyRedirectCallback> fwd = EnsureXPCOMifier();
3632
3633 nsresult rv = mChannelEventSink->AsyncOnChannelRedirect(
3634 aOldChannel, aNewChannel, aFlags, fwd);
3635 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3636 mRedirectCallback = nullptr;
3637 mNewRedirectChannel = nullptr;
3638 }
3639 return rv;
3640 }
3641
3642 // we need to strip Authentication headers for cross-origin requests
3643 // Ref: https://fetch.spec.whatwg.org/#http-redirect-fetch
3644 bool stripAuth =
3645 NS_ShouldRemoveAuthHeaderOnRedirect(aOldChannel, aNewChannel, aFlags);
3646
3647 OnRedirectVerifyCallback(NS_OK, stripAuth);
3648
3649 return NS_OK;
3650}
3651
3652nsresult XMLHttpRequestMainThread::OnRedirectVerifyCallback(nsresult result,
3653 bool aStripAuth) {
3654 DEBUG_WORKERREFSvoid();
3655 NS_ASSERTION(mRedirectCallback, "mRedirectCallback not set in callback")do { if (!(mRedirectCallback)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "mRedirectCallback not set in callback", "mRedirectCallback"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3655); MOZ_PretendNoReturn
(); } } while (0)
;
3656 NS_ASSERTION(mNewRedirectChannel, "mNewRedirectChannel not set in callback")do { if (!(mNewRedirectChannel)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "mNewRedirectChannel not set in callback", "mNewRedirectChannel"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3656); MOZ_PretendNoReturn
(); } } while (0)
;
3657
3658 if (NS_SUCCEEDED(result)((bool)(__builtin_expect(!!(!NS_FAILED_impl(result)), 1)))) {
3659 bool rewriteToGET = false;
3660 nsCOMPtr<nsIHttpChannel> oldHttpChannel = GetCurrentHttpChannel();
3661 // Fetch 4.4.11
3662 (void)oldHttpChannel->ShouldStripRequestBodyHeader(mRequestMethod,
3663 &rewriteToGET);
3664
3665 mChannel = mNewRedirectChannel;
3666
3667 nsCOMPtr<nsIHttpChannel> newHttpChannel(do_QueryInterface(mChannel));
3668 if (newHttpChannel) {
3669 // Ensure all original headers are duplicated for the new channel (bug
3670 // #553888)
3671 mAuthorRequestHeaders.ApplyToChannel(newHttpChannel, rewriteToGET,
3672 aStripAuth);
3673 }
3674 } else {
3675 mErrorLoad = ErrorType::eRedirect;
3676 mErrorLoadDetail = result;
3677 }
3678
3679 mNewRedirectChannel = nullptr;
3680
3681 mRedirectCallback->OnRedirectVerifyCallback(result);
3682 mRedirectCallback = nullptr;
3683
3684 // It's important that we return success here. If we return the result code
3685 // that we were passed, JavaScript callers who cancel the redirect will wind
3686 // up throwing an exception in the process.
3687 return NS_OK;
3688}
3689
3690/////////////////////////////////////////////////////
3691// nsIProgressEventSink methods:
3692//
3693
3694NS_IMETHODIMPnsresult
3695XMLHttpRequestMainThread::OnProgress(nsIRequest* aRequest, int64_t aProgress,
3696 int64_t aProgressMax) {
3697 DEBUG_WORKERREFSvoid();
3698 // When uploading, OnProgress reports also headers in aProgress and
3699 // aProgressMax. So, try to remove the headers, if possible.
3700 bool lengthComputable = (aProgressMax != -1);
3701 if (InUploadPhase()) {
3702 int64_t loaded = aProgress;
3703 if (lengthComputable) {
3704 int64_t headerSize = aProgressMax - mUploadTotal;
3705 loaded -= headerSize;
3706 }
3707 mUploadTransferred = loaded;
3708 mProgressSinceLastProgressEvent = true;
3709
3710 if (!mFlagSynchronous && !mProgressTimerIsActive) {
3711 StartProgressEventTimer();
3712 }
3713 } else {
3714 mLoadTotal = aProgressMax;
3715 mLoadTransferred = aProgress;
3716 // OnDataAvailable() handles mProgressSinceLastProgressEvent
3717 // for the download phase.
3718 }
3719
3720 if (mProgressEventSink) {
3721 mProgressEventSink->OnProgress(aRequest, aProgress, aProgressMax);
3722 }
3723
3724 return NS_OK;
3725}
3726
3727NS_IMETHODIMPnsresult
3728XMLHttpRequestMainThread::OnStatus(nsIRequest* aRequest, nsresult aStatus,
3729 const char16_t* aStatusArg) {
3730 DEBUG_WORKERREFSvoid();
3731 if (mProgressEventSink) {
3732 mProgressEventSink->OnStatus(aRequest, aStatus, aStatusArg);
3733 }
3734
3735 return NS_OK;
3736}
3737
3738bool XMLHttpRequestMainThread::AllowUploadProgress() {
3739 return !IsCrossSiteCORSRequest() || mFlagHadUploadListenersOnSend;
3740}
3741
3742/////////////////////////////////////////////////////
3743// nsIInterfaceRequestor methods:
3744//
3745NS_IMETHODIMPnsresult
3746XMLHttpRequestMainThread::GetInterface(const nsIID& aIID, void** aResult) {
3747 nsresult rv;
3748
3749 // Make sure to return ourselves for the channel event sink interface and
3750 // progress event sink interface, no matter what. We can forward these to
3751 // mNotificationCallbacks if it wants to get notifications for them. But we
3752 // need to see these notifications for proper functioning.
3753 if (aIID.Equals(NS_GET_IID(nsIChannelEventSink)(nsIChannelEventSink::kIID))) {
3754 mChannelEventSink = do_GetInterface(mNotificationCallbacks);
3755 *aResult = static_cast<nsIChannelEventSink*>(EnsureXPCOMifier().take());
3756 return NS_OK;
3757 } else if (aIID.Equals(NS_GET_IID(nsIProgressEventSink)(nsIProgressEventSink::kIID))) {
3758 mProgressEventSink = do_GetInterface(mNotificationCallbacks);
3759 *aResult = static_cast<nsIProgressEventSink*>(EnsureXPCOMifier().take());
3760 return NS_OK;
3761 }
3762
3763 // Now give mNotificationCallbacks (if non-null) a chance to return the
3764 // desired interface.
3765 if (mNotificationCallbacks) {
3766 rv = mNotificationCallbacks->GetInterface(aIID, aResult);
3767 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3768 NS_ASSERTION(*aResult, "Lying nsIInterfaceRequestor implementation!")do { if (!(*aResult)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Lying nsIInterfaceRequestor implementation!"
, "*aResult", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 3768); MOZ_PretendNoReturn(); } } while (0)
;
3769 return rv;
3770 }
3771 }
3772
3773 if (!mFlagBackgroundRequest && (aIID.Equals(NS_GET_IID(nsIAuthPrompt)(nsIAuthPrompt::kIID)) ||
3774 aIID.Equals(NS_GET_IID(nsIAuthPrompt2)(nsIAuthPrompt2::kIID)))) {
3775 nsCOMPtr<nsIPromptFactory> wwatch =
3776 do_GetService(NS_WINDOWWATCHER_CONTRACTID"@mozilla.org/embedcomp/window-watcher;1", &rv);
3777 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, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 3777); return rv; } } while (false)
;
3778
3779 // Get the an auth prompter for our window so that the parenting
3780 // of the dialogs works as it should when using tabs.
3781 nsCOMPtr<nsPIDOMWindowOuter> window;
3782 if (nsGlobalWindowInner* inner = GetOwnerWindow()) {
3783 window = inner->GetOuterWindow();
3784 }
3785 return wwatch->GetPrompt(window, aIID, reinterpret_cast<void**>(aResult));
3786 }
3787
3788 // Now check for the various XHR non-DOM interfaces, except
3789 // nsIProgressEventSink and nsIChannelEventSink which we already
3790 // handled above.
3791 if (aIID.Equals(NS_GET_IID(nsIStreamListener)(nsIStreamListener::kIID))) {
3792 *aResult = static_cast<nsIStreamListener*>(EnsureXPCOMifier().take());
3793 return NS_OK;
3794 }
3795 if (aIID.Equals(NS_GET_IID(nsIRequestObserver)(nsIRequestObserver::kIID))) {
3796 *aResult = static_cast<nsIRequestObserver*>(EnsureXPCOMifier().take());
3797 return NS_OK;
3798 }
3799 if (aIID.Equals(NS_GET_IID(nsITimerCallback)(nsITimerCallback::kIID))) {
3800 *aResult = static_cast<nsITimerCallback*>(EnsureXPCOMifier().take());
3801 return NS_OK;
3802 }
3803
3804 return QueryInterface(aIID, aResult);
3805}
3806
3807void XMLHttpRequestMainThread::GetInterface(
3808 JSContext* aCx, JS::Handle<JS::Value> aIID,
3809 JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv) {
3810 dom::GetInterface(aCx, this, aIID, aRetval, aRv);
3811}
3812
3813XMLHttpRequestUpload* XMLHttpRequestMainThread::GetUpload(ErrorResult& aRv) {
3814 if (!mUpload) {
3815 mUpload = new XMLHttpRequestUpload(this);
3816 }
3817 return mUpload;
3818}
3819
3820bool XMLHttpRequestMainThread::MozAnon() const { return mIsAnon; }
3821
3822bool XMLHttpRequestMainThread::MozSystem() const { return IsSystemXHR(); }
3823
3824void XMLHttpRequestMainThread::HandleTimeoutCallback() {
3825 DEBUG_WORKERREFSvoid();
3826 if (mState == XMLHttpRequest_Binding::DONE) {
3827 MOZ_ASSERT_UNREACHABLE(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"XMLHttpRequestMainThread::HandleTimeoutCallback " "with completed request"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3829
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: "
"XMLHttpRequestMainThread::HandleTimeoutCallback " "with completed request"
")"); do { MOZ_CrashSequence(__null, 3829); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3828 "XMLHttpRequestMainThread::HandleTimeoutCallback "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"XMLHttpRequestMainThread::HandleTimeoutCallback " "with completed request"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3829
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: "
"XMLHttpRequestMainThread::HandleTimeoutCallback " "with completed request"
")"); do { MOZ_CrashSequence(__null, 3829); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3829 "with completed request")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"XMLHttpRequestMainThread::HandleTimeoutCallback " "with completed request"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3829
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: "
"XMLHttpRequestMainThread::HandleTimeoutCallback " "with completed request"
")"); do { MOZ_CrashSequence(__null, 3829); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3830 // do nothing!
3831 return;
3832 }
3833
3834 mFlagTimedOut = true;
3835 CloseRequestWithError(Events::timeout);
3836}
3837
3838void XMLHttpRequestMainThread::CancelTimeoutTimer() {
3839 DEBUG_WORKERREFSvoid();
3840 if (mTimeoutTimer) {
3841 mTimeoutTimer->Cancel();
3842 mTimeoutTimer = nullptr;
3843 }
3844}
3845
3846NS_IMETHODIMPnsresult
3847XMLHttpRequestMainThread::Notify(nsITimer* aTimer) {
3848 DEBUG_WORKERREFSvoid();
3849 if (mProgressNotifier == aTimer) {
3850 HandleProgressTimerCallback();
3851 return NS_OK;
3852 }
3853
3854 if (mTimeoutTimer == aTimer) {
3855 HandleTimeoutCallback();
3856 return NS_OK;
3857 }
3858
3859 if (mSyncTimeoutTimer == aTimer) {
3860 HandleSyncTimeoutTimer();
3861 return NS_OK;
3862 }
3863
3864 // Just in case some JS user wants to QI to nsITimerCallback and play with
3865 // us...
3866 NS_WARNING("Unexpected timer!")NS_DebugBreak(NS_DEBUG_WARNING, "Unexpected timer!", nullptr,
"./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3866)
;
3867 return NS_ERROR_INVALID_POINTER;
3868}
3869
3870void XMLHttpRequestMainThread::HandleProgressTimerCallback() {
3871 DEBUG_WORKERREFSvoid();
3872 // Don't fire the progress event if mLoadTotal is 0, see XHR spec step 6.1
3873 if (!mLoadTotal && mLoadTransferred) {
3874 return;
3875 }
3876
3877 mProgressTimerIsActive = false;
3878
3879 if (!mProgressSinceLastProgressEvent || mErrorLoad != ErrorType::eOK) {
3880 return;
3881 }
3882
3883 if (InUploadPhase()) {
3884 if (mUpload && !mUploadComplete && mFlagHadUploadListenersOnSend) {
3885 DispatchProgressEvent(mUpload, Events::progress, mUploadTransferred,
3886 mUploadTotal);
3887 }
3888 } else {
3889 // Don't fire events when state is UNSENT. This can happen if abort() was
3890 // called and changed the state to UNSENT, but this timer callback was
3891 // already queued. Per spec, readystatechange doesn't fire when changing to
3892 // UNSENT, and progress events only fire during data transmission.
3893 if (mState != XMLHttpRequest_Binding::UNSENT) {
3894 FireReadystatechangeEvent();
3895 DispatchProgressEvent(this, Events::progress, mLoadTransferred,
3896 mLoadTotal);
3897 }
3898 }
3899
3900 mProgressSinceLastProgressEvent = false;
3901
3902 // Don't restart the timer if we're in UNSENT state.
3903 if (mState != XMLHttpRequest_Binding::UNSENT) {
3904 StartProgressEventTimer();
3905 }
3906}
3907
3908void XMLHttpRequestMainThread::StopProgressEventTimer() {
3909 if (mProgressNotifier) {
3910 mProgressTimerIsActive = false;
3911 mProgressNotifier->Cancel();
3912 }
3913}
3914
3915void XMLHttpRequestMainThread::StartProgressEventTimer() {
3916 if (!mProgressNotifier) {
3917 mProgressNotifier = NS_NewTimer(GetTimerEventTarget());
3918 }
3919 if (mProgressNotifier) {
3920 mProgressTimerIsActive = true;
3921 mProgressNotifier->Cancel();
3922 mProgressNotifier->InitWithCallback(this, NS_PROGRESS_EVENT_INTERVAL50,
3923 nsITimer::TYPE_ONE_SHOT);
3924 }
3925}
3926
3927XMLHttpRequestMainThread::SyncTimeoutType
3928XMLHttpRequestMainThread::MaybeStartSyncTimeoutTimer() {
3929 MOZ_ASSERT(mFlagSynchronous)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFlagSynchronous)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFlagSynchronous))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mFlagSynchronous"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3929); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mFlagSynchronous" ")"); do { MOZ_CrashSequence
(__null, 3929); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3930
3931 Document* doc = GetDocumentIfCurrent();
3932 if (!doc || !doc->GetPageUnloadingEventTimeStamp()) {
3933 return eNoTimerNeeded;
3934 }
3935
3936 // If we are in a beforeunload or a unload event, we must force a timeout.
3937 TimeDuration diff =
3938 (TimeStamp::NowLoRes() - doc->GetPageUnloadingEventTimeStamp());
3939 if (diff.ToMilliseconds() > MAX_SYNC_TIMEOUT_WHEN_UNLOADING10000) {
3940 return eErrorOrExpired;
3941 }
3942
3943 mSyncTimeoutTimer = NS_NewTimer(GetTimerEventTarget());
3944 if (!mSyncTimeoutTimer) {
3945 return eErrorOrExpired;
3946 }
3947
3948 uint32_t timeout = MAX_SYNC_TIMEOUT_WHEN_UNLOADING10000 - diff.ToMilliseconds();
3949 nsresult rv = mSyncTimeoutTimer->InitWithCallback(this, timeout,
3950 nsITimer::TYPE_ONE_SHOT);
3951 return NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) ? eErrorOrExpired : eTimerStarted;
3952}
3953
3954void XMLHttpRequestMainThread::HandleSyncTimeoutTimer() {
3955 MOZ_ASSERT(mSyncTimeoutTimer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSyncTimeoutTimer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSyncTimeoutTimer))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mSyncTimeoutTimer"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3955); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mSyncTimeoutTimer" ")"); do { MOZ_CrashSequence
(__null, 3955); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3956 MOZ_ASSERT(mFlagSyncLooping)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFlagSyncLooping)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFlagSyncLooping))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mFlagSyncLooping"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 3956); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mFlagSyncLooping" ")"); do { MOZ_CrashSequence
(__null, 3956); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3957
3958 CancelSyncTimeoutTimer();
3959 Abort();
3960 mErrorLoadDetail = NS_ERROR_DOM_TIMEOUT_ERR;
3961}
3962
3963void XMLHttpRequestMainThread::CancelSyncTimeoutTimer() {
3964 if (mSyncTimeoutTimer) {
3965 mSyncTimeoutTimer->Cancel();
3966 mSyncTimeoutTimer = nullptr;
3967 }
3968}
3969
3970already_AddRefed<nsXMLHttpRequestXPCOMifier>
3971XMLHttpRequestMainThread::EnsureXPCOMifier() {
3972 if (!mXPCOMifier) {
3973 mXPCOMifier = new nsXMLHttpRequestXPCOMifier(this);
3974 }
3975 RefPtr<nsXMLHttpRequestXPCOMifier> newRef(mXPCOMifier);
3976 return newRef.forget();
3977}
3978
3979bool XMLHttpRequestMainThread::ShouldBlockAuthPrompt() {
3980 // Verify that it's ok to prompt for credentials here, per spec
3981 // http://xhr.spec.whatwg.org/#the-send%28%29-method
3982
3983 if (mAuthorRequestHeaders.Has("authorization")) {
3984 return true;
3985 }
3986
3987 nsCOMPtr<nsIURI> uri;
3988 nsresult rv = mChannel->GetURI(getter_AddRefs(uri));
3989 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 3989)
) {
3990 return false;
3991 }
3992
3993 // Also skip if a username and/or password is provided in the URI.
3994 bool hasUserPass;
3995 return NS_SUCCEEDED(uri->GetHasUserPass(&hasUserPass))((bool)(__builtin_expect(!!(!NS_FAILED_impl(uri->GetHasUserPass
(&hasUserPass))), 1)))
&& hasUserPass;
3996}
3997
3998void XMLHttpRequestMainThread::TruncateResponseText() {
3999 mResponseText.Truncate();
4000 XMLHttpRequest_Binding::ClearCachedResponseTextValue(this);
4001}
4002
4003NS_IMPL_ISUPPORTS(XMLHttpRequestMainThread::nsHeaderVisitor,MozExternalRefCountType XMLHttpRequestMainThread::nsHeaderVisitor
::AddRef(void) { static_assert(!std::is_destructible_v<XMLHttpRequestMainThread
::nsHeaderVisitor>, "Reference-counted class " "XMLHttpRequestMainThread::nsHeaderVisitor"
" 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" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4004); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 4004
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("XMLHttpRequestMainThread::nsHeaderVisitor" != nullptr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("XMLHttpRequestMainThread::nsHeaderVisitor" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"XMLHttpRequestMainThread::nsHeaderVisitor\" != nullptr" " ("
"Must specify a name" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4004); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"XMLHttpRequestMainThread::nsHeaderVisitor\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 4004); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("XMLHttpRequestMainThread::nsHeaderVisitor" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"XMLHttpRequestMainThread::nsHeaderVisitor"), (uint32_t)(sizeof
(*this))); return count; } MozExternalRefCountType XMLHttpRequestMainThread
::nsHeaderVisitor::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"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 4004
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 4004
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("XMLHttpRequestMainThread::nsHeaderVisitor" != nullptr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("XMLHttpRequestMainThread::nsHeaderVisitor" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"XMLHttpRequestMainThread::nsHeaderVisitor\" != nullptr" " ("
"Must specify a name" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4004); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"XMLHttpRequestMainThread::nsHeaderVisitor\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 4004); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("XMLHttpRequestMainThread::nsHeaderVisitor" " not thread-safe"
); const char* const nametmp = "XMLHttpRequestMainThread::nsHeaderVisitor"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult XMLHttpRequestMainThread::nsHeaderVisitor
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 4004); 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
<XMLHttpRequestMainThread::nsHeaderVisitor, nsIHttpHeaderVisitor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIHttpHeaderVisitor
*>((XMLHttpRequestMainThread::nsHeaderVisitor*)0x1000)) - reinterpret_cast
<char*>((XMLHttpRequestMainThread::nsHeaderVisitor*)0x1000
))}, {&mozilla::detail::kImplementedIID<XMLHttpRequestMainThread
::nsHeaderVisitor, nsISupports>, int32_t(reinterpret_cast<
char*>(static_cast<nsISupports*>( static_cast<nsIHttpHeaderVisitor
*>((XMLHttpRequestMainThread::nsHeaderVisitor*)0x1000))) -
reinterpret_cast<char*>((XMLHttpRequestMainThread::nsHeaderVisitor
*)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; }
4004 nsIHttpHeaderVisitor)MozExternalRefCountType XMLHttpRequestMainThread::nsHeaderVisitor
::AddRef(void) { static_assert(!std::is_destructible_v<XMLHttpRequestMainThread
::nsHeaderVisitor>, "Reference-counted class " "XMLHttpRequestMainThread::nsHeaderVisitor"
" 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" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4004); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 4004
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("XMLHttpRequestMainThread::nsHeaderVisitor" != nullptr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("XMLHttpRequestMainThread::nsHeaderVisitor" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"XMLHttpRequestMainThread::nsHeaderVisitor\" != nullptr" " ("
"Must specify a name" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4004); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"XMLHttpRequestMainThread::nsHeaderVisitor\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 4004); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("XMLHttpRequestMainThread::nsHeaderVisitor" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"XMLHttpRequestMainThread::nsHeaderVisitor"), (uint32_t)(sizeof
(*this))); return count; } MozExternalRefCountType XMLHttpRequestMainThread
::nsHeaderVisitor::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"
")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 4004
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 4004
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("XMLHttpRequestMainThread::nsHeaderVisitor" != nullptr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("XMLHttpRequestMainThread::nsHeaderVisitor" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"XMLHttpRequestMainThread::nsHeaderVisitor\" != nullptr" " ("
"Must specify a name" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4004); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"XMLHttpRequestMainThread::nsHeaderVisitor\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 4004); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("XMLHttpRequestMainThread::nsHeaderVisitor" " not thread-safe"
); const char* const nametmp = "XMLHttpRequestMainThread::nsHeaderVisitor"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult XMLHttpRequestMainThread::nsHeaderVisitor
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 4004); 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
<XMLHttpRequestMainThread::nsHeaderVisitor, nsIHttpHeaderVisitor
>, int32_t( reinterpret_cast<char*>(static_cast<nsIHttpHeaderVisitor
*>((XMLHttpRequestMainThread::nsHeaderVisitor*)0x1000)) - reinterpret_cast
<char*>((XMLHttpRequestMainThread::nsHeaderVisitor*)0x1000
))}, {&mozilla::detail::kImplementedIID<XMLHttpRequestMainThread
::nsHeaderVisitor, nsISupports>, int32_t(reinterpret_cast<
char*>(static_cast<nsISupports*>( static_cast<nsIHttpHeaderVisitor
*>((XMLHttpRequestMainThread::nsHeaderVisitor*)0x1000))) -
reinterpret_cast<char*>((XMLHttpRequestMainThread::nsHeaderVisitor
*)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; }
4005
4006NS_IMETHODIMPnsresult XMLHttpRequestMainThread::nsHeaderVisitor::VisitHeader(
4007 const nsACString& header, const nsACString& value) {
4008 if (mXHR.IsSafeHeader(header, mHttpChannel)) {
4009 nsAutoCString lowerHeader(header);
4010 ToLowerCase(lowerHeader);
4011 if (!mHeaderList.InsertElementSorted(HeaderEntry(lowerHeader, value),
4012 fallible)) {
4013 return NS_ERROR_OUT_OF_MEMORY;
4014 }
4015 }
4016 return NS_OK;
4017}
4018
4019XMLHttpRequestMainThread::nsHeaderVisitor::nsHeaderVisitor(
4020 const XMLHttpRequestMainThread& aXMLHttpRequest,
4021 NotNull<nsIHttpChannel*> aHttpChannel)
4022 : mXHR(aXMLHttpRequest), mHttpChannel(aHttpChannel) {}
4023
4024XMLHttpRequestMainThread::nsHeaderVisitor::~nsHeaderVisitor() = default;
4025
4026void XMLHttpRequestMainThread::MaybeCreateBlobStorage() {
4027 DEBUG_WORKERREFSvoid();
4028 MOZ_ASSERT(mResponseType == XMLHttpRequestResponseType::Blob)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mResponseType == XMLHttpRequestResponseType::Blob)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mResponseType == XMLHttpRequestResponseType::Blob)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mResponseType == XMLHttpRequestResponseType::Blob"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 4028); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mResponseType == XMLHttpRequestResponseType::Blob"
")"); do { MOZ_CrashSequence(__null, 4028); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4029
4030 if (mBlobStorage) {
4031 return;
4032 }
4033
4034 MutableBlobStorage::MutableBlobStorageType storageType =
4035 BasePrincipal::Cast(mPrincipal)->PrivateBrowsingId() == 0
4036 ? MutableBlobStorage::eCouldBeInTemporaryFile
4037 : MutableBlobStorage::eOnlyInMemory;
4038
4039 nsCOMPtr<nsIEventTarget> eventTarget;
4040 if (nsIGlobalObject* global = GetRelevantGlobal()) {
4041 eventTarget = global->SerialEventTarget();
4042 }
4043
4044 mBlobStorage = new MutableBlobStorage(storageType, eventTarget);
4045}
4046
4047void XMLHttpRequestMainThread::BlobStoreCompleted(
4048 MutableBlobStorage* aBlobStorage, BlobImpl* aBlobImpl, nsresult aRv) {
4049 DEBUG_WORKERREFSvoid();
4050 // Ok, the state is changed...
4051 if (mBlobStorage != aBlobStorage || NS_FAILED(aRv)((bool)(__builtin_expect(!!(NS_FAILED_impl(aRv)), 0)))) {
4052 return;
4053 }
4054
4055 MOZ_ASSERT(mState != XMLHttpRequest_Binding::DONE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mState != XMLHttpRequest_Binding::DONE)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mState != XMLHttpRequest_Binding::DONE))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mState != XMLHttpRequest_Binding::DONE"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 4055); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mState != XMLHttpRequest_Binding::DONE" ")"
); do { MOZ_CrashSequence(__null, 4055); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4056
4057 mResponseBlobImpl = aBlobImpl;
4058 mBlobStorage = nullptr;
4059
4060 ChangeStateToDone(mFlagSyncLooping);
4061}
4062
4063NS_IMETHODIMPnsresult
4064XMLHttpRequestMainThread::GetName(nsACString& aName) {
4065 aName.AssignLiteral("XMLHttpRequest");
4066 return NS_OK;
4067}
4068
4069// nsXMLHttpRequestXPCOMifier implementation
4070NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLHttpRequestXPCOMifier)nsresult nsXMLHttpRequestXPCOMifier::QueryInterface(const nsIID
& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4070); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::kIID), (nsCycleCollectionISupports::kIID)) && (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::kIID)) || LowWordEquals
(aIID, (nsCycleCollectionISupports::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::kIID))) { *aInstancePtr
= nsXMLHttpRequestXPCOMifier::cycleCollection::GetParticipant
(); return NS_OK; } if (LowWordEquals(aIID, (nsCycleCollectionISupports
::kIID))) { *aInstancePtr = nsXMLHttpRequestXPCOMifier::cycleCollection
::Upcast(this); return NS_OK; } foundInterface = nullptr; } else
4071 NS_INTERFACE_MAP_ENTRY(nsIStreamListener)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIStreamListener>)) foundInterface
= static_cast<nsIStreamListener*>(this); else
4072 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIRequestObserver>)) foundInterface
= static_cast<nsIRequestObserver*>(this); else
4073 NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIChannelEventSink>)) foundInterface
= static_cast<nsIChannelEventSink*>(this); else
4074 NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIAsyncVerifyRedirectCallback>))
foundInterface = static_cast<nsIAsyncVerifyRedirectCallback
*>(this); else
4075 NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIProgressEventSink>)) foundInterface
= static_cast<nsIProgressEventSink*>(this); else
4076 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIInterfaceRequestor>)) foundInterface
= static_cast<nsIInterfaceRequestor*>(this); else
4077 NS_INTERFACE_MAP_ENTRY(nsITimerCallback)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsITimerCallback>)) foundInterface
= static_cast<nsITimerCallback*>(this); else
4078 NS_INTERFACE_MAP_ENTRY(nsINamed)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsINamed>)) foundInterface = static_cast
<nsINamed*>(this); else
4079 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamListener)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(static_cast<nsIStreamListener*>(this
)); else
4080NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::kIID
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aIID.Equals((nsISupports::kIID))", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::kIID))"
")"); do { MOZ_CrashSequence(__null, 4080); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
4081
4082NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXMLHttpRequestXPCOMifier)MozExternalRefCountType nsXMLHttpRequestXPCOMifier::AddRef(void
) { static_assert(!std::is_destructible_v<nsXMLHttpRequestXPCOMifier
>, "Reference-counted class " "nsXMLHttpRequestXPCOMifier"
" 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" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 4082
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("nsXMLHttpRequestXPCOMifier"
" not thread-safe"); nsISupports* base = nsXMLHttpRequestXPCOMifier
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr
(base); NS_LogAddRef((this), (count), ("nsXMLHttpRequestXPCOMifier"
), (uint32_t)(sizeof(*this))); return count; }
4083NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXMLHttpRequestXPCOMifier)MozExternalRefCountType nsXMLHttpRequestXPCOMifier::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" ")", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4083); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 4083
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("nsXMLHttpRequestXPCOMifier"
" not thread-safe"); nsISupports* base = nsXMLHttpRequestXPCOMifier
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.decr
(base); if (count == 0) { NS_CycleCollectableHasRefCntZero();
} NS_LogRelease((this), (count), ("nsXMLHttpRequestXPCOMifier"
)); return count; } void nsXMLHttpRequestXPCOMifier::DeleteCycleCollectable
(void) { delete (this); }
4084
4085// Can't NS_IMPL_CYCLE_COLLECTION( because mXHR has ambiguous
4086// inheritance from nsISupports.
4087NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequestXPCOMifier)nsXMLHttpRequestXPCOMifier::cycleCollection nsXMLHttpRequestXPCOMifier
::_cycleCollectorGlobal;
4088
4089NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXMLHttpRequestXPCOMifier)void nsXMLHttpRequestXPCOMifier::cycleCollection::Unlink(void
* p) { nsXMLHttpRequestXPCOMifier* tmp = DowncastCCParticipant
<nsXMLHttpRequestXPCOMifier>(p);
4090 if (tmp->mXHR) {
4091 tmp->mXHR->mXPCOMifier = nullptr;
4092 }
4093 NS_IMPL_CYCLE_COLLECTION_UNLINK(mXHR)ImplCycleCollectionUnlink(tmp->mXHR);
4094NS_IMPL_CYCLE_COLLECTION_UNLINK_END(void)tmp; }
4095
4096NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXMLHttpRequestXPCOMifier)nsresult nsXMLHttpRequestXPCOMifier::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsXMLHttpRequestXPCOMifier
* tmp = DowncastCCParticipant<nsXMLHttpRequestXPCOMifier>
(p); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "nsXMLHttpRequestXPCOMifier"
);
4097 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXHR)ImplCycleCollectionTraverse(cb, tmp->mXHR, "mXHR", 0);
4098NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END(void)tmp; return NS_OK; }
4099
4100NS_IMETHODIMPnsresult
4101nsXMLHttpRequestXPCOMifier::GetInterface(const nsIID& aIID, void** aResult) {
4102 // Return ourselves for the things we implement (except
4103 // nsIInterfaceRequestor) and the XHR for the rest.
4104 if (!aIID.Equals(NS_GET_IID(nsIInterfaceRequestor)(nsIInterfaceRequestor::kIID))) {
4105 nsresult rv = QueryInterface(aIID, aResult);
4106 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4107 return rv;
4108 }
4109 }
4110
4111 return mXHR->GetInterface(aIID, aResult);
4112}
4113
4114ArrayBufferBuilder::ArrayBufferBuilder()
4115 : mMutex("ArrayBufferBuilder"),
4116 mDataPtr(nullptr),
4117 mCapacity(0),
4118 mLength(0),
4119 mMapPtr(nullptr),
4120 mNeutered(false) {}
4121
4122ArrayBufferBuilder::~ArrayBufferBuilder() {
4123 if (mDataPtr) {
4124 JS_free(nullptr, mDataPtr);
4125 }
4126
4127 if (mMapPtr) {
4128 JS::ReleaseMappedArrayBufferContents(mMapPtr, mLength);
4129 mMapPtr = nullptr;
4130 }
4131
4132 mDataPtr = nullptr;
4133 mCapacity = mLength = 0;
4134}
4135
4136bool ArrayBufferBuilder::SetCapacity(uint32_t aNewCap) {
4137 MutexAutoLock lock(mMutex);
4138 return SetCapacityInternal(aNewCap, lock);
4139}
4140
4141bool ArrayBufferBuilder::SetCapacityInternal(
4142 uint32_t aNewCap, const MutexAutoLock& aProofOfLock) {
4143 MOZ_ASSERT(!mMapPtr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mMapPtr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mMapPtr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mMapPtr", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4143); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mMapPtr" ")"
); do { MOZ_CrashSequence(__null, 4143); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4144 MOZ_ASSERT(!mNeutered)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNeutered)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNeutered))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mNeutered", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNeutered"
")"); do { MOZ_CrashSequence(__null, 4144); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4145
4146 // To ensure that realloc won't free mDataPtr, use a size of 1
4147 // instead of 0.
4148 uint8_t* newdata = (uint8_t*)js_realloc(mDataPtr, aNewCap ? aNewCap : 1);
4149
4150 if (!newdata) {
4151 return false;
4152 }
4153
4154 if (aNewCap > mCapacity) {
4155 memset(newdata + mCapacity, 0, aNewCap - mCapacity);
4156 }
4157
4158 mDataPtr = newdata;
4159 mCapacity = aNewCap;
4160 if (mLength > aNewCap) {
4161 mLength = aNewCap;
4162 }
4163
4164 return true;
4165}
4166
4167bool ArrayBufferBuilder::Append(const uint8_t* aNewData, uint32_t aDataLen,
4168 uint32_t aMaxGrowth) {
4169 MutexAutoLock lock(mMutex);
4170 MOZ_ASSERT(!mMapPtr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mMapPtr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mMapPtr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mMapPtr", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4170); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mMapPtr" ")"
); do { MOZ_CrashSequence(__null, 4170); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4171 MOZ_ASSERT(!mNeutered)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNeutered)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNeutered))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mNeutered", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4171); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNeutered"
")"); do { MOZ_CrashSequence(__null, 4171); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4172
4173 CheckedUint32 neededCapacity = mLength;
4174 neededCapacity += aDataLen;
4175 if (!neededCapacity.isValid()) {
4176 return false;
4177 }
4178 if (mLength + aDataLen > mCapacity) {
4179 CheckedUint32 newcap = mCapacity;
4180 // Double while under aMaxGrowth or if not specified.
4181 if (!aMaxGrowth || mCapacity < aMaxGrowth) {
4182 newcap *= 2;
4183 } else {
4184 newcap += aMaxGrowth;
4185 }
4186
4187 if (!newcap.isValid()) {
4188 return false;
4189 }
4190
4191 // But make sure there's always enough to satisfy our request.
4192 if (newcap.value() < neededCapacity.value()) {
4193 newcap = neededCapacity;
4194 }
4195
4196 if (!SetCapacityInternal(newcap.value(), lock)) {
4197 return false;
4198 }
4199 }
4200
4201 // Assert that the region isn't overlapping so we can memcpy.
4202 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!AreOverlappingRegions(aNewData, aDataLen, mDataPtr +
mLength, aDataLen))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!AreOverlappingRegions(aNewData
, aDataLen, mDataPtr + mLength, aDataLen)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!AreOverlappingRegions(aNewData, aDataLen, mDataPtr + mLength, aDataLen)"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 4203); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!AreOverlappingRegions(aNewData, aDataLen, mDataPtr + mLength, aDataLen)"
")"); do { MOZ_CrashSequence(__null, 4203); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4203 !AreOverlappingRegions(aNewData, aDataLen, mDataPtr + mLength, aDataLen))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!AreOverlappingRegions(aNewData, aDataLen, mDataPtr +
mLength, aDataLen))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!AreOverlappingRegions(aNewData
, aDataLen, mDataPtr + mLength, aDataLen)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!AreOverlappingRegions(aNewData, aDataLen, mDataPtr + mLength, aDataLen)"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 4203); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!AreOverlappingRegions(aNewData, aDataLen, mDataPtr + mLength, aDataLen)"
")"); do { MOZ_CrashSequence(__null, 4203); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4204
4205 memcpy(mDataPtr + mLength, aNewData, aDataLen);
4206 mLength += aDataLen;
4207
4208 return true;
4209}
4210
4211uint32_t ArrayBufferBuilder::Length() {
4212 MutexAutoLock lock(mMutex);
4213 MOZ_ASSERT(!mNeutered)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNeutered)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNeutered))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mNeutered", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4213); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNeutered"
")"); do { MOZ_CrashSequence(__null, 4213); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4214 return mLength;
4215}
4216
4217uint32_t ArrayBufferBuilder::Capacity() {
4218 MutexAutoLock lock(mMutex);
4219 MOZ_ASSERT(!mNeutered)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNeutered)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNeutered))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mNeutered", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNeutered"
")"); do { MOZ_CrashSequence(__null, 4219); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4220 return mCapacity;
4221}
4222
4223JSObject* ArrayBufferBuilder::TakeArrayBuffer(JSContext* aCx) {
4224 MutexAutoLock lock(mMutex);
4225 MOZ_DIAGNOSTIC_ASSERT(!mNeutered)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNeutered)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNeutered))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mNeutered", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4225); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!mNeutered"
")"); do { MOZ_CrashSequence(__null, 4225); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4226
4227 if (mMapPtr) {
4228 JSObject* obj = JS::NewMappedArrayBufferWithContents(aCx, mLength, mMapPtr);
4229 if (!obj) {
4230 JS::ReleaseMappedArrayBufferContents(mMapPtr, mLength);
4231 }
4232
4233 mMapPtr = nullptr;
4234 mNeutered = true;
4235
4236 // The memory-mapped contents will be released when the ArrayBuffer becomes
4237 // detached or is GC'd.
4238 return obj;
4239 }
4240
4241 // we need to check for mLength == 0, because nothing may have been
4242 // added
4243 if (mCapacity > mLength || mLength == 0) {
4244 if (!SetCapacityInternal(mLength, lock)) {
4245 return nullptr;
4246 }
4247 }
4248
4249 // |mDataPtr| will be deallocated in ArrayBufferBuilder's destructor when this
4250 // ArrayBuffer allocation failed.
4251 JSObject* obj = JS::NewArrayBufferWithContents(
4252 aCx, mLength, mDataPtr,
4253 JS::NewArrayBufferOutOfMemory::CallerMustFreeMemory);
4254 if (!obj) {
4255 return nullptr;
4256 }
4257
4258 mDataPtr = nullptr;
4259 mCapacity = mLength = 0;
4260
4261 mNeutered = true;
4262 return obj;
4263}
4264
4265nsresult ArrayBufferBuilder::MapToFileInPackage(const nsCString& aFile,
4266 nsIFile* aJarFile) {
4267 MutexAutoLock lock(mMutex);
4268 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()"
, "./../../../dom/xhr/XMLHttpRequestMainThread.cpp", 4268); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 4268); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
4269 MOZ_ASSERT(!mNeutered)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNeutered)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNeutered))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mNeutered", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4269); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNeutered"
")"); do { MOZ_CrashSequence(__null, 4269); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4270
4271 nsresult rv;
4272
4273 // Open Jar file to get related attributes of target file.
4274 RefPtr<nsZipArchive> zip = nsZipArchive::OpenArchive(aJarFile);
4275 if (!zip) {
4276 return NS_ERROR_FAILURE;
4277 }
4278 nsZipItem* zipItem = zip->GetItem(aFile);
4279 if (!zipItem) {
4280 return NS_ERROR_FILE_NOT_FOUND;
4281 }
4282
4283 // If file was added to the package as stored(uncompressed), map to the
4284 // offset of file in zip package.
4285 if (!zipItem->Compression()) {
4286 uint32_t offset = zip->GetDataOffset(zipItem);
4287 uint32_t size = zipItem->RealSize();
4288 mozilla::AutoFDClose pr_fd;
4289 rv = aJarFile->OpenNSPRFileDesc(PR_RDONLY0x01, 0, getter_Transfers(pr_fd));
4290 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4291 return rv;
4292 }
4293 mMapPtr = JS::CreateMappedArrayBufferContents(
4294 PR_FileDesc2NativeHandle(pr_fd.get()), offset, size);
4295 if (mMapPtr) {
4296 mLength = size;
4297 return NS_OK;
4298 }
4299 }
4300 return NS_ERROR_FAILURE;
4301}
4302
4303/* static */
4304bool ArrayBufferBuilder::AreOverlappingRegions(const uint8_t* aStart1,
4305 uint32_t aLength1,
4306 const uint8_t* aStart2,
4307 uint32_t aLength2) {
4308 const uint8_t* end1 = aStart1 + aLength1;
4309 const uint8_t* end2 = aStart2 + aLength2;
4310
4311 const uint8_t* max_start = aStart1 > aStart2 ? aStart1 : aStart2;
4312 const uint8_t* min_end = end1 < end2 ? end1 : end2;
4313
4314 return max_start < min_end;
4315}
4316
4317RequestHeaders::RequestHeader* RequestHeaders::Find(const nsACString& aName) {
4318 for (RequestHeaders::RequestHeader& header : mHeaders) {
4319 if (header.mName.Equals(aName, nsCaseInsensitiveCStringComparator)) {
4320 return &header;
4321 }
4322 }
4323 return nullptr;
4324}
4325
4326bool RequestHeaders::IsEmpty() const { return mHeaders.IsEmpty(); }
4327
4328bool RequestHeaders::Has(const char* aName) {
4329 return Has(nsDependentCString(aName));
4330}
4331
4332bool RequestHeaders::Has(const nsACString& aName) { return !!Find(aName); }
4333
4334void RequestHeaders::Get(const char* aName, nsACString& aValue) {
4335 Get(nsDependentCString(aName), aValue);
4336}
4337
4338void RequestHeaders::Get(const nsACString& aName, nsACString& aValue) {
4339 RequestHeader* header = Find(aName);
4340 if (header) {
4341 aValue = header->mValue;
4342 } else {
4343 aValue.SetIsVoid(true);
4344 }
4345}
4346
4347void RequestHeaders::Set(const char* aName, const nsACString& aValue) {
4348 Set(nsDependentCString(aName), aValue);
4349}
4350
4351void RequestHeaders::Set(const nsACString& aName, const nsACString& aValue) {
4352 RequestHeader* header = Find(aName);
4353 if (header) {
4354 header->mValue.Assign(aValue);
4355 } else {
4356 RequestHeader newHeader = {nsCString(aName), nsCString(aValue)};
4357 mHeaders.AppendElement(newHeader);
4358 }
4359}
4360
4361void RequestHeaders::MergeOrSet(const char* aName, const nsACString& aValue) {
4362 MergeOrSet(nsDependentCString(aName), aValue);
4363}
4364
4365void RequestHeaders::MergeOrSet(const nsACString& aName,
4366 const nsACString& aValue) {
4367 RequestHeader* header = Find(aName);
4368 if (header) {
4369 header->mValue.AppendLiteral(", ");
4370 header->mValue.Append(aValue);
4371 } else {
4372 RequestHeader newHeader = {nsCString(aName), nsCString(aValue)};
4373 mHeaders.AppendElement(newHeader);
4374 }
4375}
4376
4377void RequestHeaders::Clear() { mHeaders.Clear(); }
4378
4379void RequestHeaders::ApplyToChannel(nsIHttpChannel* aChannel,
4380 bool aStripRequestBodyHeader,
4381 bool aStripAuthHeader) const {
4382 for (const RequestHeader& header : mHeaders) {
4383 if (aStripRequestBodyHeader &&
4384 (header.mName.LowerCaseEqualsASCII("content-type") ||
4385 header.mName.LowerCaseEqualsASCII("content-encoding") ||
4386 header.mName.LowerCaseEqualsASCII("content-language") ||
4387 header.mName.LowerCaseEqualsASCII("content-location"))) {
4388 continue;
4389 }
4390
4391 if (aStripAuthHeader &&
4392 header.mName.LowerCaseEqualsASCII("authorization")) {
4393 continue;
4394 }
4395
4396 // Update referrerInfo to override referrer header in system privileged.
4397 if (header.mName.LowerCaseEqualsASCII("referer")) {
4398 DebugOnly<nsresult> rv = aChannel->SetNewReferrerInfo(
4399 header.mValue, nsIReferrerInfo::ReferrerPolicyIDL::UNSAFE_URL, true);
4400 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4400); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 4400); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4401 }
4402 if (header.mValue.IsEmpty()) {
4403 DebugOnly<nsresult> rv = aChannel->SetEmptyRequestHeader(header.mName);
4404 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4404); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 4404); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4405 } else {
4406 DebugOnly<nsresult> rv =
4407 aChannel->SetRequestHeader(header.mName, header.mValue, false);
4408 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../dom/xhr/XMLHttpRequestMainThread.cpp"
, 4408); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 4408); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4409 }
4410 }
4411}
4412
4413void RequestHeaders::GetCORSUnsafeHeaders(nsTArray<nsCString>& aArray) const {
4414 for (const RequestHeader& header : mHeaders) {
4415 if (!nsContentUtils::IsCORSSafelistedRequestHeader(header.mName,
4416 header.mValue)) {
4417 aArray.AppendElement(header.mName);
4418 }
4419 }
4420}
4421
4422RequestHeaders::CharsetIterator::CharsetIterator(nsACString& aSource)
4423 : mValid(false),
4424 mCurPos(-1),
4425 mCurLen(-1),
4426 mCutoff(aSource.Length()),
4427 mSource(aSource) {}
4428
4429bool RequestHeaders::CharsetIterator::Equals(
4430 const nsACString& aOther, const nsCStringComparator& aCmp) const {
4431 if (mValid) {
4432 return Substring(mSource, mCurPos, mCurLen).Equals(aOther, aCmp);
4433 } else {
4434 return false;
4435 }
4436}
4437
4438void RequestHeaders::CharsetIterator::Replace(const nsACString& aReplacement) {
4439 if (mValid) {
4440 mSource.Replace(mCurPos, mCurLen, aReplacement);
4441 mCurLen = aReplacement.Length();
4442 }
4443}
4444
4445bool RequestHeaders::CharsetIterator::Next() {
4446 int32_t start, end;
4447 nsAutoCString charset;
4448
4449 // Look for another charset declaration in the string, limiting the
4450 // search to only the characters before the parts we've already searched
4451 // (before mCutoff), so that we don't find the same charset twice.
4452 NS_ExtractCharsetFromContentType(Substring(mSource, 0, mCutoff), charset,
4453 &mValid, &start, &end);
4454
4455 if (!mValid) {
4456 return false;
4457 }
4458
4459 // Everything after the = sign is the part of the charset we want.
4460 mCurPos = mSource.FindChar('=', start) + 1;
4461 mCurLen = end - mCurPos;
4462
4463 // Special case: the extracted charset is quoted with single quotes.
4464 // For the purpose of preserving what was set we want to handle them
4465 // as delimiters (although they aren't really).
4466 if (charset.Length() >= 2 && charset.First() == '\'' &&
4467 charset.Last() == '\'') {
4468 ++mCurPos;
4469 mCurLen -= 2;
4470 }
4471
4472 mCutoff = start;
4473
4474 return true;
4475}
4476
4477} // namespace mozilla::dom