Bug 614352 - Change nsXMLHttpRequest to show a correct progress in case of gzip data. r=bz

Now it shows correct amount of data transferred and not the amount of decompressed data.
This commit is contained in:
Dragana Damjanovic 2014-07-24 01:47:00 -04:00
parent 6eb1ed7b80
commit cbc7d0ba88
5 changed files with 112 additions and 4 deletions

View File

@ -433,6 +433,7 @@ nsXMLHttpRequest::ResetResponse()
mResultArrayBuffer = nullptr;
mArrayBufferBuilder.reset();
mResultJSON = JSVAL_VOID;
mDataAvailable = 0;
mLoadTransferred = 0;
mResponseBodyDecodedPos = 0;
}
@ -781,11 +782,14 @@ void
nsXMLHttpRequest::CreatePartialBlob()
{
if (mDOMFile) {
// 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) {
mResponseBlob = mDOMFile;
} else {
mResponseBlob =
mDOMFile->CreateSlice(0, mLoadTransferred, EmptyString());
mDOMFile->CreateSlice(0, mDataAvailable, EmptyString());
}
return;
}
@ -1909,12 +1913,12 @@ nsXMLHttpRequest::OnDataAvailable(nsIRequest *request,
if (cancelable) {
// We don't have to read from the local file for the blob response
mDOMFile->GetSize(&mLoadTransferred);
mDOMFile->GetSize(&mDataAvailable);
ChangeState(XML_HTTP_REQUEST_LOADING);
return request->Cancel(NS_OK);
}
mLoadTransferred += totalRead;
mDataAvailable += totalRead;
ChangeState(XML_HTTP_REQUEST_LOADING);
@ -3599,7 +3603,7 @@ nsXMLHttpRequest::OnProgress(nsIRequest *aRequest, nsISupports *aContext, uint64
} else {
mLoadLengthComputable = lengthComputable;
mLoadTotal = lengthComputable ? aProgressMax : 0;
mLoadTransferred = aProgress;
// Don't dispatch progress events here. OnDataAvailable will take care
// of that.
}

View File

@ -724,6 +724,16 @@ protected:
bool mWarnAboutSyncHtml;
bool mLoadLengthComputable;
uint64_t mLoadTotal; // 0 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.
uint64_t mLoadTransferred;
nsCOMPtr<nsITimer> mProgressNotifier;
void HandleProgressTimerCallback();

View File

@ -220,6 +220,7 @@ support-files =
script-1_bug597345.sjs
script-2_bug597345.js
script_bug602838.sjs
send_gzip_content.sjs
somedatas.resource
somedatas.resource^headers^
variable_style_sheet.sjs
@ -607,6 +608,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1
[test_plugin_freezing.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #CLICK_TO_PLAY
[test_processing_instruction_update_stylesheet.xhtml]
[test_progress_events_for_gzip_data.html]
[test_range_bounds.html]
skip-if = toolkit == 'android' || e10s
[test_reentrant_flush.html]

View File

@ -0,0 +1,48 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
function gzipCompressString(string, obs) {
let scs = Cc["@mozilla.org/streamConverters;1"]
.getService(Ci.nsIStreamConverterService);
let listener = Cc["@mozilla.org/network/stream-loader;1"]
.createInstance(Ci.nsIStreamLoader);
listener.init(obs);
let converter = scs.asyncConvertData("uncompressed", "gzip",
listener, null);
let stringStream = Cc["@mozilla.org/io/string-input-stream;1"]
.createInstance(Ci.nsIStringInputStream);
stringStream.data = string;
converter.onStartRequest(null, null);
converter.onDataAvailable(null, null, stringStream, 0, string.length);
converter.onStopRequest(null, null, null);
}
function produceData() {
var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+";
var result = '';
for (var i = 0; i < 100000; ++i) {
result += chars;
}
return result;
}
function handleRequest(request, response)
{
response.processAsync();
// Generate data
var strings_to_send = produceData();
response.setHeader("Content-Type", "text/plain", false);
response.setHeader("Content-Encoding", "gzip", false);
let observer = {
onStreamComplete: function(loader, context, status, length, result) {
buffer = String.fromCharCode.apply(this, result);
response.setHeader("Content-Length", ""+buffer.length, false);
response.write(buffer);
response.finish();
}
};
gzipCompressString(strings_to_send, observer);
}

View File

@ -0,0 +1,44 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test progess events in case of gzipped data.</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="onLoadData()">
<script class="testbody" type="text/javascript">"use strict";
SimpleTest.waitForExplicitFinish();
var url = "send_gzip_content.sjs";
var loaded = 0;
var total = 0;
function onProgress(e) {
if(e.lengthComputable) {
loaded = e.loaded;
total = e.total;
if (loaded > total) {
ok(false, "We have loaded more bytes (" + loaded +
") than the total amount of bytes (" + total +
") available!!!");
}
}
}
function onLoadData() {
var xhr = new XMLHttpRequest();
xhr.addEventListener('progress', onProgress, false);
xhr.open('GET', url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
is(loaded, total, "loaded should be equal to total");
isnot(loaded, 0, "loaded should be bigger than 0");
SimpleTest.finish();
}
}
xhr.send(null);
}
</script>
</body>
</html>