зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1285036 - Part 4: Remove the 'sent' pseudostate and add support for the spec's send() flag instead. r=baku
This commit is contained in:
Родитель
6876d3a1ff
Коммит
5aaa9bf897
|
@ -164,7 +164,7 @@ XMLHttpRequestMainThread::XMLHttpRequestMainThread()
|
|||
mFlagSynchronous(false), mFlagAborted(false), mFlagParseBody(false),
|
||||
mFlagSyncLooping(false), mFlagBackgroundRequest(false),
|
||||
mFlagHadUploadListenersOnSend(false), mFlagACwithCredentials(false),
|
||||
mFlagTimedOut(false), mFlagDeleted(false),
|
||||
mFlagTimedOut(false), mFlagDeleted(false), mFlagSend(false),
|
||||
mUploadTransferred(0), mUploadTotal(0), mUploadComplete(true),
|
||||
mProgressSinceLastProgressEvent(false),
|
||||
mRequestSentTime(0), mTimeoutMilliseconds(0),
|
||||
|
@ -188,7 +188,8 @@ XMLHttpRequestMainThread::~XMLHttpRequestMainThread()
|
|||
{
|
||||
mFlagDeleted = true;
|
||||
|
||||
if (mState == State::sent || mState == State::loading) {
|
||||
if ((mState == State::opened && mFlagSend) ||
|
||||
mState == State::loading) {
|
||||
Abort();
|
||||
}
|
||||
|
||||
|
@ -1020,7 +1021,7 @@ XMLHttpRequestMainThread::CloseRequestWithError(const ProgressEventType aType)
|
|||
}
|
||||
|
||||
if (mState != State::unsent &&
|
||||
mState != State::opened &&
|
||||
!(mState == State::opened && !mFlagSend) &&
|
||||
mState != State::done) {
|
||||
ChangeState(State::done, true);
|
||||
|
||||
|
@ -1132,9 +1133,7 @@ XMLHttpRequestMainThread::GetAllResponseHeaders(nsACString& aResponseHeaders,
|
|||
|
||||
// If the state is UNSENT or OPENED,
|
||||
// return the empty string and terminate these steps.
|
||||
if (mState == State::unsent ||
|
||||
mState == State::opened ||
|
||||
mState == State::sent) {
|
||||
if (mState == State::unsent || mState == State::opened) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1198,9 +1197,7 @@ XMLHttpRequestMainThread::GetResponseHeader(const nsACString& header,
|
|||
if (!httpChannel) {
|
||||
// If the state is UNSENT or OPENED,
|
||||
// return null and terminate these steps.
|
||||
if (mState == State::unsent ||
|
||||
mState == State::opened ||
|
||||
mState == State::sent) {
|
||||
if (mState == State::unsent || mState == State::opened) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1407,7 +1404,7 @@ XMLHttpRequestMainThread::Open(const nsACString& inMethod, const nsACString& url
|
|||
nsCOMPtr<nsIURI> uri;
|
||||
|
||||
if (mState == State::opened || mState == State::headers_received ||
|
||||
mState == State::loading || mState == State::sent) {
|
||||
mState == State::loading) {
|
||||
// IE aborts as well
|
||||
Abort();
|
||||
|
||||
|
@ -1418,6 +1415,8 @@ XMLHttpRequestMainThread::Open(const nsACString& inMethod, const nsACString& url
|
|||
// why things didn't work.
|
||||
}
|
||||
|
||||
mFlagSend = false;
|
||||
|
||||
// Unset any pre-existing aborted and timed-out flags.
|
||||
mFlagAborted = false;
|
||||
mFlagTimedOut = false;
|
||||
|
@ -2113,6 +2112,8 @@ XMLHttpRequestMainThread::ChangeStateToDone()
|
|||
|
||||
ChangeState(State::done, true);
|
||||
|
||||
mFlagSend = false;
|
||||
|
||||
if (mTimeoutTimer) {
|
||||
mTimeoutTimer->Cancel();
|
||||
}
|
||||
|
@ -2427,13 +2428,9 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable<RequestBody>
|
|||
nsresult rv = CheckInnerWindowCorrectness();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Return error if we're already processing a request
|
||||
if (mState == State::sent) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
// Make sure we've been opened
|
||||
if (!mChannel || mState != State::opened) {
|
||||
if (mState != State::opened || // Step 1
|
||||
mFlagSend || // Step 2
|
||||
!mChannel) { // Gecko-specific
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
|
@ -2752,6 +2749,9 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable<RequestBody>
|
|||
|
||||
mWaitingForOnStopRequest = true;
|
||||
|
||||
// Step 8
|
||||
mFlagSend = true;
|
||||
|
||||
// If we're synchronous, spin an event loop here and wait
|
||||
if (mFlagSynchronous) {
|
||||
mFlagSyncLooping = true;
|
||||
|
@ -2771,11 +2771,13 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable<RequestBody>
|
|||
}
|
||||
}
|
||||
|
||||
ChangeState(State::sent);
|
||||
if (mProgressNotifier) {
|
||||
mProgressTimerIsActive = false;
|
||||
mProgressNotifier->Cancel();
|
||||
}
|
||||
|
||||
{
|
||||
nsAutoSyncOperation sync(suspendedDoc);
|
||||
// Note, calling ChangeState may have cleared mFlagSyncLooping
|
||||
nsIThread *thread = NS_GetCurrentThread();
|
||||
while (mFlagSyncLooping) {
|
||||
if (!NS_ProcessNextEvent(thread)) {
|
||||
|
@ -2798,7 +2800,11 @@ 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(State::sent);
|
||||
if (mProgressNotifier) {
|
||||
mProgressTimerIsActive = false;
|
||||
mProgressNotifier->Cancel();
|
||||
}
|
||||
|
||||
if (mUpload && mUpload->HasListenersFor(nsGkAtoms::onprogress)) {
|
||||
StartProgressEventTimer();
|
||||
}
|
||||
|
@ -2822,8 +2828,8 @@ NS_IMETHODIMP
|
|||
XMLHttpRequestMainThread::SetRequestHeader(const nsACString& header,
|
||||
const nsACString& value)
|
||||
{
|
||||
// Step 1 and 2
|
||||
if (mState != State::opened) {
|
||||
// Steps 1 and 2
|
||||
if (mState != State::opened || mFlagSend) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
NS_ASSERTION(mChannel, "mChannel must be valid if we're OPENED.");
|
||||
|
@ -2987,20 +2993,21 @@ uint16_t
|
|||
XMLHttpRequestMainThread::ReadyState() const
|
||||
{
|
||||
// Translate some of our internal states for external consumers
|
||||
if (mState == State::unsent) {
|
||||
return UNSENT;
|
||||
switch(mState) {
|
||||
case State::unsent:
|
||||
return UNSENT;
|
||||
case State::opened:
|
||||
return OPENED;
|
||||
case State::headers_received:
|
||||
return HEADERS_RECEIVED;
|
||||
case State::loading:
|
||||
return LOADING;
|
||||
case State::done:
|
||||
return DONE;
|
||||
default:
|
||||
MOZ_CRASH("Unknown state");
|
||||
}
|
||||
if (mState == State::opened || mState == State::sent) {
|
||||
return OPENED;
|
||||
}
|
||||
if (mState == State::headers_received) {
|
||||
return HEADERS_RECEIVED;
|
||||
}
|
||||
if (mState == State::loading) {
|
||||
return LOADING;
|
||||
}
|
||||
MOZ_ASSERT(mState == State::done);
|
||||
return DONE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void XMLHttpRequestMainThread::OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv)
|
||||
|
@ -3087,7 +3094,8 @@ 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 != State::unsent && mState != State::opened) || mIsAnon) {
|
||||
if ((mState != State::unsent && mState != State::opened) ||
|
||||
mFlagSend || mIsAnon) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
@ -3098,9 +3106,6 @@ XMLHttpRequestMainThread::SetWithCredentials(bool aWithCredentials, ErrorResult&
|
|||
nsresult
|
||||
XMLHttpRequestMainThread::ChangeState(State aState, bool aBroadcast)
|
||||
{
|
||||
bool droppingFromSENTtoOPENED = mState == State::sent &&
|
||||
aState == State::opened;
|
||||
|
||||
mState = aState;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
@ -3110,10 +3115,10 @@ XMLHttpRequestMainThread::ChangeState(State aState, bool aBroadcast)
|
|||
mProgressNotifier->Cancel();
|
||||
}
|
||||
|
||||
if (aState != State::sent && // SENT is internal
|
||||
!droppingFromSENTtoOPENED && // since SENT is essentially OPENED
|
||||
aBroadcast &&
|
||||
(!mFlagSynchronous || aState == State::opened || aState == State::done)) {
|
||||
|
||||
if (aBroadcast && (!mFlagSynchronous ||
|
||||
aState == State::opened ||
|
||||
aState == State::done)) {
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
rv = CreateReadystatechangeEvent(getter_AddRefs(event));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -3213,8 +3218,8 @@ XMLHttpRequestMainThread::MaybeDispatchProgressEvents(bool aFinalProgress)
|
|||
StartProgressEventTimer();
|
||||
}
|
||||
|
||||
// We're uploading if our state is State::opened or State::sent
|
||||
if (mState == State::opened || mState == State::sent) {
|
||||
// We're in the upload phase while our state is State::opened.
|
||||
if (mState == State::opened) {
|
||||
if (mUpload && !mUploadComplete) {
|
||||
DispatchProgressEvent(mUpload, ProgressEventType::progress,
|
||||
mUploadLengthComputable, mUploadTransferred,
|
||||
|
@ -3244,8 +3249,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 State::opened or State::sent
|
||||
bool upload = mState == State::opened || mState == State::sent;
|
||||
// We're in the upload phase while our state is State::opened.
|
||||
bool upload = mState == State::opened;
|
||||
// When uploading, OnProgress reports also headers in aProgress and aProgressMax.
|
||||
// So, try to remove the headers, if possible.
|
||||
bool lengthComputable = (aProgressMax != -1);
|
||||
|
|
|
@ -561,11 +561,9 @@ public:
|
|||
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.
|
||||
|
@ -700,6 +698,12 @@ protected:
|
|||
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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче