From 34d95111bf00f758497a209d2e54586ecb632ba9 Mon Sep 17 00:00:00 2001 From: "cbiesinger%gmx.at" Date: Fri, 10 Aug 2007 19:52:51 +0000 Subject: [PATCH] 390126 unescape the URL before compressing whitespace r+sr=bz git-svn-id: svn://10.0.0.236/trunk@231844 18797224-902f-48f8-a5cc-f745e15eee43 --- .../protocol/data/src/nsDataChannel.cpp | 39 ++---- .../netwerk/test/unit/test_data_protocol.js | 125 ++++++++++++++++++ 2 files changed, 139 insertions(+), 25 deletions(-) create mode 100644 mozilla/netwerk/test/unit/test_data_protocol.js diff --git a/mozilla/netwerk/protocol/data/src/nsDataChannel.cpp b/mozilla/netwerk/protocol/data/src/nsDataChannel.cpp index 37fd69b676a..b7e3e1ab543 100644 --- a/mozilla/netwerk/protocol/data/src/nsDataChannel.cpp +++ b/mozilla/netwerk/protocol/data/src/nsDataChannel.cpp @@ -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 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; } diff --git a/mozilla/netwerk/test/unit/test_data_protocol.js b/mozilla/netwerk/test/unit/test_data_protocol.js new file mode 100644 index 00000000000..7481a087554 --- /dev/null +++ b/mozilla/netwerk/test/unit/test_data_protocol.js @@ -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); + } +} +