зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1538364 - Fire the load/loadend/final readyState events for XHR later during page load (after page load event if possible), r=baku
Differential Revision: https://phabricator.services.mozilla.com/D24613 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
ffd99e653e
Коммит
9ca69947d4
|
@ -2457,10 +2457,21 @@ void nsPIDOMWindowInner::SetAudioCapture(bool aCapture) {
|
|||
}
|
||||
}
|
||||
|
||||
void nsPIDOMWindowInner::SetActiveLoadingState(bool aIsLoading) /* const? */ {
|
||||
void nsPIDOMWindowInner::SetActiveLoadingState(bool aIsLoading) {
|
||||
if (!nsGlobalWindowInner::Cast(this)->IsChromeWindow()) {
|
||||
mTimeoutManager->SetLoading(aIsLoading);
|
||||
}
|
||||
|
||||
if (!aIsLoading) {
|
||||
for (uint32_t i = 0; i < mAfterLoadRunners.Length(); ++i) {
|
||||
NS_DispatchToCurrentThread(mAfterLoadRunners[i].forget());
|
||||
}
|
||||
mAfterLoadRunners.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void nsPIDOMWindowInner::AddAfterLoadRunner(nsIRunnable* aRunner) {
|
||||
mAfterLoadRunners.AppendElement(aRunner);
|
||||
}
|
||||
|
||||
// nsISpeechSynthesisGetter
|
||||
|
|
|
@ -33,6 +33,7 @@ class nsICSSDeclaration;
|
|||
class nsIDocShell;
|
||||
class nsDocShellLoadState;
|
||||
class nsIPrincipal;
|
||||
class nsIRunnable;
|
||||
class nsIScriptTimeoutHandler;
|
||||
class nsISerialEventTarget;
|
||||
class nsIURI;
|
||||
|
@ -175,6 +176,7 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
|
|||
|
||||
// Note: not related to IsLoading. Set to false if there's an error, etc.
|
||||
void SetActiveLoadingState(bool aIsActiveLoading);
|
||||
void AddAfterLoadRunner(nsIRunnable* aRunner);
|
||||
|
||||
bool AddAudioContext(mozilla::dom::AudioContext* aAudioContext);
|
||||
void RemoveAudioContext(mozilla::dom::AudioContext* aAudioContext);
|
||||
|
@ -664,6 +666,8 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
|
|||
// This will be non-null during the full lifetime of the window, initialized
|
||||
// during SetNewDocument, and cleared during FreeInnerObjects.
|
||||
RefPtr<mozilla::dom::WindowGlobalChild> mWindowGlobalChild;
|
||||
|
||||
nsTArray<nsCOMPtr<nsIRunnable>> mAfterLoadRunners;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMWindowInner, NS_PIDOMWINDOWINNER_IID)
|
||||
|
|
|
@ -43,7 +43,7 @@ already_AddRefed<XMLHttpRequest> XMLHttpRequest::Constructor(
|
|||
}
|
||||
|
||||
RefPtr<XMLHttpRequestMainThread> req = new XMLHttpRequestMainThread();
|
||||
req->Construct(principal->GetPrincipal(), global, cookieSettings);
|
||||
req->Construct(principal->GetPrincipal(), global, cookieSettings, false);
|
||||
req->InitParameters(aParams.mMozAnon, aParams.mMozSystem);
|
||||
return req.forget();
|
||||
}
|
||||
|
|
|
@ -235,6 +235,8 @@ XMLHttpRequestMainThread::XMLHttpRequestMainThread()
|
|||
}
|
||||
|
||||
XMLHttpRequestMainThread::~XMLHttpRequestMainThread() {
|
||||
DisconnectDoneNotifier();
|
||||
|
||||
mFlagDeleted = true;
|
||||
|
||||
if ((mState == XMLHttpRequest_Binding::OPENED && mFlagSend) ||
|
||||
|
@ -975,6 +977,7 @@ void XMLHttpRequestMainThread::Abort(ErrorResult& aRv) {
|
|||
|
||||
void XMLHttpRequestMainThread::AbortInternal(ErrorResult& aRv) {
|
||||
mFlagAborted = true;
|
||||
DisconnectDoneNotifier();
|
||||
|
||||
// Step 1
|
||||
TerminateOngoingFetch();
|
||||
|
@ -1456,6 +1459,7 @@ nsresult XMLHttpRequestMainThread::Open(const nsACString& aMethod,
|
|||
|
||||
// Step 11
|
||||
// timeouts are handled without a flag
|
||||
DisconnectDoneNotifier();
|
||||
mFlagSend = false;
|
||||
mRequestMethod.Assign(method);
|
||||
mRequestURL = parsedURL;
|
||||
|
@ -1691,7 +1695,7 @@ void XMLHttpRequestMainThread::LocalFileToBlobCompleted(Blob* aBlob) {
|
|||
mBlobStorage = nullptr;
|
||||
NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
|
||||
|
||||
ChangeStateToDone();
|
||||
ChangeStateToDone(mFlagSyncLooping);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -2096,7 +2100,7 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest* request, nsresult status) {
|
|||
|
||||
// If we were just reading a blob URL, we're already done
|
||||
if (status == NS_ERROR_FILE_ALREADY_EXISTS && mResponseBlob) {
|
||||
ChangeStateToDone();
|
||||
ChangeStateToDone(mFlagSyncLooping);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2182,6 +2186,7 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest* request, nsresult status) {
|
|||
mChannelEventSink = nullptr;
|
||||
mProgressEventSink = nullptr;
|
||||
|
||||
bool wasSync = mFlagSyncLooping;
|
||||
mFlagSyncLooping = false;
|
||||
mRequestSentTime = 0;
|
||||
|
||||
|
@ -2210,7 +2215,7 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest* request, nsresult status) {
|
|||
|
||||
// We postpone the 'done' until the creation of the Blob is completed.
|
||||
if (!waitingForBlobCreation) {
|
||||
ChangeStateToDone();
|
||||
ChangeStateToDone(wasSync);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -2238,14 +2243,14 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest* request, nsresult status) {
|
|||
mErrorParsingXML = true;
|
||||
mResponseXML = nullptr;
|
||||
}
|
||||
ChangeStateToDone();
|
||||
ChangeStateToDone(wasSync);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void XMLHttpRequestMainThread::OnBodyParseEnd() {
|
||||
mFlagParseBody = false;
|
||||
mParseEndListener = nullptr;
|
||||
ChangeStateToDone();
|
||||
ChangeStateToDone(mFlagSyncLooping);
|
||||
}
|
||||
|
||||
void XMLHttpRequestMainThread::MatchCharsetAndDecoderToResponseDocument() {
|
||||
|
@ -2258,8 +2263,48 @@ void XMLHttpRequestMainThread::MatchCharsetAndDecoderToResponseDocument() {
|
|||
mDecoder = mResponseXML->GetDocumentCharacterSet()->NewDecoder();
|
||||
}
|
||||
}
|
||||
void XMLHttpRequestMainThread::DisconnectDoneNotifier() {
|
||||
if (mDelayedDoneNotifier) {
|
||||
mDelayedDoneNotifier->Disconnect();
|
||||
mDelayedDoneNotifier = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void XMLHttpRequestMainThread::ChangeStateToDone() {
|
||||
void XMLHttpRequestMainThread::ChangeStateToDone(bool aWasSync) {
|
||||
DisconnectDoneNotifier();
|
||||
|
||||
if (!mForWorker && !aWasSync && mChannel) {
|
||||
// If the top level page is loading, try to postpone the handling of the
|
||||
// final events.
|
||||
nsLoadFlags loadFlags = 0;
|
||||
mChannel->GetLoadFlags(&loadFlags);
|
||||
if (loadFlags & nsIRequest::LOAD_BACKGROUND) {
|
||||
nsPIDOMWindowInner* owner = GetOwner();
|
||||
Document* doc = owner ? owner->GetExtantDoc() : nullptr;
|
||||
doc = doc ? doc->GetTopLevelContentDocument() : nullptr;
|
||||
if (doc &&
|
||||
(doc->GetReadyStateEnum() > Document::READYSTATE_UNINITIALIZED &&
|
||||
doc->GetReadyStateEnum() < Document::READYSTATE_COMPLETE)) {
|
||||
nsPIDOMWindowInner* topWin = doc->GetInnerWindow();
|
||||
if (topWin) {
|
||||
MOZ_ASSERT(!mDelayedDoneNotifier);
|
||||
RefPtr<XMLHttpRequestDoneNotifier> notifier =
|
||||
new XMLHttpRequestDoneNotifier(this);
|
||||
mDelayedDoneNotifier = notifier;
|
||||
topWin->AddAfterLoadRunner(notifier);
|
||||
NS_DispatchToCurrentThreadQueue(notifier.forget(), 5000,
|
||||
EventQueuePriority::Idle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChangeStateToDoneInternal();
|
||||
}
|
||||
|
||||
void XMLHttpRequestMainThread::ChangeStateToDoneInternal() {
|
||||
DisconnectDoneNotifier();
|
||||
StopProgressEventTimer();
|
||||
|
||||
MOZ_ASSERT(!mFlagParseBody,
|
||||
|
@ -3594,7 +3639,7 @@ void XMLHttpRequestMainThread::BlobStoreCompleted(
|
|||
mResponseBlob = aBlob;
|
||||
mBlobStorage = nullptr;
|
||||
|
||||
ChangeStateToDone();
|
||||
ChangeStateToDone(mFlagSyncLooping);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -157,6 +157,7 @@ class RequestHeaders {
|
|||
};
|
||||
|
||||
class nsXHRParseEndListener;
|
||||
class XMLHttpRequestDoneNotifier;
|
||||
|
||||
// Make sure that any non-DOM interfaces added here are also added to
|
||||
// nsXMLHttpRequestXPCOMifier.
|
||||
|
@ -171,6 +172,7 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest,
|
|||
public MutableBlobStorageCallback {
|
||||
friend class nsXHRParseEndListener;
|
||||
friend class nsXMLHttpRequestXPCOMifier;
|
||||
friend class XMLHttpRequestDoneNotifier;
|
||||
|
||||
public:
|
||||
enum class ProgressEventType : uint8_t {
|
||||
|
@ -199,7 +201,8 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest,
|
|||
XMLHttpRequestMainThread();
|
||||
|
||||
void Construct(nsIPrincipal* aPrincipal, nsIGlobalObject* aGlobalObject,
|
||||
nsICookieSettings* aCookieSettings, nsIURI* aBaseURI = nullptr,
|
||||
nsICookieSettings* aCookieSettings, bool aForWorker,
|
||||
nsIURI* aBaseURI = nullptr,
|
||||
nsILoadGroup* aLoadGroup = nullptr,
|
||||
PerformanceStorage* aPerformanceStorage = nullptr,
|
||||
nsICSPEventListener* aCSPEventListener = nullptr) {
|
||||
|
@ -209,6 +212,7 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest,
|
|||
mBaseURI = aBaseURI;
|
||||
mLoadGroup = aLoadGroup;
|
||||
mCookieSettings = aCookieSettings;
|
||||
mForWorker = aForWorker;
|
||||
mPerformanceStorage = aPerformanceStorage;
|
||||
mCSPEventListener = aCSPEventListener;
|
||||
}
|
||||
|
@ -458,7 +462,8 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest,
|
|||
bool InUploadPhase() const;
|
||||
|
||||
void OnBodyParseEnd();
|
||||
void ChangeStateToDone();
|
||||
void ChangeStateToDone(bool aWasSync);
|
||||
void ChangeStateToDoneInternal();
|
||||
|
||||
void StartProgressEventTimer();
|
||||
void StopProgressEventTimer();
|
||||
|
@ -604,6 +609,9 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest,
|
|||
|
||||
uint16_t mState;
|
||||
|
||||
// If true, this object is used by the worker's XMLHttpRequest.
|
||||
bool mForWorker;
|
||||
|
||||
bool mFlagSynchronous;
|
||||
bool mFlagAborted;
|
||||
bool mFlagParseBody;
|
||||
|
@ -714,6 +722,9 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest,
|
|||
// Our parse-end listener, if we are parsing.
|
||||
RefPtr<nsXHRParseEndListener> mParseEndListener;
|
||||
|
||||
RefPtr<XMLHttpRequestDoneNotifier> mDelayedDoneNotifier;
|
||||
void DisconnectDoneNotifier();
|
||||
|
||||
static bool sDontWarnAboutSyncXHR;
|
||||
};
|
||||
|
||||
|
@ -770,6 +781,28 @@ class nsXMLHttpRequestXPCOMifier final : public nsIStreamListener,
|
|||
RefPtr<XMLHttpRequestMainThread> mXHR;
|
||||
};
|
||||
|
||||
|
||||
class XMLHttpRequestDoneNotifier : public Runnable
|
||||
{
|
||||
public:
|
||||
explicit XMLHttpRequestDoneNotifier(XMLHttpRequestMainThread* aXHR)
|
||||
: Runnable("XMLHttpRequestDoneNotifier"), mXHR(aXHR) {}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
if (mXHR) {
|
||||
RefPtr<XMLHttpRequestMainThread> xhr = mXHR;
|
||||
mXHR = nullptr;
|
||||
xhr->ChangeStateToDoneInternal();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Disconnect() { mXHR = nullptr; }
|
||||
private:
|
||||
XMLHttpRequestMainThread* mXHR;
|
||||
};
|
||||
|
||||
|
||||
class nsXHRParseEndListener : public nsIDOMEventListener {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
|
|
@ -780,6 +780,7 @@ bool Proxy::Init() {
|
|||
mXHR->Construct(mWorkerPrivate->GetPrincipal(),
|
||||
ownerWindow ? ownerWindow->AsGlobal() : nullptr,
|
||||
mWorkerPrivate->CookieSettings(),
|
||||
true,
|
||||
mWorkerPrivate->GetBaseURI(), mWorkerPrivate->GetLoadGroup(),
|
||||
mWorkerPrivate->GetPerformanceStorage(),
|
||||
mWorkerPrivate->CSPEventListener());
|
||||
|
|
Загрузка…
Ссылка в новой задаче