390126 unescape the URL before compressing whitespace r+sr=bz

This commit is contained in:
cbiesinger@gmx.at 2007-08-10 12:52:50 -07:00
parent a11ff4a96f
commit b5a1f780d7
2 changed files with 139 additions and 25 deletions

View File

@ -114,20 +114,13 @@ nsDataChannel::OpenContentStream(PRBool async, nsIInputStream **result)
contentType.StripWhitespace();
contentCharset.StripWhitespace();
char *dataBuffer = nsnull;
PRBool cleanup = PR_FALSE;
if (!lBase64 && ((strncmp(contentType.get(),"text/",5) == 0) ||
contentType.Find("xml") != kNotFound)) {
// it's text, don't compress spaces
dataBuffer = comma+1;
} else {
nsCAutoString dataBuffer(comma + 1);
NS_UnescapeURL(dataBuffer);
if (lBase64 || ((strncmp(contentType.get(),"text/",5) != 0) &&
contentType.Find("xml") == kNotFound)) {
// it's ascii encoded binary, don't let any spaces in
nsCAutoString dataBuf(comma+1);
dataBuf.StripWhitespace();
dataBuffer = ToNewCString(dataBuf);
if (!dataBuffer)
return NS_ERROR_OUT_OF_MEMORY;
cleanup = PR_TRUE;
dataBuffer.StripWhitespace();
}
nsCOMPtr<nsIInputStream> bufInStream;
@ -139,12 +132,12 @@ nsDataChannel::OpenContentStream(PRBool async, nsIInputStream **result)
NET_DEFAULT_SEGMENT_SIZE, PR_UINT32_MAX,
async, PR_TRUE);
if (NS_FAILED(rv))
goto cleanup;
return rv;
PRUint32 dataLen, contentLen;
dataLen = nsUnescapeCount(dataBuffer);
PRUint32 contentLen;
if (lBase64) {
*base64 = ';';
const PRUint32 dataLen = dataBuffer.Length();
PRInt32 resultLen = 0;
if (dataLen >= 1 && dataBuffer[dataLen-1] == '=') {
if (dataLen >= 2 && dataBuffer[dataLen-2] == '=')
@ -159,20 +152,19 @@ nsDataChannel::OpenContentStream(PRBool async, nsIInputStream **result)
// XXX PL_Base64Decode will return a null pointer for decoding
// errors. Since those are more likely than out-of-memory,
// should we return NS_ERROR_MALFORMED_URI instead?
char * decodedData = PL_Base64Decode(dataBuffer, dataLen, nsnull);
char * decodedData = PL_Base64Decode(dataBuffer.get(), dataLen, nsnull);
if (!decodedData) {
rv = NS_ERROR_OUT_OF_MEMORY;
goto cleanup;
return NS_ERROR_OUT_OF_MEMORY;
}
rv = bufOutStream->Write(decodedData, resultLen, &contentLen);
PR_Free(decodedData);
} else {
rv = bufOutStream->Write(dataBuffer, dataLen, &contentLen);
rv = bufOutStream->Write(dataBuffer.get(), dataBuffer.Length(), &contentLen);
}
if (NS_FAILED(rv))
goto cleanup;
return rv;
*comma = ',';
@ -182,8 +174,5 @@ nsDataChannel::OpenContentStream(PRBool async, nsIInputStream **result)
NS_ADDREF(*result = bufInStream);
cleanup:
if (cleanup)
nsMemory::Free(dataBuffer);
return rv;
return NS_OK;
}

View File

@ -0,0 +1,125 @@
/* run some tests on the data: protocol handler */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
var urls = [
["data:,foo", "foo"],
["data:text/plain,foo%00 bar", "foo\x00 bar"],
["data:text/plain;base64,Zm9 vI%20GJ%0Dhc%0Ag==", "foo bar"]
];
function run_next_test() {
test_array[test_index++]();
}
/* read count bytes from stream and return as a String object */
function read_stream(stream, count) {
/* assume stream has non-ASCII data */
var wrapper =
Cc["@mozilla.org/binaryinputstream;1"].
createInstance(Ci.nsIBinaryInputStream);
wrapper.setInputStream(stream);
/* JS methods can be called with a maximum of 65535 arguments, and input
streams don't have to return all the data they make .available() when
asked to .read() that number of bytes. */
var data = [];
while (count > 0) {
var bytes = wrapper.readByteArray(Math.min(65535, count));
data.push(String.fromCharCode.apply(null, bytes));
count -= bytes.length;
if (bytes.length == 0)
do_throw("Nothing read from input stream!");
}
return data.join('');
}
/* stream listener */
function Listener(closure, ctx) {
this._closure = closure;
this._closurectx = ctx;
}
Listener.prototype = {
_closure: null,
_closurectx: null,
_buffer: "",
_got_onstartrequest: false,
_got_onstoprequest: false,
_contentLen: -1,
QueryInterface: function(iid) {
if (iid.Equals(Ci.nsIStreamListener) ||
iid.Equals(Ci.nsIRequestObserver) ||
iid.Equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
onStartRequest: function(request, context) {
if (this._got_onstartrequest)
do_throw("Got second onStartRequest event!");
this._got_onstartrequest = true;
request.QueryInterface(Ci.nsIChannel);
this._contentLen = request.contentLength;
if (this._contentLen == -1)
do_throw("Content length is unknown in onStartRequest!");
},
onDataAvailable: function(request, context, stream, offset, count) {
if (!this._got_onstartrequest)
do_throw("onDataAvailable without onStartRequest event!");
if (this._got_onstoprequest)
do_throw("onDataAvailable after onStopRequest event!");
if (!request.isPending())
do_throw("request reports itself as not pending from onStartRequest!");
this._buffer = this._buffer.concat(read_stream(stream, count));
},
onStopRequest: function(request, context, status) {
if (!this._got_onstartrequest)
do_throw("onStopRequest without onStartRequest event!");
if (this._got_onstoprequest)
do_throw("Got second onStopRequest event!");
this._got_onstoprequest = true;
if (!Components.isSuccessCode(status))
do_throw("Failed to load URL: " + status.toString(16));
if (status != request.status)
do_throw("request.status does not match status arg to onStopRequest!");
if (request.isPending())
do_throw("request reports itself as pending from onStopRequest!");
if (this._contentLen != -1 && this._buffer.length != this._contentLen)
do_throw("did not read nsIChannel.contentLength number of bytes!");
this._closure(this._buffer, this._closurectx);
}
};
function run_test() {
dump("*** run_test\n");
function on_read_complete(data, idx) {
dump("*** run_test.on_read_complete\n");
if (chan.contentType != "text/plain")
do_throw("Type mismatch! Is <" + chan.contentType + ">, should be text/plain")
/* read completed successfully. now compare the data. */
if (data != urls[idx][1])
do_throw("Stream contents do not match with direct read!");
do_test_finished();
}
var ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
for (var i = 0; i < urls.length; ++i) {
dump("*** opening channel " + i + "\n");
do_test_pending();
var chan = ios.newChannel(urls[i][0], "", null);
chan.contentType = "foo/bar"; // should be ignored
chan.asyncOpen(new Listener(on_read_complete, i), null);
}
}