mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1319744 - Ensure that progress events and corresponding LOADING readystatechanges fire as per spec. r=baku
This commit is contained in:
parent
cefb75a8ec
commit
54ad3187aa
@ -15,8 +15,8 @@ xhr.onloadend = function(e) {
|
||||
xhr.onprogress = function(e) {
|
||||
if (e.loaded > 0) {
|
||||
progressFired = true;
|
||||
xhr.abort();
|
||||
}
|
||||
xhr.abort();
|
||||
};
|
||||
|
||||
onmessage = function(e) {
|
||||
|
@ -107,6 +107,7 @@ support-files =
|
||||
script_createFile.js
|
||||
worker_suspended.js
|
||||
window_suspended.html
|
||||
!/dom/base/test/file_bug945152.jar
|
||||
!/dom/base/test/file_websocket_basic_wsh.py
|
||||
!/dom/base/test/file_websocket_hello_wsh.py
|
||||
!/dom/base/test/file_websocket_http_resource.txt
|
||||
|
@ -673,7 +673,7 @@ XMLHttpRequestMainThread::CreatePartialBlob(ErrorResult& aRv)
|
||||
// Use progress info to determine whether load is complete, but use
|
||||
// mDataAvailable to ensure a slice is created based on the uncompressed
|
||||
// data count.
|
||||
if (mLoadTotal == mLoadTransferred) {
|
||||
if (mState == State::done) {
|
||||
mResponseBlob = mDOMBlob;
|
||||
} else {
|
||||
mResponseBlob = mDOMBlob->CreateSlice(0, mDataAvailable,
|
||||
@ -688,7 +688,7 @@ XMLHttpRequestMainThread::CreatePartialBlob(ErrorResult& aRv)
|
||||
}
|
||||
|
||||
nsAutoCString contentType;
|
||||
if (mLoadTotal == mLoadTransferred) {
|
||||
if (mState == State::done) {
|
||||
mChannel->GetContentType(contentType);
|
||||
}
|
||||
|
||||
@ -1790,7 +1790,15 @@ XMLHttpRequestMainThread::OnDataAvailable(nsIRequest *request,
|
||||
|
||||
mDataAvailable += totalRead;
|
||||
|
||||
ChangeState(State::loading);
|
||||
// Fire the first progress event/loading state change
|
||||
if (mState != State::loading) {
|
||||
ChangeState(State::loading);
|
||||
if (!mFlagSynchronous) {
|
||||
DispatchProgressEvent(this, ProgressEventType::progress,
|
||||
mLoadTransferred, mLoadTotal);
|
||||
}
|
||||
mProgressSinceLastProgressEvent = false;
|
||||
}
|
||||
|
||||
if (!mFlagSynchronous && !mProgressTimerIsActive) {
|
||||
StartProgressEventTimer();
|
||||
@ -2098,10 +2106,6 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
||||
bool waitingForBlobCreation = false;
|
||||
|
||||
if (NS_SUCCEEDED(status) &&
|
||||
(mResponseType == XMLHttpRequestResponseType::_empty ||
|
||||
mResponseType == XMLHttpRequestResponseType::Text)) {
|
||||
mLoadTotal = mResponseBody.Length();
|
||||
} else if (NS_SUCCEEDED(status) &&
|
||||
(mResponseType == XMLHttpRequestResponseType::Blob ||
|
||||
mResponseType == XMLHttpRequestResponseType::Moz_blob)) {
|
||||
ErrorResult rv;
|
||||
@ -2111,11 +2115,6 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
||||
if (mDOMBlob) {
|
||||
mResponseBlob = mDOMBlob;
|
||||
mDOMBlob = nullptr;
|
||||
|
||||
mLoadTotal = mResponseBlob->GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
status = rv.StealNSResult();
|
||||
}
|
||||
} else {
|
||||
// Smaller files may be written in cache map instead of separate files.
|
||||
// Also, no-store response cannot be written in persistent cache.
|
||||
@ -2126,8 +2125,7 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
||||
// mBlobStorage can be null if the channel is non-file non-cacheable
|
||||
// and if the response length is zero.
|
||||
MaybeCreateBlobStorage();
|
||||
mLoadTotal =
|
||||
mBlobStorage->GetBlobWhenReady(GetOwner(), contentType, this);
|
||||
mBlobStorage->GetBlobWhenReady(GetOwner(), contentType, this);
|
||||
waitingForBlobCreation = true;
|
||||
} else {
|
||||
// mBlobSet can be null if the channel is non-file non-cacheable
|
||||
@ -2148,10 +2146,6 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
||||
}
|
||||
|
||||
mResponseBlob = Blob::Create(GetOwner(), blobImpl);
|
||||
mLoadTotal = mResponseBlob->GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
status = rv.StealNSResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2163,8 +2157,7 @@ XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
||||
mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer)) {
|
||||
// set the capacity down to the actual length, to realloc back
|
||||
// down to the actual size
|
||||
mLoadTotal = mArrayBufferBuilder.length();
|
||||
if (!mArrayBufferBuilder.setCapacity(mLoadTotal)) {
|
||||
if (!mArrayBufferBuilder.setCapacity(mArrayBufferBuilder.length())) {
|
||||
// this should never happen!
|
||||
status = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
@ -2268,12 +2261,6 @@ XMLHttpRequestMainThread::ChangeStateToDone()
|
||||
mTimeoutTimer->Cancel();
|
||||
}
|
||||
|
||||
if (mLoadTransferred) {
|
||||
mLoadTotal = mLoadTransferred;
|
||||
} else {
|
||||
mLoadTotal = -1;
|
||||
}
|
||||
|
||||
// Per spec, fire the last download progress event, if any,
|
||||
// before readystatechange=4/done. (Note that 0-sized responses
|
||||
// will have not sent a progress event yet, so one must be sent here).
|
||||
@ -3412,9 +3399,8 @@ XMLHttpRequestMainThread::OnProgress(nsIRequest *aRequest, nsISupports *aContext
|
||||
StartProgressEventTimer();
|
||||
}
|
||||
} else {
|
||||
mLoadTotal = lengthComputable ? aProgressMax : -1;
|
||||
mLoadTotal = aProgressMax;
|
||||
mLoadTransferred = aProgress;
|
||||
|
||||
// OnDataAvailable() handles mProgressSinceLastProgressEvent
|
||||
// for the download phase.
|
||||
}
|
||||
@ -3631,6 +3617,7 @@ XMLHttpRequestMainThread::HandleProgressTimerCallback()
|
||||
mUploadTransferred, mUploadTotal);
|
||||
}
|
||||
} else {
|
||||
FireReadystatechangeEvent();
|
||||
DispatchProgressEvent(this, ProgressEventType::progress,
|
||||
mLoadTransferred, mLoadTotal);
|
||||
}
|
||||
@ -3809,12 +3796,6 @@ XMLHttpRequestMainThread::BlobStoreCompleted(MutableBlobStorage* aBlobStorage,
|
||||
mResponseBlob = aBlob;
|
||||
mBlobStorage = nullptr;
|
||||
|
||||
ErrorResult rv;
|
||||
mLoadTotal = mResponseBlob->GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
}
|
||||
|
||||
ChangeStateToDone();
|
||||
}
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
[firing-events-http-no-content-length.html]
|
||||
type: testharness
|
||||
[ProgressEvent: firing events for HTTP with no Content-Length]
|
||||
expected: FAIL
|
||||
|
@ -22,53 +22,56 @@
|
||||
}
|
||||
|
||||
function getNextEvent(arr) {
|
||||
var eventStr = arr.shift();
|
||||
var event = { str: arr.shift() };
|
||||
|
||||
// we can only handle strings, numbers (readystates) and undefined
|
||||
if (eventStr === undefined) {
|
||||
if (event.str === undefined) {
|
||||
return event;
|
||||
}
|
||||
if (typeof eventStr !== "string") {
|
||||
if (Number.isInteger(eventStr)) {
|
||||
eventStr = "readystatechange(" + eventStr + ")";
|
||||
|
||||
if (typeof event.str !== "string") {
|
||||
if (Number.isInteger(event.str)) {
|
||||
event.state = event.str;
|
||||
event.str = "readystatechange(" + event.str + ")";
|
||||
} else {
|
||||
throw "Test error: unexpected event type " + eventStr;
|
||||
throw "Test error: unexpected event type " + event.str;
|
||||
}
|
||||
}
|
||||
|
||||
// parse out the general type, loaded and total values
|
||||
var type = eventStr.type = eventStr.split("(")[0].split(".").pop();
|
||||
eventStr.mayFollowOptionalProgressEvents = type == "progress" ||
|
||||
type == "load" || type == "abort" || type == "error";
|
||||
var loadedAndTotal = eventStr.match(/\((\d)+,(\d)+/);
|
||||
var type = event.type = event.str.split("(")[0].split(".").pop();
|
||||
var loadedAndTotal = event.str.match(/.*\((\d+),(\d+),(true|false)\)/);
|
||||
if (loadedAndTotal) {
|
||||
eventStr.loaded = parseInt(loadedAndTotal[0]);
|
||||
eventStr.total = parseInt(loadedAndTotal[1]);
|
||||
event.loaded = parseInt(loadedAndTotal[1]);
|
||||
event.total = parseInt(loadedAndTotal[2]);
|
||||
event.lengthComputable = loadedAndTotal[3] == "true";
|
||||
}
|
||||
|
||||
return eventStr;
|
||||
return event;
|
||||
}
|
||||
|
||||
global.assert_xhr_event_order_matches = function(expected) {
|
||||
var recorded = recorded_xhr_events;
|
||||
var lastRecordedLoaded = -1;
|
||||
|
||||
while(expected.length && recorded.length) {
|
||||
var currentExpected = getNextEvent(expected),
|
||||
currentRecorded = getNextEvent(recorded);
|
||||
|
||||
// skip to the last progress event if we've hit one
|
||||
while (recorded.length && currentRecorded.type == "progress") {
|
||||
assert_greater(currentRecorded.loaded, lastRecordedLoaded,
|
||||
"progress event 'loaded' values must only increase");
|
||||
// skip to the last progress event if we've hit one (note the next
|
||||
// event after a progress event should be a LOADING readystatechange,
|
||||
// if there are multiple progress events in a row).
|
||||
while (recorded.length && currentRecorded.type == "progress" &&
|
||||
parseInt(recorded) === 3) {
|
||||
assert_greater_than(currentRecorded.loaded, lastRecordedLoaded,
|
||||
"progress event 'loaded' values must only increase");
|
||||
lastRecordedLoaded = currentRecorded.loaded;
|
||||
currentRecorded = getNextEvent(recorded);
|
||||
}
|
||||
if (currentRecorded.type == "loadstart") {
|
||||
if (currentRecorded.type == "loadend") {
|
||||
recordedProgressCount = 0;
|
||||
lastRecordedLoaded = -1;
|
||||
}
|
||||
|
||||
assert_equals(currentRecorded, currentExpected);
|
||||
assert_equals(currentRecorded.str, currentExpected.str);
|
||||
}
|
||||
if (recorded.length) {
|
||||
throw "\nUnexpected extra events: " + recorded.join(", ");
|
||||
|
Loading…
Reference in New Issue
Block a user