зеркало из https://github.com/mozilla/gecko-dev.git
Bug 687087 part 3. Implement XHR.responseType="moz-chunked-text" and XHR.responseType="moz-chunked-arraybuffer". r=smaug on code changes, rs=smaug on tests.
This commit is contained in:
Родитель
d51a0e15c7
Коммит
8fae097f9c
|
@ -428,6 +428,7 @@ nsXMLHttpRequest::nsXMLHttpRequest()
|
|||
mProgressEventWasDelayed(PR_FALSE),
|
||||
mLoadLengthComputable(PR_FALSE), mLoadTotal(0),
|
||||
mFirstStartRequestSeen(PR_FALSE),
|
||||
mInLoadProgressEvent(PR_FALSE),
|
||||
mResultJSON(JSVAL_VOID),
|
||||
mResultArrayBuffer(nsnull)
|
||||
{
|
||||
|
@ -723,7 +724,8 @@ nsXMLHttpRequest::DetectCharset()
|
|||
|
||||
if (mResponseType != XML_HTTP_RESPONSE_TYPE_DEFAULT &&
|
||||
mResponseType != XML_HTTP_RESPONSE_TYPE_TEXT &&
|
||||
mResponseType != XML_HTTP_RESPONSE_TYPE_JSON) {
|
||||
mResponseType != XML_HTTP_RESPONSE_TYPE_JSON &&
|
||||
mResponseType != XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -819,10 +821,17 @@ NS_IMETHODIMP nsXMLHttpRequest::GetResponseText(nsAString& aResponseText)
|
|||
aResponseText.Truncate();
|
||||
|
||||
if (mResponseType != XML_HTTP_RESPONSE_TYPE_DEFAULT &&
|
||||
mResponseType != XML_HTTP_RESPONSE_TYPE_TEXT) {
|
||||
mResponseType != XML_HTTP_RESPONSE_TYPE_TEXT &&
|
||||
mResponseType != XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
if (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT &&
|
||||
!mInLoadProgressEvent) {
|
||||
aResponseText.SetIsVoid(PR_TRUE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!(mState & (XML_HTTP_REQUEST_DONE | XML_HTTP_REQUEST_LOADING))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -933,6 +942,12 @@ NS_IMETHODIMP nsXMLHttpRequest::GetResponseType(nsAString& aResponseType)
|
|||
case XML_HTTP_RESPONSE_TYPE_JSON:
|
||||
aResponseType.AssignLiteral("moz-json");
|
||||
break;
|
||||
case XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT:
|
||||
aResponseType.AssignLiteral("moz-chunked-text");
|
||||
break;
|
||||
case XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER:
|
||||
aResponseType.AssignLiteral("moz-chunked-arraybuffer");
|
||||
break;
|
||||
default:
|
||||
NS_ERROR("Should not happen");
|
||||
}
|
||||
|
@ -962,6 +977,16 @@ NS_IMETHODIMP nsXMLHttpRequest::SetResponseType(const nsAString& aResponseType)
|
|||
mResponseType = XML_HTTP_RESPONSE_TYPE_TEXT;
|
||||
} else if (aResponseType.EqualsLiteral("moz-json")) {
|
||||
mResponseType = XML_HTTP_RESPONSE_TYPE_JSON;
|
||||
} else if (aResponseType.EqualsLiteral("moz-chunked-text")) {
|
||||
if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
mResponseType = XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT;
|
||||
} else if (aResponseType.EqualsLiteral("moz-chunked-arraybuffer")) {
|
||||
if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
mResponseType = XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER;
|
||||
}
|
||||
// If the given value is not the empty string, "arraybuffer",
|
||||
// "blob", "document", or "text" terminate these steps.
|
||||
|
@ -989,20 +1014,29 @@ NS_IMETHODIMP nsXMLHttpRequest::GetResponse(JSContext *aCx, jsval *aResult)
|
|||
switch (mResponseType) {
|
||||
case XML_HTTP_RESPONSE_TYPE_DEFAULT:
|
||||
case XML_HTTP_RESPONSE_TYPE_TEXT:
|
||||
case XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT:
|
||||
{
|
||||
nsString str;
|
||||
rv = GetResponseText(str);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsStringBuffer* buf;
|
||||
*aResult = XPCStringConvert::ReadableToJSVal(aCx, str, &buf);
|
||||
if (buf) {
|
||||
str.ForgetSharedBuffer();
|
||||
if (str.IsVoid()) {
|
||||
*aResult = JSVAL_NULL;
|
||||
} else {
|
||||
nsStringBuffer* buf;
|
||||
*aResult = XPCStringConvert::ReadableToJSVal(aCx, str, &buf);
|
||||
if (buf) {
|
||||
str.ForgetSharedBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER:
|
||||
if (mState & XML_HTTP_REQUEST_DONE) {
|
||||
case XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER:
|
||||
if ((mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER &&
|
||||
mState & XML_HTTP_REQUEST_DONE) ||
|
||||
(mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER &&
|
||||
mInLoadProgressEvent)) {
|
||||
if (!mResultArrayBuffer) {
|
||||
rv = CreateResponseArrayBuffer(aCx);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1604,17 +1638,18 @@ nsXMLHttpRequest::StreamReaderFunc(nsIInputStream* in,
|
|||
if ((xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT &&
|
||||
xmlHttpRequest->mResponseXML) ||
|
||||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER ||
|
||||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB) {
|
||||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_BLOB ||
|
||||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER) {
|
||||
// Copy for our own use
|
||||
PRUint32 previousLength = xmlHttpRequest->mResponseBody.Length();
|
||||
xmlHttpRequest->mResponseBody.Append(fromRawSegment,count);
|
||||
if (count > 0 && xmlHttpRequest->mResponseBody.Length() == previousLength) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
else if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT ||
|
||||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_TEXT ||
|
||||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_JSON) {
|
||||
} else if (xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_DEFAULT ||
|
||||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_TEXT ||
|
||||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_JSON ||
|
||||
xmlHttpRequest->mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT) {
|
||||
NS_ASSERTION(!xmlHttpRequest->mResponseXML,
|
||||
"We shouldn't be parsing a doc here");
|
||||
xmlHttpRequest->AppendToResponseText(fromRawSegment, count);
|
||||
|
@ -2991,9 +3026,17 @@ nsXMLHttpRequest::MaybeDispatchProgressEvents(PRBool aFinalProgress)
|
|||
mLoadTotal = mLoadTransferred;
|
||||
mLoadLengthComputable = PR_TRUE;
|
||||
}
|
||||
mInLoadProgressEvent = PR_TRUE;
|
||||
DispatchProgressEvent(this, NS_LITERAL_STRING(PROGRESS_STR),
|
||||
PR_TRUE, mLoadLengthComputable, mLoadTransferred,
|
||||
mLoadTotal, mLoadTransferred, mLoadTotal);
|
||||
mInLoadProgressEvent = PR_FALSE;
|
||||
if (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT ||
|
||||
mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER) {
|
||||
mResponseBody.Truncate();
|
||||
mResponseText.Truncate();
|
||||
mResultArrayBuffer = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
mProgressSinceLastProgressEvent = PR_FALSE;
|
||||
|
|
|
@ -305,7 +305,9 @@ protected:
|
|||
XML_HTTP_RESPONSE_TYPE_BLOB,
|
||||
XML_HTTP_RESPONSE_TYPE_DOCUMENT,
|
||||
XML_HTTP_RESPONSE_TYPE_TEXT,
|
||||
XML_HTTP_RESPONSE_TYPE_JSON
|
||||
XML_HTTP_RESPONSE_TYPE_JSON,
|
||||
XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT,
|
||||
XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER
|
||||
} mResponseType;
|
||||
|
||||
nsCOMPtr<nsIDOMBlob> mResponseBlob;
|
||||
|
@ -350,6 +352,7 @@ protected:
|
|||
nsCOMPtr<nsITimer> mProgressNotifier;
|
||||
|
||||
PRPackedBool mFirstStartRequestSeen;
|
||||
PRPackedBool mInLoadProgressEvent;
|
||||
|
||||
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
|
||||
nsCOMPtr<nsIChannel> mNewRedirectChannel;
|
||||
|
|
|
@ -499,6 +499,8 @@ _TEST_FILES2 = \
|
|||
accesscontrol.resource^headers^ \
|
||||
invalid_accesscontrol.resource \
|
||||
invalid_accesscontrol.resource^headers^ \
|
||||
test_xhr_progressevents.html \
|
||||
progressserver.sjs \
|
||||
somedatas.resource \
|
||||
somedatas.resource^headers^ \
|
||||
delayedServerEvents.sjs \
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
const CC = Components.Constructor;
|
||||
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream",
|
||||
"setInputStream");
|
||||
|
||||
function setReq(req) {
|
||||
setObjectState("content/base/test/progressserver", req);
|
||||
}
|
||||
|
||||
function getReq() {
|
||||
var req;
|
||||
getObjectState("content/base/test/progressserver", function(v) {
|
||||
req = v;
|
||||
});
|
||||
return req;
|
||||
}
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
var pairs = request.queryString.split('&');
|
||||
var command = pairs.shift();
|
||||
|
||||
var bodyStream = new BinaryInputStream(request.bodyInputStream);
|
||||
var body = "";
|
||||
var bodyAvail;
|
||||
while ((bodyAvail = bodyStream.available()) > 0)
|
||||
body += String.fromCharCode.apply(null, bodyStream.readByteArray(bodyAvail));
|
||||
|
||||
if (command == "open") {
|
||||
response.processAsync();
|
||||
setReq(response);
|
||||
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
pairs.forEach(function (val) {
|
||||
var [name, value] = val.split('=');
|
||||
response.setHeader(name, unescape(value), false);
|
||||
});
|
||||
response.write(body);
|
||||
return;
|
||||
}
|
||||
|
||||
if (command == "send") {
|
||||
getReq().write(body);
|
||||
}
|
||||
else if (command == "close") {
|
||||
getReq().finish();
|
||||
setReq(null);
|
||||
}
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.write("ok");
|
||||
}
|
|
@ -14,41 +14,6 @@
|
|||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// test receiving as JSON
|
||||
function testJSON(aJsonStr, invalid) {
|
||||
var errorThrown = false;
|
||||
var anotherErrorThrown = false;
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
var didthrow = false;
|
||||
try { xhr.responseType = 'moz-json'; } catch (e) { didthrow = true; }
|
||||
ok(didthrow,
|
||||
"should have thrown when setting responseType to moz-json before open");
|
||||
|
||||
xhr.open("POST", 'responseIdentical.sjs', false);
|
||||
xhr.responseType = 'moz-json';
|
||||
xhr.send(aJsonStr);
|
||||
|
||||
if (!invalid) {
|
||||
is(JSON.stringify(xhr.response), aJsonStr);
|
||||
is(xhr.response, xhr.response, "returning the same object on each access");
|
||||
}
|
||||
else {
|
||||
var didThrow = false;
|
||||
try { xhr.response } catch(ex) { didThrow = true; }
|
||||
ok(didThrow, "accessing response should throw");
|
||||
|
||||
didThrow = false;
|
||||
try { xhr.response } catch(ex) { didThrow = true; }
|
||||
ok(didThrow, "accessing response should throw");
|
||||
}
|
||||
}
|
||||
|
||||
var jsonStr = '{"title":"aBook","author":"john"}';
|
||||
testJSON(jsonStr, false);
|
||||
var invalidJson = '{ "abc": }'
|
||||
testJSON(invalidJson, true);
|
||||
|
||||
var path = "/tests/content/base/test/";
|
||||
|
||||
var passFiles = [['file_XHR_pass1.xml', 'GET'],
|
||||
|
@ -109,18 +74,25 @@ function checkResponseXMLAccessThrows(xhr) {
|
|||
try { xhr.responseXML } catch (e) { didthrow = true; }
|
||||
ok(didthrow, "should have thrown when accessing responseXML");
|
||||
}
|
||||
function checkSetResponseTypeThrows(xhr) {
|
||||
function checkResponseAccessThrows(xhr) {
|
||||
var didthrow = false;
|
||||
try { xhr.responseType = 'document'; } catch (e) { didthrow = true; }
|
||||
ok(didthrow, "should have thrown when accessing responseType");
|
||||
try { xhr.response } catch (e) { didthrow = true; }
|
||||
ok(didthrow, "should have thrown when accessing response");
|
||||
}
|
||||
function checkSetResponseTypeThrows(xhr, type) {
|
||||
var didthrow = false;
|
||||
try { xhr.responseType = type; } catch (e) { didthrow = true; }
|
||||
ok(didthrow, "should have thrown when setting responseType");
|
||||
}
|
||||
|
||||
xhr = new XMLHttpRequest();
|
||||
checkSetResponseTypeThrows(xhr);
|
||||
checkSetResponseTypeThrows(xhr, "document");
|
||||
xhr.open("GET", 'file_XHR_pass1.xml', false);
|
||||
checkSetResponseTypeThrows(xhr, "moz-chunked-text");
|
||||
checkSetResponseTypeThrows(xhr, "moz-chunked-arraybuffer");
|
||||
xhr.responseType = 'document';
|
||||
xhr.send(null);
|
||||
checkSetResponseTypeThrows(xhr);
|
||||
checkSetResponseTypeThrows(xhr, "document");
|
||||
is(xhr.status, 200, "wrong status");
|
||||
checkResponseTextAccessThrows(xhr);
|
||||
is((new XMLSerializer()).serializeToString(xhr.response.documentElement),
|
||||
|
@ -178,16 +150,30 @@ checkResponseXMLAccessThrows(xhr);
|
|||
ab = xhr.response;
|
||||
ok(ab != null, "should have a non-null arraybuffer");
|
||||
arraybuffer_equals_to(ab, "\xaa\xee\0\x03\xff\xff\xff\xff\xbb\xbb\xbb\xbb");
|
||||
is(xhr.response, xhr.response, "returns the same ArrayBuffer");
|
||||
|
||||
// test array buffer GetResult returns the same object
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", 'file_XHR_binary1.bin', false);
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.send(null)
|
||||
// test response (responseType='moz-json')
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", 'responseIdentical.sjs', false);
|
||||
xhr.responseType = 'moz-json';
|
||||
jsonObjStr = JSON.stringify({title: "aBook", author: "john"});
|
||||
xhr.send(jsonObjStr);
|
||||
is(xhr.status, 200, "wrong status");
|
||||
checkResponseTextAccessThrows(xhr);
|
||||
checkResponseXMLAccessThrows(xhr);
|
||||
is(xhr.response, xhr.response, "returns the same ArrayBuffer");
|
||||
is(JSON.stringify(xhr.response), jsonObjStr, "correct result");
|
||||
is(xhr.response, xhr.response, "returning the same object on each access");
|
||||
|
||||
// with invalid json
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", 'responseIdentical.sjs', false);
|
||||
xhr.responseType = 'moz-json';
|
||||
xhr.send("{");
|
||||
is(xhr.status, 200, "wrong status");
|
||||
checkResponseTextAccessThrows(xhr);
|
||||
checkResponseXMLAccessThrows(xhr);
|
||||
checkResponseAccessThrows(xhr);
|
||||
checkResponseAccessThrows(xhr); // Check twice to ensure that we still throw
|
||||
|
||||
// test response (responseType='blob')
|
||||
var onloadCount = 0;
|
||||
|
|
|
@ -0,0 +1,282 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for XMLHttpRequest Progress Events</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="gen.next();">
|
||||
<pre id=l></pre>
|
||||
<script type="application/javascript;version=1.7">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var gen = runTests();
|
||||
|
||||
function log(s) {
|
||||
//document.getElementById("l").textContent += s + "\n";
|
||||
}
|
||||
|
||||
function getEvent(e) {
|
||||
log("got event: " + e.type + " (" + e.target.readyState + ")");
|
||||
gen.send(e);
|
||||
}
|
||||
|
||||
function startsWith(a, b) {
|
||||
return a.substr(0, b.length) === b;
|
||||
}
|
||||
|
||||
function updateProgress(e, data, testName) {
|
||||
var test = " while running " + testName;
|
||||
is(e.type, "progress", "event type" + test);
|
||||
|
||||
let response;
|
||||
if (data.nodata) {
|
||||
is(e.target.response, null, "response should be null" + test);
|
||||
response = null;
|
||||
}
|
||||
else if (data.text) {
|
||||
is(typeof e.target.response, "string", "response should be a string" + test);
|
||||
response = e.target.response;
|
||||
}
|
||||
else {
|
||||
ok(e.target.response instanceof ArrayBuffer, "response should be a ArrayBuffer" + test);
|
||||
response = bufferToString(e.target.response);
|
||||
}
|
||||
|
||||
if (!data.nodata && !data.encoded) {
|
||||
if (!data.chunked) {
|
||||
is(e.loaded, response.length, "event.loaded matches response size" + test);
|
||||
}
|
||||
else {
|
||||
is(e.loaded - data.receivedBytes, response.length,
|
||||
"event.loaded grew by response size" + test);
|
||||
}
|
||||
}
|
||||
ok(e.loaded > data.receivedBytes, "event.loaded increased" + test);
|
||||
ok(e.loaded - data.receivedBytes <= data.pendingBytes,
|
||||
"event.loaded didn't increase too much" + test);
|
||||
|
||||
if (!data.nodata) {
|
||||
var newData;
|
||||
ok(startsWith(response, data.receivedResult),
|
||||
"response strictly grew" + test);
|
||||
newData = response.substr(data.receivedResult.length);
|
||||
|
||||
if (!data.encoded) {
|
||||
ok(newData.length > 0, "sanity check for progress" + test);
|
||||
}
|
||||
ok(startsWith(data.pendingResult, newData), "new data matches expected" + test);
|
||||
}
|
||||
|
||||
is(e.lengthComputable, "total" in data, "lengthComputable" + test);
|
||||
if ("total" in data) {
|
||||
is(e.total, data.total, "total" + test);
|
||||
}
|
||||
|
||||
if (!data.nodata) {
|
||||
data.pendingResult = data.pendingResult.substr(newData.length);
|
||||
}
|
||||
data.pendingBytes -= e.loaded - data.receivedBytes;
|
||||
data.receivedResult = response;
|
||||
data.receivedBytes = e.loaded;
|
||||
}
|
||||
|
||||
function sendData(s) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "progressserver.sjs?send");
|
||||
xhr.sendAsBinary(s);
|
||||
}
|
||||
|
||||
function closeConn() {
|
||||
log("in closeConn");
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "progressserver.sjs?close");
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
var longString = "long";
|
||||
while(longString.length < 65536)
|
||||
longString += longString;
|
||||
|
||||
function utf8encode(s) {
|
||||
return unescape(encodeURIComponent(s));
|
||||
}
|
||||
|
||||
function bufferToString(buffer) {
|
||||
return String.fromCharCode.apply(String, new Uint8Array(buffer));
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onprogress = xhr.onload = xhr.onerror = xhr.onreadystatechange = xhr.onloadend = getEvent;
|
||||
|
||||
var responseTypes = [{ type: "text", text: true },
|
||||
{ type: "arraybuffer", text: false, nodata: true },
|
||||
{ type: "blob", text: false, nodata: true },
|
||||
{ type: "document", text: true, nodata: true },
|
||||
{ type: "moz-json", text: true, nodata: true },
|
||||
{ type: "", text: true },
|
||||
{ type: "moz-chunked-text", text: true, chunked: true },
|
||||
{ type: "moz-chunked-arraybuffer", text: false, chunked: true },
|
||||
];
|
||||
var responseType;
|
||||
while (responseType = responseTypes.shift()) {
|
||||
let tests = [{ open: "Content-Type=text/plain", name: "simple test" },
|
||||
{ data: "hello world" },
|
||||
{ data: "\u0000\u0001\u0002\u0003" },
|
||||
{ data: longString },
|
||||
{ data: "x" },
|
||||
{ close: true },
|
||||
{ open: "Content-Type=text/plain&Content-Length=20", name: "with length", total: 20 },
|
||||
// 5 bytes from the "ready" in the open step
|
||||
{ data: "abcde" },
|
||||
{ data: "0123456789" },
|
||||
{ close: true },
|
||||
{ open: "Content-Type=application/xml", data: "ready", name: "without length, as xml" },
|
||||
{ data: "<out>" },
|
||||
{ data: "text" },
|
||||
{ data: "</foo>invalid" },
|
||||
{ close: true },
|
||||
{ open: "Content-Type=text/plain;charset%3dutf-8", name: "utf8 data", encoded: true },
|
||||
{ data: utf8encode("räksmörgås"), utf16: "räksmörgås" },
|
||||
{ data: utf8encode("Å").substr(0,1), utf16: "" },
|
||||
{ data: utf8encode("Å").substr(1), utf16: "Å" },
|
||||
{ data: utf8encode("aöb").substr(0,2), utf16: "a" },
|
||||
{ data: utf8encode("aöb").substr(2), utf16: "öb" },
|
||||
{ data: utf8encode("a\u867Eb").substr(0,3), utf16: "a" },
|
||||
{ data: utf8encode("a\u867Eb").substr(3,1), utf16: "\u867E" },
|
||||
{ data: utf8encode("a\u867Eb").substr(4), utf16: "b" },
|
||||
{ close: true },
|
||||
];
|
||||
let testState = { index: 0 };
|
||||
|
||||
for (let i = 0; i < tests.length; ++i) {
|
||||
let test = tests[i];
|
||||
testState.index++;
|
||||
if ("open" in test) {
|
||||
log("opening " + testState.name);
|
||||
testState = { name: test.name + " for " + responseType.type,
|
||||
index: 0,
|
||||
pendingResult: "ready",
|
||||
pendingBytes: 5,
|
||||
receivedResult: "",
|
||||
receivedBytes: 0,
|
||||
total: test.total,
|
||||
encoded: test.encoded,
|
||||
nodata: responseType.nodata,
|
||||
chunked: responseType.chunked,
|
||||
text: responseType.text };
|
||||
|
||||
xhr.onreadystatechange = null;
|
||||
xhr.open("POST", "progressserver.sjs?open&" + test.open);
|
||||
xhr.responseType = responseType.type;
|
||||
xhr.send("ready");
|
||||
xhr.onreadystatechange = getEvent;
|
||||
|
||||
let e = yield;
|
||||
is(e.type, "readystatechange", "should readystate to headers-received starting " + testState.name);
|
||||
is(xhr.readyState, xhr.HEADERS_RECEIVED, "should be in state HEADERS_RECEIVED starting " + testState.name);
|
||||
|
||||
e = yield;
|
||||
is(e.type, "readystatechange", "should readystate to loading starting " + testState.name);
|
||||
is(xhr.readyState, xhr.LOADING, "should be in state LOADING starting " + testState.name);
|
||||
if (typeof testState.total == "undefined")
|
||||
delete testState.total;
|
||||
}
|
||||
else if ("close" in test) {
|
||||
log("closing");
|
||||
closeConn();
|
||||
|
||||
e = yield;
|
||||
is(e.type, "readystatechange", "should readystate to done closing " + testState.name);
|
||||
is(xhr.readyState, xhr.DONE, "should be in state DONE closing " + testState.name);
|
||||
log("readystate to 4");
|
||||
|
||||
if (responseType.chunked) {
|
||||
xhr.responseType;
|
||||
is(xhr.response, null, "chunked data has null response for " + testState.name);
|
||||
}
|
||||
|
||||
e = yield;
|
||||
is(e.type, "load", "should fire load closing " + testState.name);
|
||||
is(e.lengthComputable, true, "length should be computable during load closing " + testState.name);
|
||||
log("got load");
|
||||
|
||||
if (responseType.chunked) {
|
||||
is(xhr.response, null, "chunked data has null response for " + testState.name);
|
||||
}
|
||||
|
||||
e = yield;
|
||||
is(e.type, "loadend", "should fire loadend closing " + testState.name);
|
||||
is(e.lengthComputable, true, "length should be computable during loadend closing " + testState.name);
|
||||
log("got loadend");
|
||||
|
||||
if (responseType.chunked) {
|
||||
is(xhr.response, null, "chunked data has null response for " + testState.name);
|
||||
}
|
||||
|
||||
if (!testState.nodata || responseType.chunked) {
|
||||
// This branch intentionally left blank
|
||||
// Under these conditions we check the response during updateProgress
|
||||
}
|
||||
else if (responseType.type === "arraybuffer") {
|
||||
is(bufferToString(xhr.response), testState.pendingResult,
|
||||
"full response for " + testState.name);
|
||||
}
|
||||
else if (responseType.type === "blob") {
|
||||
let reader = new FileReader;
|
||||
reader.readAsBinaryString(xhr.response);
|
||||
reader.onloadend = getEvent;
|
||||
yield;
|
||||
|
||||
is(reader.result, testState.pendingResult,
|
||||
"full response in blob for " + testState.name);
|
||||
}
|
||||
|
||||
testState.name = "";
|
||||
}
|
||||
else {
|
||||
log("sending");
|
||||
if (responseType.text) {
|
||||
testState.pendingResult += "utf16" in test ? test.utf16 : test.data;
|
||||
}
|
||||
else {
|
||||
testState.pendingResult += test.data;
|
||||
}
|
||||
testState.pendingBytes = test.data.length;
|
||||
sendData(test.data);
|
||||
}
|
||||
|
||||
while(testState.pendingBytes) {
|
||||
log("waiting for more bytes: " + testState.pendingBytes);
|
||||
e = yield;
|
||||
// Readystate can fire several times between each progress event.
|
||||
if (e.type === "readystatechange")
|
||||
continue;
|
||||
|
||||
updateProgress(e, testState, "data for " + testState.name + "[" + testState.index + "]");
|
||||
if (responseType.chunked) {
|
||||
testState.receivedResult = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (!testState.nodata) {
|
||||
is(testState.pendingResult, "",
|
||||
"should have consumed the expected result");
|
||||
}
|
||||
|
||||
log("done with this test");
|
||||
}
|
||||
|
||||
is(testState.name, "", "forgot to close last test");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
yield;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче