зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1285036 - Part 2: Split mState up into an enum and a set of bool flags. r=baku
This commit is contained in:
Родитель
c603d18df1
Коммит
d6255ae33c
|
@ -115,37 +115,6 @@ namespace {
|
|||
}
|
||||
|
||||
// CIDs
|
||||
|
||||
// State
|
||||
#define XML_HTTP_REQUEST_UNSENT (1 << 0) // 0 UNSENT
|
||||
#define XML_HTTP_REQUEST_OPENED (1 << 1) // 1 OPENED
|
||||
#define XML_HTTP_REQUEST_HEADERS_RECEIVED (1 << 2) // 2 HEADERS_RECEIVED
|
||||
#define XML_HTTP_REQUEST_LOADING (1 << 3) // 3 LOADING
|
||||
#define XML_HTTP_REQUEST_DONE (1 << 4) // 4 DONE
|
||||
#define XML_HTTP_REQUEST_SENT (1 << 5) // Internal, corresponds to
|
||||
// "OPENED and the send()
|
||||
// flag is set" in spec
|
||||
// terms.
|
||||
// The above states are mutually exclusive, change with ChangeState() only.
|
||||
// The states below can be combined.
|
||||
#define XML_HTTP_REQUEST_ABORTED (1 << 7) // Internal
|
||||
#define XML_HTTP_REQUEST_ASYNC (1 << 8) // Internal
|
||||
#define XML_HTTP_REQUEST_PARSEBODY (1 << 9) // Internal
|
||||
#define XML_HTTP_REQUEST_SYNCLOOPING (1 << 10) // Internal
|
||||
#define XML_HTTP_REQUEST_BACKGROUND (1 << 13) // Internal
|
||||
#define XML_HTTP_REQUEST_HAD_UPLOAD_LISTENERS_ON_SEND (1 << 14) // Internal
|
||||
#define XML_HTTP_REQUEST_AC_WITH_CREDENTIALS (1 << 15) // Internal
|
||||
#define XML_HTTP_REQUEST_TIMED_OUT (1 << 16) // Internal
|
||||
#define XML_HTTP_REQUEST_DELETED (1 << 17) // Internal
|
||||
|
||||
#define XML_HTTP_REQUEST_LOADSTATES \
|
||||
(XML_HTTP_REQUEST_UNSENT | \
|
||||
XML_HTTP_REQUEST_OPENED | \
|
||||
XML_HTTP_REQUEST_HEADERS_RECEIVED | \
|
||||
XML_HTTP_REQUEST_LOADING | \
|
||||
XML_HTTP_REQUEST_DONE | \
|
||||
XML_HTTP_REQUEST_SENT)
|
||||
|
||||
#define NS_BADCERTHANDLER_CONTRACTID \
|
||||
"@mozilla.org/content/xmlhttprequest-bad-cert-handler;1"
|
||||
|
||||
|
@ -191,7 +160,11 @@ XMLHttpRequestMainThread::XMLHttpRequestMainThread()
|
|||
: mResponseBodyDecodedPos(0),
|
||||
mResponseType(XMLHttpRequestResponseType::_empty),
|
||||
mRequestObserver(nullptr),
|
||||
mState(XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC),
|
||||
mState(State::unsent),
|
||||
mFlagAsynchronous(true), mFlagAborted(false), mFlagParseBody(false),
|
||||
mFlagSyncLooping(false), mFlagBackgroundRequest(false),
|
||||
mFlagHadUploadListenersOnSend(false), mFlagACwithCredentials(false),
|
||||
mFlagTimedOut(false), mFlagDeleted(false),
|
||||
mUploadTransferred(0), mUploadTotal(0), mUploadComplete(true),
|
||||
mProgressSinceLastProgressEvent(false),
|
||||
mRequestSentTime(0), mTimeoutMilliseconds(0),
|
||||
|
@ -213,15 +186,14 @@ XMLHttpRequestMainThread::XMLHttpRequestMainThread()
|
|||
|
||||
XMLHttpRequestMainThread::~XMLHttpRequestMainThread()
|
||||
{
|
||||
mState |= XML_HTTP_REQUEST_DELETED;
|
||||
mFlagDeleted = true;
|
||||
|
||||
if (mState & (XML_HTTP_REQUEST_SENT |
|
||||
XML_HTTP_REQUEST_LOADING)) {
|
||||
if (mState == State::sent || mState == State::loading) {
|
||||
Abort();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!(mState & XML_HTTP_REQUEST_SYNCLOOPING), "we rather crash than hang");
|
||||
mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
|
||||
MOZ_ASSERT(!mFlagSyncLooping, "we rather crash than hang");
|
||||
mFlagSyncLooping = false;
|
||||
|
||||
mResultJSON.setUndefined();
|
||||
mResultArrayBuffer = nullptr;
|
||||
|
@ -507,7 +479,7 @@ XMLHttpRequestMainThread::GetResponseXML(ErrorResult& aRv)
|
|||
mWarnAboutSyncHtml = false;
|
||||
LogMessage("HTMLSyncXHRWarning", GetOwner());
|
||||
}
|
||||
if (!(XML_HTTP_REQUEST_DONE & mState)) {
|
||||
if (mState != State::done) {
|
||||
return nullptr;
|
||||
}
|
||||
return mResponseXML;
|
||||
|
@ -623,7 +595,7 @@ XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!(mState & (XML_HTTP_REQUEST_DONE | XML_HTTP_REQUEST_LOADING))) {
|
||||
if (mState != State::loading && mState != State::done) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -653,7 +625,7 @@ XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText,
|
|||
|
||||
mResponseBodyDecodedPos = mResponseBody.Length();
|
||||
|
||||
if (mState & XML_HTTP_REQUEST_DONE) {
|
||||
if (mState == State::done) {
|
||||
// Free memory buffer which we no longer need
|
||||
mResponseBody.Truncate();
|
||||
mResponseBodyDecodedPos = 0;
|
||||
|
@ -741,20 +713,19 @@ XMLHttpRequestMainThread::SetResponseType(XMLHttpRequestResponseType aResponseTy
|
|||
{
|
||||
// If the state is LOADING or DONE raise an INVALID_STATE_ERR exception
|
||||
// and terminate these steps.
|
||||
if ((mState & (XML_HTTP_REQUEST_LOADING | XML_HTTP_REQUEST_DONE))) {
|
||||
if (mState == State::loading || mState == State::done) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// sync request is not allowed setting responseType in window context
|
||||
if (HasOrHasHadOwner() &&
|
||||
!(mState & (XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC))) {
|
||||
if (HasOrHasHadOwner() && mState != State::unsent && !mFlagAsynchronous) {
|
||||
LogMessage("ResponseTypeSyncXHRWarning", GetOwner());
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(mState & XML_HTTP_REQUEST_ASYNC) &&
|
||||
if (!mFlagAsynchronous &&
|
||||
(aResponseType == XMLHttpRequestResponseType::Moz_chunked_text ||
|
||||
aResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer)) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
|
@ -798,7 +769,7 @@ XMLHttpRequestMainThread::GetResponse(JSContext* aCx,
|
|||
case XMLHttpRequestResponseType::Moz_chunked_arraybuffer:
|
||||
{
|
||||
if (!(mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
|
||||
mState & XML_HTTP_REQUEST_DONE) &&
|
||||
mState == State::done) &&
|
||||
!(mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer &&
|
||||
mInLoadProgressEvent)) {
|
||||
aResponse.setNull();
|
||||
|
@ -821,7 +792,7 @@ XMLHttpRequestMainThread::GetResponse(JSContext* aCx,
|
|||
case XMLHttpRequestResponseType::Blob:
|
||||
case XMLHttpRequestResponseType::Moz_blob:
|
||||
{
|
||||
if (!(mState & XML_HTTP_REQUEST_DONE)) {
|
||||
if (mState != State::done) {
|
||||
if (mResponseType != XMLHttpRequestResponseType::Moz_blob) {
|
||||
aResponse.setNull();
|
||||
return;
|
||||
|
@ -842,7 +813,7 @@ XMLHttpRequestMainThread::GetResponse(JSContext* aCx,
|
|||
}
|
||||
case XMLHttpRequestResponseType::Document:
|
||||
{
|
||||
if (!(mState & XML_HTTP_REQUEST_DONE) || !mResponseXML) {
|
||||
if (!mResponseXML || mState != State::done) {
|
||||
aResponse.setNull();
|
||||
return;
|
||||
}
|
||||
|
@ -852,7 +823,7 @@ XMLHttpRequestMainThread::GetResponse(JSContext* aCx,
|
|||
}
|
||||
case XMLHttpRequestResponseType::Json:
|
||||
{
|
||||
if (!(mState & XML_HTTP_REQUEST_DONE)) {
|
||||
if (mState != State::done) {
|
||||
aResponse.setNull();
|
||||
return;
|
||||
}
|
||||
|
@ -1031,8 +1002,7 @@ XMLHttpRequestMainThread::GetStatusText(nsACString& aStatusText,
|
|||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestMainThread::CloseRequestWithError(const ProgressEventType aType,
|
||||
const uint32_t aFlag)
|
||||
XMLHttpRequestMainThread::CloseRequestWithError(const ProgressEventType aType)
|
||||
{
|
||||
if (mChannel) {
|
||||
mChannel->Cancel(NS_BINDING_ABORTED);
|
||||
|
@ -1042,20 +1012,19 @@ XMLHttpRequestMainThread::CloseRequestWithError(const ProgressEventType aType,
|
|||
}
|
||||
uint32_t responseLength = mResponseBody.Length();
|
||||
ResetResponse();
|
||||
mState |= aFlag;
|
||||
|
||||
// If we're in the destructor, don't risk dispatching an event.
|
||||
if (mState & XML_HTTP_REQUEST_DELETED) {
|
||||
mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
|
||||
if (mFlagDeleted) {
|
||||
mFlagSyncLooping = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(mState & (XML_HTTP_REQUEST_UNSENT |
|
||||
XML_HTTP_REQUEST_OPENED |
|
||||
XML_HTTP_REQUEST_DONE))) {
|
||||
ChangeState(XML_HTTP_REQUEST_DONE, true);
|
||||
if (mState != State::unsent &&
|
||||
mState != State::opened &&
|
||||
mState != State::done) {
|
||||
ChangeState(State::done, true);
|
||||
|
||||
if (!(mState & XML_HTTP_REQUEST_SYNCLOOPING)) {
|
||||
if (!mFlagSyncLooping) {
|
||||
DispatchProgressEvent(this, aType, mLoadLengthComputable, responseLength,
|
||||
mLoadTotal);
|
||||
if (mUpload && !mUploadComplete) {
|
||||
|
@ -1069,17 +1038,18 @@ XMLHttpRequestMainThread::CloseRequestWithError(const ProgressEventType aType,
|
|||
// The ChangeState call above calls onreadystatechange handlers which
|
||||
// if they load a new url will cause XMLHttpRequestMainThread::Open to clear
|
||||
// the abort state bit. If this occurs we're not uninitialized (bug 361773).
|
||||
if (mState & XML_HTTP_REQUEST_ABORTED) {
|
||||
ChangeState(XML_HTTP_REQUEST_UNSENT, false); // IE seems to do it
|
||||
if (mFlagAborted) {
|
||||
ChangeState(State::unsent, false); // IE seems to do it
|
||||
}
|
||||
|
||||
mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
|
||||
mFlagSyncLooping = false;
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestMainThread::Abort(ErrorResult& arv)
|
||||
{
|
||||
CloseRequestWithError(ProgressEventType::abort, XML_HTTP_REQUEST_ABORTED);
|
||||
mFlagAborted = true;
|
||||
CloseRequestWithError(ProgressEventType::abort);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1162,8 +1132,9 @@ XMLHttpRequestMainThread::GetAllResponseHeaders(nsACString& aResponseHeaders,
|
|||
|
||||
// If the state is UNSENT or OPENED,
|
||||
// return the empty string and terminate these steps.
|
||||
if (mState & (XML_HTTP_REQUEST_UNSENT |
|
||||
XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT)) {
|
||||
if (mState == State::unsent ||
|
||||
mState == State::opened ||
|
||||
mState == State::sent) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1227,8 +1198,9 @@ XMLHttpRequestMainThread::GetResponseHeader(const nsACString& header,
|
|||
if (!httpChannel) {
|
||||
// If the state is UNSENT or OPENED,
|
||||
// return null and terminate these steps.
|
||||
if (mState & (XML_HTTP_REQUEST_UNSENT |
|
||||
XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT)) {
|
||||
if (mState == State::unsent ||
|
||||
mState == State::opened ||
|
||||
mState == State::sent) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1285,7 +1257,7 @@ XMLHttpRequestMainThread::GetResponseHeader(const nsACString& header,
|
|||
already_AddRefed<nsILoadGroup>
|
||||
XMLHttpRequestMainThread::GetLoadGroup() const
|
||||
{
|
||||
if (mState & XML_HTTP_REQUEST_BACKGROUND) {
|
||||
if (mFlagBackgroundRequest) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1433,10 +1405,8 @@ XMLHttpRequestMainThread::Open(const nsACString& inMethod, const nsACString& url
|
|||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
|
||||
if (mState & (XML_HTTP_REQUEST_OPENED |
|
||||
XML_HTTP_REQUEST_HEADERS_RECEIVED |
|
||||
XML_HTTP_REQUEST_LOADING |
|
||||
XML_HTTP_REQUEST_SENT)) {
|
||||
if (mState == State::opened || mState == State::headers_received ||
|
||||
mState == State::loading || mState == State::sent) {
|
||||
// IE aborts as well
|
||||
Abort();
|
||||
|
||||
|
@ -1447,14 +1417,11 @@ XMLHttpRequestMainThread::Open(const nsACString& inMethod, const nsACString& url
|
|||
// why things didn't work.
|
||||
}
|
||||
|
||||
// Unset any pre-existing aborted and timed-out states.
|
||||
mState &= ~XML_HTTP_REQUEST_ABORTED & ~XML_HTTP_REQUEST_TIMED_OUT;
|
||||
// Unset any pre-existing aborted and timed-out flags.
|
||||
mFlagAborted = false;
|
||||
mFlagTimedOut = false;
|
||||
|
||||
if (async) {
|
||||
mState |= XML_HTTP_REQUEST_ASYNC;
|
||||
} else {
|
||||
mState &= ~XML_HTTP_REQUEST_ASYNC;
|
||||
}
|
||||
mFlagAsynchronous = async;
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = GetDocumentIfCurrent();
|
||||
if (!doc) {
|
||||
|
@ -1560,7 +1527,7 @@ XMLHttpRequestMainThread::Open(const nsACString& inMethod, const nsACString& url
|
|||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mState &= ~XML_HTTP_REQUEST_HAD_UPLOAD_LISTENERS_ON_SEND;
|
||||
mFlagHadUploadListenersOnSend = false;
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
|
||||
if (httpChannel) {
|
||||
|
@ -1574,7 +1541,7 @@ XMLHttpRequestMainThread::Open(const nsACString& inMethod, const nsACString& url
|
|||
}
|
||||
}
|
||||
|
||||
ChangeState(XML_HTTP_REQUEST_OPENED);
|
||||
ChangeState(State::opened);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1648,7 +1615,7 @@ XMLHttpRequestMainThread::StreamReaderFunc(nsIInputStream* in,
|
|||
xmlHttpRequest->AppendToResponseText(fromRawSegment, count);
|
||||
}
|
||||
|
||||
if (xmlHttpRequest->mState & XML_HTTP_REQUEST_PARSEBODY) {
|
||||
if (xmlHttpRequest->mFlagParseBody) {
|
||||
// Give the same data to the parser.
|
||||
|
||||
// We need to wrap the data in a new lightweight stream and pass that
|
||||
|
@ -1667,7 +1634,7 @@ XMLHttpRequestMainThread::StreamReaderFunc(nsIInputStream* in,
|
|||
// No use to continue parsing if we failed here, but we
|
||||
// should still finish reading the stream
|
||||
if (NS_FAILED(parsingResult)) {
|
||||
xmlHttpRequest->mState &= ~XML_HTTP_REQUEST_PARSEBODY;
|
||||
xmlHttpRequest->mFlagParseBody = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1737,13 +1704,13 @@ XMLHttpRequestMainThread::OnDataAvailable(nsIRequest *request,
|
|||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
ChangeState(XML_HTTP_REQUEST_LOADING);
|
||||
ChangeState(State::loading);
|
||||
return request->Cancel(NS_OK);
|
||||
}
|
||||
|
||||
mDataAvailable += totalRead;
|
||||
|
||||
ChangeState(XML_HTTP_REQUEST_LOADING);
|
||||
ChangeState(State::loading);
|
||||
|
||||
MaybeDispatchProgressEvents(false);
|
||||
|
||||
|
@ -1768,19 +1735,20 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
}
|
||||
|
||||
// Don't do anything if we have been aborted
|
||||
if (mState & XML_HTTP_REQUEST_UNSENT)
|
||||
if (mState == State::unsent) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Apparently, Abort() should set XML_HTTP_REQUEST_UNSENT. See bug 361773.
|
||||
/* Apparently, Abort() should set State::unsent. See bug 361773.
|
||||
XHR2 spec says this is correct. */
|
||||
if (mState & XML_HTTP_REQUEST_ABORTED) {
|
||||
if (mFlagAborted) {
|
||||
NS_ERROR("Ugh, still getting data on an aborted XMLHttpRequest!");
|
||||
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Don't do anything if we have timed out.
|
||||
if (mState & XML_HTTP_REQUEST_TIMED_OUT) {
|
||||
if (mFlagTimedOut) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1791,8 +1759,7 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
request->GetStatus(&status);
|
||||
mErrorLoad = mErrorLoad || NS_FAILED(status);
|
||||
|
||||
if (mUpload && !mUploadComplete && !mErrorLoad &&
|
||||
(mState & XML_HTTP_REQUEST_ASYNC)) {
|
||||
if (mUpload && !mUploadComplete && !mErrorLoad && mFlagAsynchronous) {
|
||||
if (mProgressTimerIsActive) {
|
||||
mProgressTimerIsActive = false;
|
||||
mProgressNotifier->Cancel();
|
||||
|
@ -1809,8 +1776,8 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
}
|
||||
|
||||
mContext = ctxt;
|
||||
mState |= XML_HTTP_REQUEST_PARSEBODY;
|
||||
ChangeState(XML_HTTP_REQUEST_HEADERS_RECEIVED);
|
||||
mFlagParseBody = true;
|
||||
ChangeState(State::headers_received);
|
||||
|
||||
ResetResponse();
|
||||
|
||||
|
@ -1897,11 +1864,11 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
// legacy users of XHR who use responseType == "" for retrieving the
|
||||
// responseText of text/html resources. This legacy case is so common
|
||||
// that it's not useful to emit a warning about it.
|
||||
if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
|
||||
if (!mFlagAsynchronous) {
|
||||
// We don't make cool new features available in the bad synchronous
|
||||
// mode. The synchronous mode is for legacy only.
|
||||
mWarnAboutSyncHtml = true;
|
||||
mState &= ~XML_HTTP_REQUEST_PARSEBODY;
|
||||
mFlagParseBody = false;
|
||||
} else {
|
||||
mIsHtml = true;
|
||||
}
|
||||
|
@ -1911,14 +1878,14 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
// Follow https://xhr.spec.whatwg.org/
|
||||
// If final MIME type is not null, text/html, text/xml, application/xml,
|
||||
// or does not end in +xml, return null.
|
||||
mState &= ~XML_HTTP_REQUEST_PARSEBODY;
|
||||
mFlagParseBody = false;
|
||||
}
|
||||
} else {
|
||||
// The request failed, so we shouldn't be parsing anyway
|
||||
mState &= ~XML_HTTP_REQUEST_PARSEBODY;
|
||||
mFlagParseBody = false;
|
||||
}
|
||||
|
||||
if (mState & XML_HTTP_REQUEST_PARSEBODY) {
|
||||
if (mFlagParseBody) {
|
||||
nsCOMPtr<nsIURI> baseURI, docURI;
|
||||
rv = mChannel->GetURI(getter_AddRefs(docURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1991,7 +1958,7 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
// We won't get any progress events anyway if we didn't have progress
|
||||
// events when starting the request - so maybe no need to start timer here.
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
(mState & XML_HTTP_REQUEST_ASYNC) &&
|
||||
mFlagAsynchronous &&
|
||||
HasListenersFor(nsGkAtoms::onprogress)) {
|
||||
StartProgressEventTimer();
|
||||
}
|
||||
|
@ -2020,16 +1987,15 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
|||
|
||||
// make sure to notify the listener if we were aborted
|
||||
// XXX in fact, why don't we do the cleanup below in this case??
|
||||
// XML_HTTP_REQUEST_UNSENT is for abort calls. See OnStartRequest above.
|
||||
if ((mState & XML_HTTP_REQUEST_UNSENT) ||
|
||||
(mState & XML_HTTP_REQUEST_TIMED_OUT)) {
|
||||
// State::unsent is for abort calls. See OnStartRequest above.
|
||||
if (mState == State::unsent || mFlagTimedOut) {
|
||||
if (mXMLParserStreamListener)
|
||||
(void) mXMLParserStreamListener->OnStopRequest(request, ctxt, status);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Is this good enough here?
|
||||
if (mState & XML_HTTP_REQUEST_PARSEBODY && mXMLParserStreamListener) {
|
||||
if (mXMLParserStreamListener && mFlagParseBody) {
|
||||
mXMLParserStreamListener->OnStopRequest(request, ctxt, status);
|
||||
}
|
||||
|
||||
|
@ -2093,7 +2059,7 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
|||
mChannelEventSink = nullptr;
|
||||
mProgressEventSink = nullptr;
|
||||
|
||||
mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
|
||||
mFlagSyncLooping = false;
|
||||
|
||||
if (NS_FAILED(status)) {
|
||||
// This can happen if the server is unreachable. Other possible
|
||||
|
@ -2106,8 +2072,7 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
|||
// If we're uninitialized at this point, we encountered an error
|
||||
// earlier and listeners have already been notified. Also we do
|
||||
// not want to do this if we already completed.
|
||||
if (mState & (XML_HTTP_REQUEST_UNSENT |
|
||||
XML_HTTP_REQUEST_DONE)) {
|
||||
if (mState == State::unsent || mState == State::done) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2116,7 +2081,7 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
|||
return NS_OK;
|
||||
}
|
||||
if (mIsHtml) {
|
||||
NS_ASSERTION(!(mState & XML_HTTP_REQUEST_SYNCLOOPING),
|
||||
NS_ASSERTION(!mFlagSyncLooping,
|
||||
"We weren't supposed to support HTML parsing with XHR!");
|
||||
nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(mResponseXML);
|
||||
EventListenerManager* manager =
|
||||
|
@ -2146,7 +2111,8 @@ XMLHttpRequestMainThread::ChangeStateToDone()
|
|||
MaybeDispatchProgressEvents(true);
|
||||
}
|
||||
|
||||
ChangeState(XML_HTTP_REQUEST_DONE, true);
|
||||
ChangeState(State::done, true);
|
||||
|
||||
if (mTimeoutTimer) {
|
||||
mTimeoutTimer->Cancel();
|
||||
}
|
||||
|
@ -2462,12 +2428,12 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable<RequestBody>
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Return error if we're already processing a request
|
||||
if (XML_HTTP_REQUEST_SENT & mState) {
|
||||
if (mState == State::sent) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
// Make sure we've been opened
|
||||
if (!mChannel || !(XML_HTTP_REQUEST_OPENED & mState)) {
|
||||
if (!mChannel || mState != State::opened) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
|
@ -2656,8 +2622,7 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable<RequestBody>
|
|||
|
||||
ResetResponse();
|
||||
|
||||
if (!IsSystemXHR() && !mIsAnon &&
|
||||
(mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS)) {
|
||||
if (!IsSystemXHR() && !mIsAnon && mFlagACwithCredentials) {
|
||||
// This is quite sad. We have to create the channel in .open(), since the
|
||||
// chrome-only xhr.channel API depends on that. However .withCredentials
|
||||
// can be modified after, so we don't know what to set the
|
||||
|
@ -2731,14 +2696,14 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable<RequestBody>
|
|||
|
||||
// Check if we should enabled cross-origin upload listeners.
|
||||
if (mUpload && mUpload->HasListeners()) {
|
||||
mState |= XML_HTTP_REQUEST_HAD_UPLOAD_LISTENERS_ON_SEND;
|
||||
mFlagHadUploadListenersOnSend = true;
|
||||
}
|
||||
|
||||
// Set up the preflight if needed
|
||||
if (!IsSystemXHR()) {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
|
||||
loadInfo->SetCorsPreflightInfo(mCORSUnsafeHeaders,
|
||||
mState & XML_HTTP_REQUEST_HAD_UPLOAD_LISTENERS_ON_SEND);
|
||||
mFlagHadUploadListenersOnSend);
|
||||
}
|
||||
|
||||
mIsMappedArrayBuffer = false;
|
||||
|
@ -2788,8 +2753,8 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable<RequestBody>
|
|||
mWaitingForOnStopRequest = true;
|
||||
|
||||
// If we're synchronous, spin an event loop here and wait
|
||||
if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
|
||||
mState |= XML_HTTP_REQUEST_SYNCLOOPING;
|
||||
if (!mFlagAsynchronous) {
|
||||
mFlagSyncLooping = true;
|
||||
|
||||
nsCOMPtr<nsIDocument> suspendedDoc;
|
||||
nsCOMPtr<nsIRunnable> resumeTimeoutRunnable;
|
||||
|
@ -2806,14 +2771,13 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable<RequestBody>
|
|||
}
|
||||
}
|
||||
|
||||
ChangeState(XML_HTTP_REQUEST_SENT);
|
||||
ChangeState(State::sent);
|
||||
|
||||
{
|
||||
nsAutoSyncOperation sync(suspendedDoc);
|
||||
// Note, calling ChangeState may have cleared
|
||||
// XML_HTTP_REQUEST_SYNCLOOPING flag.
|
||||
// Note, calling ChangeState may have cleared mFlagSyncLooping
|
||||
nsIThread *thread = NS_GetCurrentThread();
|
||||
while (mState & XML_HTTP_REQUEST_SYNCLOOPING) {
|
||||
while (mFlagSyncLooping) {
|
||||
if (!NS_ProcessNextEvent(thread)) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
break;
|
||||
|
@ -2834,7 +2798,7 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable<RequestBody>
|
|||
// that this needs to come after the AsyncOpen() and rv check, because this
|
||||
// can run script that would try to restart this request, and that could end
|
||||
// up doing our AsyncOpen on a null channel if the reentered AsyncOpen fails.
|
||||
ChangeState(XML_HTTP_REQUEST_SENT);
|
||||
ChangeState(State::sent);
|
||||
if (mUpload && mUpload->HasListenersFor(nsGkAtoms::onprogress)) {
|
||||
StartProgressEventTimer();
|
||||
}
|
||||
|
@ -2859,7 +2823,7 @@ XMLHttpRequestMainThread::SetRequestHeader(const nsACString& header,
|
|||
const nsACString& value)
|
||||
{
|
||||
// Step 1 and 2
|
||||
if (!(mState & XML_HTTP_REQUEST_OPENED)) {
|
||||
if (mState != State::opened) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
NS_ASSERTION(mChannel, "mChannel must be valid if we're OPENED.");
|
||||
|
@ -2968,8 +2932,7 @@ XMLHttpRequestMainThread::SetTimeout(uint32_t aTimeout)
|
|||
void
|
||||
XMLHttpRequestMainThread::SetTimeout(uint32_t aTimeout, ErrorResult& aRv)
|
||||
{
|
||||
if (!(mState & (XML_HTTP_REQUEST_ASYNC | XML_HTTP_REQUEST_UNSENT)) &&
|
||||
HasOrHasHadOwner()) {
|
||||
if (!mFlagAsynchronous && mState != State::unsent && HasOrHasHadOwner()) {
|
||||
/* Timeout is not supported for synchronous requests with an owning window,
|
||||
per XHR2 spec. */
|
||||
LogMessage("TimeoutSyncXHRWarning", GetOwner());
|
||||
|
@ -2988,7 +2951,7 @@ XMLHttpRequestMainThread::StartTimeoutTimer()
|
|||
{
|
||||
MOZ_ASSERT(mRequestSentTime,
|
||||
"StartTimeoutTimer mustn't be called before the request was sent!");
|
||||
if (mState & XML_HTTP_REQUEST_DONE) {
|
||||
if (mState == State::done) {
|
||||
// do nothing!
|
||||
return;
|
||||
}
|
||||
|
@ -3024,25 +2987,25 @@ uint16_t
|
|||
XMLHttpRequestMainThread::ReadyState() const
|
||||
{
|
||||
// Translate some of our internal states for external consumers
|
||||
if (mState & XML_HTTP_REQUEST_UNSENT) {
|
||||
if (mState == State::unsent) {
|
||||
return UNSENT;
|
||||
}
|
||||
if (mState & (XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT)) {
|
||||
if (mState == State::opened || mState == State::sent) {
|
||||
return OPENED;
|
||||
}
|
||||
if (mState & XML_HTTP_REQUEST_HEADERS_RECEIVED) {
|
||||
if (mState == State::headers_received) {
|
||||
return HEADERS_RECEIVED;
|
||||
}
|
||||
if (mState & XML_HTTP_REQUEST_LOADING) {
|
||||
if (mState == State::loading) {
|
||||
return LOADING;
|
||||
}
|
||||
MOZ_ASSERT(mState & XML_HTTP_REQUEST_DONE);
|
||||
MOZ_ASSERT(mState == State::done);
|
||||
return DONE;
|
||||
}
|
||||
|
||||
void XMLHttpRequestMainThread::OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv)
|
||||
{
|
||||
if ((mState & XML_HTTP_REQUEST_LOADING) || (mState & XML_HTTP_REQUEST_DONE)) {
|
||||
if (mState == State::loading || mState == State::done) {
|
||||
ResetResponse();
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
|
@ -3069,7 +3032,7 @@ XMLHttpRequestMainThread::GetMozBackgroundRequest(bool *_retval)
|
|||
bool
|
||||
XMLHttpRequestMainThread::MozBackgroundRequest() const
|
||||
{
|
||||
return !!(mState & XML_HTTP_REQUEST_BACKGROUND);
|
||||
return mFlagBackgroundRequest;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -3079,16 +3042,12 @@ XMLHttpRequestMainThread::SetMozBackgroundRequest(bool aMozBackgroundRequest)
|
|||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
if (!(mState & XML_HTTP_REQUEST_UNSENT)) {
|
||||
if (mState != State::unsent) {
|
||||
// Can't change this while we're in the middle of something.
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
if (aMozBackgroundRequest) {
|
||||
mState |= XML_HTTP_REQUEST_BACKGROUND;
|
||||
} else {
|
||||
mState &= ~XML_HTTP_REQUEST_BACKGROUND;
|
||||
}
|
||||
mFlagBackgroundRequest = aMozBackgroundRequest;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -3111,7 +3070,7 @@ XMLHttpRequestMainThread::GetWithCredentials(bool *_retval)
|
|||
bool
|
||||
XMLHttpRequestMainThread::WithCredentials() const
|
||||
{
|
||||
return !!(mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS);
|
||||
return mFlagACwithCredentials;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -3128,43 +3087,33 @@ XMLHttpRequestMainThread::SetWithCredentials(bool aWithCredentials, ErrorResult&
|
|||
// Return error if we're already processing a request. Note that we can't use
|
||||
// ReadyState() here, because it can't differentiate between "opened" and
|
||||
// "sent", so we use mState directly.
|
||||
if ((!(mState & XML_HTTP_REQUEST_UNSENT) &&
|
||||
!(mState & XML_HTTP_REQUEST_OPENED)) ||
|
||||
mIsAnon) {
|
||||
if ((mState != State::unsent && mState != State::opened) || mIsAnon) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aWithCredentials) {
|
||||
mState |= XML_HTTP_REQUEST_AC_WITH_CREDENTIALS;
|
||||
} else {
|
||||
mState &= ~XML_HTTP_REQUEST_AC_WITH_CREDENTIALS;
|
||||
}
|
||||
mFlagACwithCredentials = aWithCredentials;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XMLHttpRequestMainThread::ChangeState(uint32_t aState, bool aBroadcast)
|
||||
XMLHttpRequestMainThread::ChangeState(State aState, bool aBroadcast)
|
||||
{
|
||||
// If we are setting one of the mutually exclusive states,
|
||||
// unset those state bits first.
|
||||
if (aState & XML_HTTP_REQUEST_LOADSTATES) {
|
||||
mState &= ~XML_HTTP_REQUEST_LOADSTATES;
|
||||
}
|
||||
mState |= aState;
|
||||
bool droppingFromSENTtoOPENED = mState == State::sent &&
|
||||
aState == State::opened;
|
||||
|
||||
mState = aState;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (mProgressNotifier &&
|
||||
!(aState & (XML_HTTP_REQUEST_HEADERS_RECEIVED | XML_HTTP_REQUEST_LOADING))) {
|
||||
aState != State::headers_received && aState != State::loading) {
|
||||
mProgressTimerIsActive = false;
|
||||
mProgressNotifier->Cancel();
|
||||
}
|
||||
|
||||
if ((aState & XML_HTTP_REQUEST_LOADSTATES) && // Broadcast load states only
|
||||
aState != XML_HTTP_REQUEST_SENT && // And not internal ones
|
||||
if (aState != State::sent && // SENT is internal
|
||||
!droppingFromSENTtoOPENED && // since SENT is essentially OPENED
|
||||
aBroadcast &&
|
||||
(mState & XML_HTTP_REQUEST_ASYNC ||
|
||||
aState & XML_HTTP_REQUEST_OPENED ||
|
||||
aState & XML_HTTP_REQUEST_DONE)) {
|
||||
(mFlagAsynchronous || aState == State::opened || aState == State::done)) {
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
rv = CreateReadystatechangeEvent(getter_AddRefs(event));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -3256,7 +3205,7 @@ XMLHttpRequestMainThread::MaybeDispatchProgressEvents(bool aFinalProgress)
|
|||
if (mProgressTimerIsActive ||
|
||||
!mProgressSinceLastProgressEvent ||
|
||||
mErrorLoad ||
|
||||
!(mState & XML_HTTP_REQUEST_ASYNC)) {
|
||||
!mFlagAsynchronous) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3264,9 +3213,8 @@ XMLHttpRequestMainThread::MaybeDispatchProgressEvents(bool aFinalProgress)
|
|||
StartProgressEventTimer();
|
||||
}
|
||||
|
||||
// We're uploading if our state is XML_HTTP_REQUEST_OPENED or
|
||||
// XML_HTTP_REQUEST_SENT
|
||||
if ((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState) {
|
||||
// We're uploading if our state is State::opened or State::sent
|
||||
if (mState == State::opened || mState == State::sent) {
|
||||
if (mUpload && !mUploadComplete) {
|
||||
DispatchProgressEvent(mUpload, ProgressEventType::progress,
|
||||
mUploadLengthComputable, mUploadTransferred,
|
||||
|
@ -3296,9 +3244,8 @@ XMLHttpRequestMainThread::MaybeDispatchProgressEvents(bool aFinalProgress)
|
|||
NS_IMETHODIMP
|
||||
XMLHttpRequestMainThread::OnProgress(nsIRequest *aRequest, nsISupports *aContext, int64_t aProgress, int64_t aProgressMax)
|
||||
{
|
||||
// We're uploading if our state is XML_HTTP_REQUEST_OPENED or
|
||||
// XML_HTTP_REQUEST_SENT
|
||||
bool upload = !!((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState);
|
||||
// We're uploading if our state is State::opened or State::sent
|
||||
bool upload = mState == State::opened || mState == State::sent;
|
||||
// When uploading, OnProgress reports also headers in aProgress and aProgressMax.
|
||||
// So, try to remove the headers, if possible.
|
||||
bool lengthComputable = (aProgressMax != -1);
|
||||
|
@ -3343,7 +3290,7 @@ bool
|
|||
XMLHttpRequestMainThread::AllowUploadProgress()
|
||||
{
|
||||
return !IsCrossSiteCORSRequest() ||
|
||||
(mState & XML_HTTP_REQUEST_HAD_UPLOAD_LISTENERS_ON_SEND);
|
||||
mFlagHadUploadListenersOnSend;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
|
@ -3378,7 +3325,7 @@ XMLHttpRequestMainThread::GetInterface(const nsIID & aIID, void **aResult)
|
|||
}
|
||||
}
|
||||
|
||||
if (mState & XML_HTTP_REQUEST_BACKGROUND) {
|
||||
if (mFlagBackgroundRequest) {
|
||||
nsCOMPtr<nsIInterfaceRequestor> badCertHandler(do_CreateInstance(NS_BADCERTHANDLER_CONTRACTID, &rv));
|
||||
|
||||
// Ignore failure to get component, we may not have all its dependencies
|
||||
|
@ -3480,13 +3427,14 @@ XMLHttpRequestMainThread::GetMozSystem(bool* aSystem)
|
|||
void
|
||||
XMLHttpRequestMainThread::HandleTimeoutCallback()
|
||||
{
|
||||
if (mState & XML_HTTP_REQUEST_DONE) {
|
||||
if (mState == State::done) {
|
||||
NS_NOTREACHED("XMLHttpRequestMainThread::HandleTimeoutCallback with completed request");
|
||||
// do nothing!
|
||||
return;
|
||||
}
|
||||
|
||||
CloseRequestWithError(ProgressEventType::timeout, XML_HTTP_REQUEST_TIMED_OUT);
|
||||
mFlagTimedOut = true;
|
||||
CloseRequestWithError(ProgressEventType::timeout);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef mozilla_dom_XMLHttpRequestMainThread_h
|
||||
#define mozilla_dom_XMLHttpRequestMainThread_h
|
||||
|
||||
#include <bitset>
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIXMLHttpRequest.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
|
@ -558,6 +559,18 @@ public:
|
|||
return sDontWarnAboutSyncXHR;
|
||||
}
|
||||
protected:
|
||||
// XHR states are meant to mirror the XHR2 spec:
|
||||
// https://xhr.spec.whatwg.org/#states
|
||||
// Note that we currently have an extra pseudo-state called sent.
|
||||
enum class State : uint8_t {
|
||||
unsent, // object has been constructed.
|
||||
opened, // open() has been successfully invoked.
|
||||
sent, // non-spec, corresponds with "opened and the send() flag is set".
|
||||
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 NS_METHOD StreamReaderFunc(nsIInputStream* in,
|
||||
|
@ -571,7 +584,7 @@ protected:
|
|||
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(uint32_t aState, bool aBroadcast = true);
|
||||
nsresult ChangeState(State aState, bool aBroadcast = true);
|
||||
already_AddRefed<nsILoadGroup> GetLoadGroup() const;
|
||||
nsIURI *GetBaseURI();
|
||||
|
||||
|
@ -675,7 +688,17 @@ protected:
|
|||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
|
||||
uint32_t mState;
|
||||
State mState;
|
||||
|
||||
bool mFlagAsynchronous;
|
||||
bool mFlagAborted;
|
||||
bool mFlagParseBody;
|
||||
bool mFlagSyncLooping;
|
||||
bool mFlagBackgroundRequest;
|
||||
bool mFlagHadUploadListenersOnSend;
|
||||
bool mFlagACwithCredentials;
|
||||
bool mFlagTimedOut;
|
||||
bool mFlagDeleted;
|
||||
|
||||
RefPtr<XMLHttpRequestUpload> mUpload;
|
||||
int64_t mUploadTransferred;
|
||||
|
@ -725,10 +748,8 @@ protected:
|
|||
* events.
|
||||
*
|
||||
* @param aType The progress event type.
|
||||
* @param aFlag A XML_HTTP_REQUEST_* state flag defined in
|
||||
* XMLHttpRequestMainthread.cpp.
|
||||
*/
|
||||
void CloseRequestWithError(const ProgressEventType aType, const uint32_t aFlag);
|
||||
void CloseRequestWithError(const ProgressEventType aType);
|
||||
|
||||
bool mFirstStartRequestSeen;
|
||||
bool mInLoadProgressEvent;
|
||||
|
|
Загрузка…
Ссылка в новой задаче