Bug Summary

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