summaryrefslogtreecommitdiffstats
path: root/dom/xhr/XMLHttpRequestMainThread.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/xhr/XMLHttpRequestMainThread.h')
-rw-r--r--dom/xhr/XMLHttpRequestMainThread.h872
1 files changed, 872 insertions, 0 deletions
diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h
new file mode 100644
index 000000000..c9bcddf99
--- /dev/null
+++ b/dom/xhr/XMLHttpRequestMainThread.h
@@ -0,0 +1,872 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_XMLHttpRequestMainThread_h
+#define mozilla_dom_XMLHttpRequestMainThread_h
+
+#include <bitset>
+#include "nsAutoPtr.h"
+#include "nsIXMLHttpRequest.h"
+#include "nsISupportsUtils.h"
+#include "nsIURI.h"
+#include "nsIHttpChannel.h"
+#include "nsIDocument.h"
+#include "nsIStreamListener.h"
+#include "nsWeakReference.h"
+#include "nsIChannelEventSink.h"
+#include "nsIAsyncVerifyRedirectCallback.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIHttpHeaderVisitor.h"
+#include "nsIProgressEventSink.h"
+#include "nsJSUtils.h"
+#include "nsTArray.h"
+#include "nsITimer.h"
+#include "nsIPrincipal.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "nsISizeOfEventTarget.h"
+#include "nsIXPConnect.h"
+#include "nsIInputStream.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/NotNull.h"
+#include "mozilla/dom/MutableBlobStorage.h"
+#include "mozilla/dom/TypedArray.h"
+#include "mozilla/dom/XMLHttpRequest.h"
+#include "mozilla/dom/XMLHttpRequestBinding.h"
+#include "mozilla/dom/XMLHttpRequestEventTarget.h"
+#include "mozilla/dom/XMLHttpRequestString.h"
+
+#ifdef Status
+/* Xlib headers insist on this for some reason... Nuke it because
+ it'll override our member name */
+#undef Status
+#endif
+
+class nsIJARChannel;
+class nsILoadGroup;
+class nsIUnicodeDecoder;
+class nsIJSID;
+
+namespace mozilla {
+namespace dom {
+
+class Blob;
+class BlobSet;
+class DOMString;
+class FormData;
+class URLSearchParams;
+class XMLHttpRequestUpload;
+struct OriginAttributesDictionary;
+
+// A helper for building up an ArrayBuffer object's data
+// before creating the ArrayBuffer itself. Will do doubling
+// based reallocation, up to an optional maximum growth given.
+//
+// When all the data has been appended, call getArrayBuffer,
+// passing in the JSContext* for which the ArrayBuffer object
+// is to be created. This also implicitly resets the builder,
+// or it can be reset explicitly at any point by calling reset().
+class ArrayBufferBuilder
+{
+ uint8_t* mDataPtr;
+ uint32_t mCapacity;
+ uint32_t mLength;
+ void* mMapPtr;
+public:
+ ArrayBufferBuilder();
+ ~ArrayBufferBuilder();
+
+ void reset();
+
+ // Will truncate if aNewCap is < length().
+ bool setCapacity(uint32_t aNewCap);
+
+ // Append aDataLen bytes from data to the current buffer. If we
+ // need to grow the buffer, grow by doubling the size up to a
+ // maximum of aMaxGrowth (if given). If aDataLen is greater than
+ // what the new capacity would end up as, then grow by aDataLen.
+ //
+ // The data parameter must not overlap with anything beyond the
+ // builder's current valid contents [0..length)
+ bool append(const uint8_t* aNewData, uint32_t aDataLen,
+ uint32_t aMaxGrowth = 0);
+
+ uint32_t length() { return mLength; }
+ uint32_t capacity() { return mCapacity; }
+
+ JSObject* getArrayBuffer(JSContext* aCx);
+
+ // Memory mapping to starting position of file(aFile) in the zip
+ // package(aJarFile).
+ //
+ // The file in the zip package has to be uncompressed and the starting
+ // position of the file must be aligned according to array buffer settings
+ // in JS engine.
+ nsresult mapToFileInPackage(const nsCString& aFile, nsIFile* aJarFile);
+
+protected:
+ static bool areOverlappingRegions(const uint8_t* aStart1, uint32_t aLength1,
+ const uint8_t* aStart2, uint32_t aLength2);
+};
+
+class nsXMLHttpRequestXPCOMifier;
+
+class RequestHeaders
+{
+ struct RequestHeader
+ {
+ nsCString mName;
+ nsCString mValue;
+ };
+ nsTArray<RequestHeader> mHeaders;
+ RequestHeader* Find(const nsACString& aName);
+
+public:
+ class CharsetIterator
+ {
+ bool mValid;
+ int32_t mCurPos, mCurLen, mCutoff;
+ nsACString& mSource;
+
+ public:
+ explicit CharsetIterator(nsACString& aSource);
+ bool Equals(const nsACString& aOther, const nsCStringComparator& aCmp) const;
+ void Replace(const nsACString& aReplacement);
+ bool Next();
+ };
+
+ bool Has(const char* aName);
+ bool Has(const nsACString& aName);
+ void Get(const char* aName, nsACString& aValue);
+ void Get(const nsACString& aName, nsACString& aValue);
+ void Set(const char* aName, const nsACString& aValue);
+ void Set(const nsACString& aName, const nsACString& aValue);
+ void MergeOrSet(const char* aName, const nsACString& aValue);
+ void MergeOrSet(const nsACString& aName, const nsACString& aValue);
+ void Clear();
+ void ApplyToChannel(nsIHttpChannel* aChannel) const;
+ void GetCORSUnsafeHeaders(nsTArray<nsCString>& aArray) const;
+};
+
+// Make sure that any non-DOM interfaces added here are also added to
+// nsXMLHttpRequestXPCOMifier.
+class XMLHttpRequestMainThread final : public XMLHttpRequest,
+ public nsIXMLHttpRequest,
+ public nsIJSXMLHttpRequest,
+ public nsIStreamListener,
+ public nsIChannelEventSink,
+ public nsIProgressEventSink,
+ public nsIInterfaceRequestor,
+ public nsSupportsWeakReference,
+ public nsITimerCallback,
+ public nsISizeOfEventTarget,
+ public MutableBlobStorageCallback
+{
+ friend class nsXHRParseEndListener;
+ friend class nsXMLHttpRequestXPCOMifier;
+
+public:
+ enum class ProgressEventType : uint8_t {
+ loadstart,
+ progress,
+ error,
+ abort,
+ timeout,
+ load,
+ loadend,
+ ENUM_MAX
+ };
+
+ XMLHttpRequestMainThread();
+
+ void Construct(nsIPrincipal* aPrincipal,
+ nsIGlobalObject* aGlobalObject,
+ nsIURI* aBaseURI = nullptr,
+ nsILoadGroup* aLoadGroup = nullptr)
+ {
+ MOZ_ASSERT(aPrincipal);
+ MOZ_ASSERT_IF(nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(
+ aGlobalObject), win->IsInnerWindow());
+ mPrincipal = aPrincipal;
+ BindToOwner(aGlobalObject);
+ mBaseURI = aBaseURI;
+ mLoadGroup = aLoadGroup;
+ }
+
+ void InitParameters(bool aAnon, bool aSystem);
+
+ void SetParameters(bool aAnon, bool aSystem)
+ {
+ mIsAnon = aAnon || aSystem;
+ mIsSystem = aSystem;
+ }
+
+ NS_DECL_ISUPPORTS_INHERITED
+
+ // nsIXMLHttpRequest
+ NS_DECL_NSIXMLHTTPREQUEST
+
+ NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(XMLHttpRequestEventTarget::)
+
+ // nsIStreamListener
+ NS_DECL_NSISTREAMLISTENER
+
+ // nsIRequestObserver
+ NS_DECL_NSIREQUESTOBSERVER
+
+ // nsIChannelEventSink
+ NS_DECL_NSICHANNELEVENTSINK
+
+ // nsIProgressEventSink
+ NS_DECL_NSIPROGRESSEVENTSINK
+
+ // nsIInterfaceRequestor
+ NS_DECL_NSIINTERFACEREQUESTOR
+
+ // nsITimerCallback
+ NS_DECL_NSITIMERCALLBACK
+
+ // nsISizeOfEventTarget
+ virtual size_t
+ SizeOfEventTargetIncludingThis(MallocSizeOf aMallocSizeOf) const override;
+
+ NS_REALLY_FORWARD_NSIDOMEVENTTARGET(XMLHttpRequestEventTarget)
+
+ // states
+ virtual uint16_t ReadyState() const override;
+
+ // request
+ nsresult CreateChannel();
+ nsresult InitiateFetch(nsIInputStream* aUploadStream,
+ int64_t aUploadLength,
+ nsACString& aUploadContentType);
+
+ virtual void
+ Open(const nsACString& aMethod, const nsAString& aUrl,
+ ErrorResult& aRv) override;
+
+ virtual void
+ Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync,
+ const nsAString& aUsername, const nsAString& aPassword,
+ ErrorResult& aRv) override;
+
+ nsresult
+ Open(const nsACString& aMethod,
+ const nsACString& aUrl,
+ bool aAsync,
+ const nsAString& aUsername,
+ const nsAString& aPassword);
+
+ virtual void
+ SetRequestHeader(const nsACString& aName, const nsACString& aValue,
+ ErrorResult& aRv) override
+ {
+ aRv = SetRequestHeader(aName, aValue);
+ }
+
+ virtual uint32_t
+ Timeout() const override
+ {
+ return mTimeoutMilliseconds;
+ }
+
+ virtual void
+ SetTimeout(uint32_t aTimeout, ErrorResult& aRv) override;
+
+ virtual bool WithCredentials() const override;
+
+ virtual void
+ SetWithCredentials(bool aWithCredentials, ErrorResult& aRv) override;
+
+ virtual XMLHttpRequestUpload*
+ GetUpload(ErrorResult& aRv) override;
+
+private:
+ virtual ~XMLHttpRequestMainThread();
+
+ class RequestBodyBase
+ {
+ public:
+ virtual nsresult GetAsStream(nsIInputStream** aResult,
+ uint64_t* aContentLength,
+ nsACString& aContentType,
+ nsACString& aCharset) const
+ {
+ NS_ASSERTION(false, "RequestBodyBase should not be used directly.");
+ return NS_ERROR_FAILURE;
+ }
+ };
+
+ template<typename Type>
+ class RequestBody final : public RequestBodyBase
+ {
+ Type* mBody;
+ public:
+ explicit RequestBody(Type* aBody) : mBody(aBody)
+ {
+ }
+ nsresult GetAsStream(nsIInputStream** aResult,
+ uint64_t* aContentLength,
+ nsACString& aContentType,
+ nsACString& aCharset) const override;
+ };
+
+ nsresult SendInternal(const RequestBodyBase* aBody);
+
+ bool IsCrossSiteCORSRequest() const;
+ bool IsDeniedCrossSiteCORSRequest();
+
+ // Tell our channel what network interface ID we were told to use.
+ // If it's an HTTP channel and we were told to use a non-default
+ // interface ID.
+ void PopulateNetworkInterfaceId();
+
+public:
+ virtual void
+ Send(JSContext* /*aCx*/, ErrorResult& aRv) override
+ {
+ aRv = SendInternal(nullptr);
+ }
+
+ virtual void
+ Send(JSContext* /*aCx*/, const ArrayBuffer& aArrayBuffer,
+ ErrorResult& aRv) override
+ {
+ RequestBody<const ArrayBuffer> body(&aArrayBuffer);
+ aRv = SendInternal(&body);
+ }
+
+ virtual void
+ Send(JSContext* /*aCx*/, const ArrayBufferView& aArrayBufferView,
+ ErrorResult& aRv) override
+ {
+ RequestBody<const ArrayBufferView> body(&aArrayBufferView);
+ aRv = SendInternal(&body);
+ }
+
+ virtual void
+ Send(JSContext* /*aCx*/, Blob& aBlob, ErrorResult& aRv) override
+ {
+ RequestBody<Blob> body(&aBlob);
+ aRv = SendInternal(&body);
+ }
+
+ virtual void Send(JSContext* /*aCx*/, URLSearchParams& aURLSearchParams,
+ ErrorResult& aRv) override
+ {
+ RequestBody<URLSearchParams> body(&aURLSearchParams);
+ aRv = SendInternal(&body);
+ }
+
+ virtual void
+ Send(JSContext* /*aCx*/, nsIDocument& aDoc, ErrorResult& aRv) override
+ {
+ RequestBody<nsIDocument> body(&aDoc);
+ aRv = SendInternal(&body);
+ }
+
+ virtual void
+ Send(JSContext* aCx, const nsAString& aString, ErrorResult& aRv) override
+ {
+ if (DOMStringIsNull(aString)) {
+ Send(aCx, aRv);
+ } else {
+ RequestBody<const nsAString> body(&aString);
+ aRv = SendInternal(&body);
+ }
+ }
+
+ virtual void
+ Send(JSContext* /*aCx*/, FormData& aFormData, ErrorResult& aRv) override
+ {
+ RequestBody<FormData> body(&aFormData);
+ aRv = SendInternal(&body);
+ }
+
+ virtual void
+ Send(JSContext* aCx, nsIInputStream* aStream, ErrorResult& aRv) override
+ {
+ NS_ASSERTION(aStream, "Null should go to string version");
+ RequestBody<nsIInputStream> body(aStream);
+ aRv = SendInternal(&body);
+ }
+
+ void
+ Abort() {
+ ErrorResult rv;
+ Abort(rv);
+ MOZ_ASSERT(!rv.Failed());
+ }
+
+ virtual void
+ Abort(ErrorResult& aRv) override;
+
+ // response
+ virtual void
+ GetResponseURL(nsAString& aUrl) override;
+
+ virtual uint32_t
+ GetStatus(ErrorResult& aRv) override;
+
+ virtual void
+ GetStatusText(nsACString& aStatusText, ErrorResult& aRv) override;
+
+ virtual void
+ GetResponseHeader(const nsACString& aHeader, nsACString& aResult,
+ ErrorResult& aRv) override;
+
+ void
+ GetResponseHeader(const nsAString& aHeader, nsAString& aResult,
+ ErrorResult& aRv)
+ {
+ nsAutoCString result;
+ GetResponseHeader(NS_ConvertUTF16toUTF8(aHeader), result, aRv);
+ if (result.IsVoid()) {
+ aResult.SetIsVoid(true);
+ }
+ else {
+ // The result value should be inflated:
+ CopyASCIItoUTF16(result, aResult);
+ }
+ }
+
+ virtual void
+ GetAllResponseHeaders(nsACString& aResponseHeaders,
+ ErrorResult& aRv) override;
+
+ bool IsSafeHeader(const nsACString& aHeaderName,
+ NotNull<nsIHttpChannel*> aHttpChannel) const;
+
+ virtual void
+ OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv) override;
+
+ virtual XMLHttpRequestResponseType
+ ResponseType() const override
+ {
+ return XMLHttpRequestResponseType(mResponseType);
+ }
+
+ virtual void
+ SetResponseType(XMLHttpRequestResponseType aType,
+ ErrorResult& aRv) override;
+
+ virtual void
+ GetResponse(JSContext* aCx, JS::MutableHandle<JS::Value> aResponse,
+ ErrorResult& aRv) override;
+
+ virtual void
+ GetResponseText(DOMString& aResponseText, ErrorResult& aRv) override;
+
+ void
+ GetResponseText(XMLHttpRequestStringSnapshot& aSnapshot,
+ ErrorResult& aRv);
+
+ virtual nsIDocument*
+ GetResponseXML(ErrorResult& aRv) override;
+
+ virtual bool
+ MozBackgroundRequest() const override;
+
+ virtual void
+ SetMozBackgroundRequest(bool aMozBackgroundRequest, ErrorResult& aRv) override;
+
+ virtual bool
+ MozAnon() const override;
+
+ virtual bool
+ MozSystem() const override;
+
+ virtual nsIChannel*
+ GetChannel() const override
+ {
+ return mChannel;
+ }
+
+ virtual void
+ GetNetworkInterfaceId(nsACString& aId) const override
+ {
+ aId = mNetworkInterfaceId;
+ }
+
+ virtual void
+ SetNetworkInterfaceId(const nsACString& aId) override
+ {
+ mNetworkInterfaceId = aId;
+ }
+
+ // We need a GetInterface callable from JS for chrome JS
+ virtual void
+ GetInterface(JSContext* aCx, nsIJSID* aIID,
+ JS::MutableHandle<JS::Value> aRetval,
+ ErrorResult& aRv) override;
+
+ // This fires a trusted readystatechange event, which is not cancelable and
+ // doesn't bubble.
+ nsresult FireReadystatechangeEvent();
+ void DispatchProgressEvent(DOMEventTargetHelper* aTarget,
+ const ProgressEventType aType,
+ int64_t aLoaded, int64_t aTotal);
+
+ // This is called by the factory constructor.
+ nsresult Init();
+
+ nsresult init(nsIPrincipal* principal,
+ nsPIDOMWindowInner* globalObject,
+ nsIURI* baseURI);
+
+ void SetRequestObserver(nsIRequestObserver* aObserver);
+
+ NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(XMLHttpRequestMainThread,
+ XMLHttpRequest)
+ bool AllowUploadProgress();
+
+ virtual void DisconnectFromOwner() override;
+
+ static void SetDontWarnAboutSyncXHR(bool aVal)
+ {
+ sDontWarnAboutSyncXHR = aVal;
+ }
+ static bool DontWarnAboutSyncXHR()
+ {
+ return sDontWarnAboutSyncXHR;
+ }
+
+ virtual void
+ SetOriginAttributes(const mozilla::dom::OriginAttributesDictionary& aAttrs) override;
+
+ void BlobStoreCompleted(MutableBlobStorage* aBlobStorage,
+ Blob* aBlob,
+ nsresult aResult) override;
+
+protected:
+ // XHR states are meant to mirror the XHR2 spec:
+ // https://xhr.spec.whatwg.org/#states
+ enum class State : uint8_t {
+ unsent, // object has been constructed.
+ opened, // open() has been successfully invoked.
+ headers_received, // redirects followed and response headers received.
+ loading, // response body is being received.
+ done, // data transfer concluded, whether success or error.
+ };
+
+ nsresult DetectCharset();
+ nsresult AppendToResponseText(const char * aBuffer, uint32_t aBufferLen);
+ static nsresult StreamReaderFunc(nsIInputStream* in,
+ void* closure,
+ const char* fromRawSegment,
+ uint32_t toOffset,
+ uint32_t count,
+ uint32_t *writeCount);
+ nsresult CreateResponseParsedJSON(JSContext* aCx);
+ void CreatePartialBlob(ErrorResult& aRv);
+ bool CreateDOMBlob(nsIRequest *request);
+ // Change the state of the object with this. The broadcast argument
+ // determines if the onreadystatechange listener should be called.
+ nsresult ChangeState(State aState, bool aBroadcast = true);
+ already_AddRefed<nsILoadGroup> GetLoadGroup() const;
+ nsIURI *GetBaseURI();
+
+ already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel();
+ already_AddRefed<nsIJARChannel> GetCurrentJARChannel();
+
+ void TruncateResponseText();
+
+ bool IsSystemXHR() const;
+ bool InUploadPhase() const;
+
+ void OnBodyParseEnd();
+ void ChangeStateToDone();
+
+ void StartProgressEventTimer();
+ void StopProgressEventTimer();
+
+ void MaybeCreateBlobStorage();
+
+ nsresult OnRedirectVerifyCallback(nsresult result);
+
+ already_AddRefed<nsXMLHttpRequestXPCOMifier> EnsureXPCOMifier();
+
+ nsCOMPtr<nsISupports> mContext;
+ nsCOMPtr<nsIPrincipal> mPrincipal;
+ nsCOMPtr<nsIChannel> mChannel;
+ nsCString mRequestMethod;
+ nsCOMPtr<nsIURI> mRequestURL;
+ nsCOMPtr<nsIDocument> mResponseXML;
+
+ nsCOMPtr<nsIStreamListener> mXMLParserStreamListener;
+
+ // used to implement getAllResponseHeaders()
+ class nsHeaderVisitor : public nsIHttpHeaderVisitor
+ {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIHTTPHEADERVISITOR
+ nsHeaderVisitor(const XMLHttpRequestMainThread& aXMLHttpRequest,
+ NotNull<nsIHttpChannel*> aHttpChannel)
+ : mXHR(aXMLHttpRequest), mHttpChannel(aHttpChannel) {}
+ const nsACString &Headers() { return mHeaders; }
+ private:
+ virtual ~nsHeaderVisitor() {}
+
+ nsCString mHeaders;
+ const XMLHttpRequestMainThread& mXHR;
+ NotNull<nsCOMPtr<nsIHttpChannel>> mHttpChannel;
+ };
+
+ // The bytes of our response body. Only used for DEFAULT, ARRAYBUFFER and
+ // BLOB responseTypes
+ nsCString mResponseBody;
+
+ // The text version of our response body. This is incrementally decoded into
+ // as we receive network data. However for the DEFAULT responseType we
+ // lazily decode into this from mResponseBody only when .responseText is
+ // accessed.
+ // Only used for DEFAULT and TEXT responseTypes.
+ XMLHttpRequestString mResponseText;
+
+ // For DEFAULT responseType we use this to keep track of how far we've
+ // lazily decoded from mResponseBody to mResponseText
+ uint32_t mResponseBodyDecodedPos;
+
+ // Decoder used for decoding into mResponseText
+ // Only used for DEFAULT, TEXT and JSON responseTypes.
+ // In cases where we've only received half a surrogate, the decoder itself
+ // carries the state to remember this. Next time we receive more data we
+ // simply feed the new data into the decoder which will handle the second
+ // part of the surrogate.
+ nsCOMPtr<nsIUnicodeDecoder> mDecoder;
+
+ nsCString mResponseCharset;
+
+ void MatchCharsetAndDecoderToResponseDocument();
+
+ XMLHttpRequestResponseType mResponseType;
+
+ // It is either a cached blob-response from the last call to GetResponse,
+ // but is also explicitly set in OnStopRequest.
+ RefPtr<Blob> mResponseBlob;
+ // Non-null only when we are able to get a os-file representation of the
+ // response, i.e. when loading from a file.
+ RefPtr<Blob> mDOMBlob;
+ // We stream data to mBlobStorage when response type is "blob" and mDOMBlob is
+ // null.
+ RefPtr<MutableBlobStorage> mBlobStorage;
+ // We stream data to mBlobStorage when response type is "moz-blob" and
+ // mDOMBlob is null.
+ nsAutoPtr<BlobSet> mBlobSet;
+
+ nsString mOverrideMimeType;
+
+ /**
+ * The notification callbacks the channel had when Send() was
+ * called. We want to forward things here as needed.
+ */
+ nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
+ /**
+ * Sink interfaces that we implement that mNotificationCallbacks may
+ * want to also be notified for. These are inited lazily if we're
+ * asked for the relevant interface.
+ */
+ nsCOMPtr<nsIChannelEventSink> mChannelEventSink;
+ nsCOMPtr<nsIProgressEventSink> mProgressEventSink;
+
+ nsIRequestObserver* mRequestObserver;
+
+ nsCOMPtr<nsIURI> mBaseURI;
+ nsCOMPtr<nsILoadGroup> mLoadGroup;
+
+ State mState;
+
+ bool mFlagSynchronous;
+ bool mFlagAborted;
+ bool mFlagParseBody;
+ bool mFlagSyncLooping;
+ bool mFlagBackgroundRequest;
+ bool mFlagHadUploadListenersOnSend;
+ bool mFlagACwithCredentials;
+ bool mFlagTimedOut;
+ bool mFlagDeleted;
+
+ // The XHR2 spec's send() flag. Set when the XHR begins uploading, until it
+ // finishes downloading (or an error/abort has occurred during either phase).
+ // Used to guard against the user trying to alter headers/etc when it's too
+ // late, and ensure the XHR only handles one in-flight request at once.
+ bool mFlagSend;
+
+ RefPtr<XMLHttpRequestUpload> mUpload;
+ int64_t mUploadTransferred;
+ int64_t mUploadTotal;
+ bool mUploadComplete;
+ bool mProgressSinceLastProgressEvent;
+
+ // Timeout support
+ PRTime mRequestSentTime;
+ uint32_t mTimeoutMilliseconds;
+ nsCOMPtr<nsITimer> mTimeoutTimer;
+ void StartTimeoutTimer();
+ void HandleTimeoutCallback();
+
+ nsCOMPtr<nsITimer> mSyncTimeoutTimer;
+
+ enum SyncTimeoutType {
+ eErrorOrExpired,
+ eTimerStarted,
+ eNoTimerNeeded
+ };
+
+ SyncTimeoutType MaybeStartSyncTimeoutTimer();
+ void HandleSyncTimeoutTimer();
+ void CancelSyncTimeoutTimer();
+
+ bool mErrorLoad;
+ bool mErrorParsingXML;
+ bool mWaitingForOnStopRequest;
+ bool mProgressTimerIsActive;
+ bool mIsHtml;
+ bool mWarnAboutMultipartHtml;
+ bool mWarnAboutSyncHtml;
+ int64_t mLoadTotal; // -1 if not known.
+ // Amount of script-exposed (i.e. after undoing gzip compresion) data
+ // received.
+ uint64_t mDataAvailable;
+ // Number of HTTP message body bytes received so far. This quantity is
+ // in the same units as Content-Length and mLoadTotal, and hence counts
+ // compressed bytes when the channel has gzip Content-Encoding. If the
+ // channel does not have Content-Encoding, this will be the same as
+ // mDataReceived except between the OnProgress that changes mLoadTransferred
+ // and the corresponding OnDataAvailable (which changes mDataReceived).
+ // Ordering of OnProgress and OnDataAvailable is undefined.
+ int64_t mLoadTransferred;
+ nsCOMPtr<nsITimer> mProgressNotifier;
+ void HandleProgressTimerCallback();
+
+ bool mIsSystem;
+ bool mIsAnon;
+
+ // A platform-specific identifer to represent the network interface
+ // that this request is associated with.
+ nsCString mNetworkInterfaceId;
+
+ /**
+ * Close the XMLHttpRequest's channels.
+ */
+ void CloseRequest();
+
+ /**
+ * Close the XMLHttpRequest's channels and dispatch appropriate progress
+ * events.
+ *
+ * @param aType The progress event type.
+ */
+ void CloseRequestWithError(const ProgressEventType aType);
+
+ bool mFirstStartRequestSeen;
+ bool mInLoadProgressEvent;
+
+ nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
+ nsCOMPtr<nsIChannel> mNewRedirectChannel;
+
+ JS::Heap<JS::Value> mResultJSON;
+
+ ArrayBufferBuilder mArrayBufferBuilder;
+ JS::Heap<JSObject*> mResultArrayBuffer;
+ bool mIsMappedArrayBuffer;
+
+ void ResetResponse();
+
+ bool ShouldBlockAuthPrompt();
+
+ RequestHeaders mAuthorRequestHeaders;
+
+ // Helper object to manage our XPCOM scriptability bits
+ nsXMLHttpRequestXPCOMifier* mXPCOMifier;
+
+ static bool sDontWarnAboutSyncXHR;
+};
+
+class MOZ_STACK_CLASS AutoDontWarnAboutSyncXHR
+{
+public:
+ AutoDontWarnAboutSyncXHR() : mOldVal(XMLHttpRequestMainThread::DontWarnAboutSyncXHR())
+ {
+ XMLHttpRequestMainThread::SetDontWarnAboutSyncXHR(true);
+ }
+
+ ~AutoDontWarnAboutSyncXHR()
+ {
+ XMLHttpRequestMainThread::SetDontWarnAboutSyncXHR(mOldVal);
+ }
+
+private:
+ bool mOldVal;
+};
+
+// A shim class designed to expose the non-DOM interfaces of
+// XMLHttpRequest via XPCOM stuff.
+class nsXMLHttpRequestXPCOMifier final : public nsIStreamListener,
+ public nsIChannelEventSink,
+ public nsIAsyncVerifyRedirectCallback,
+ public nsIProgressEventSink,
+ public nsIInterfaceRequestor,
+ public nsITimerCallback
+{
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXMLHttpRequestXPCOMifier,
+ nsIStreamListener)
+
+ explicit nsXMLHttpRequestXPCOMifier(XMLHttpRequestMainThread* aXHR) :
+ mXHR(aXHR)
+ {
+ }
+
+private:
+ ~nsXMLHttpRequestXPCOMifier() {
+ if (mXHR) {
+ mXHR->mXPCOMifier = nullptr;
+ }
+ }
+
+public:
+ NS_FORWARD_NSISTREAMLISTENER(mXHR->)
+ NS_FORWARD_NSIREQUESTOBSERVER(mXHR->)
+ NS_FORWARD_NSICHANNELEVENTSINK(mXHR->)
+ NS_FORWARD_NSIASYNCVERIFYREDIRECTCALLBACK(mXHR->)
+ NS_FORWARD_NSIPROGRESSEVENTSINK(mXHR->)
+ NS_FORWARD_NSITIMERCALLBACK(mXHR->)
+
+ NS_DECL_NSIINTERFACEREQUESTOR
+
+private:
+ RefPtr<XMLHttpRequestMainThread> mXHR;
+};
+
+class nsXHRParseEndListener : public nsIDOMEventListener
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_IMETHOD HandleEvent(nsIDOMEvent *event) override
+ {
+ nsCOMPtr<nsIXMLHttpRequest> xhr = do_QueryReferent(mXHR);
+ if (xhr) {
+ static_cast<XMLHttpRequestMainThread*>(xhr.get())->OnBodyParseEnd();
+ }
+ mXHR = nullptr;
+ return NS_OK;
+ }
+ explicit nsXHRParseEndListener(nsIXMLHttpRequest* aXHR)
+ : mXHR(do_GetWeakReference(aXHR)) {}
+private:
+ virtual ~nsXHRParseEndListener() {}
+
+ nsWeakPtr mXHR;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_XMLHttpRequestMainThread_h