diff options
Diffstat (limited to 'netwerk/test/browser/browser_nsIFormPOSTActionChannel.js')
-rw-r--r-- | netwerk/test/browser/browser_nsIFormPOSTActionChannel.js | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/netwerk/test/browser/browser_nsIFormPOSTActionChannel.js b/netwerk/test/browser/browser_nsIFormPOSTActionChannel.js new file mode 100644 index 0000000000..07387f8c09 --- /dev/null +++ b/netwerk/test/browser/browser_nsIFormPOSTActionChannel.js @@ -0,0 +1,292 @@ +/* + * Tests for bug 1241377: A channel with nsIFormPOSTActionChannel interface + * should be able to accept form POST. + */ + +/* eslint-env mozilla/frame-script */ + +"use strict"; + +const SCHEME = "x-bug1241377"; + +const FORM_BASE = SCHEME + "://dummy/form/"; +const NORMAL_FORM_URI = FORM_BASE + "normal.html"; +const UPLOAD_FORM_URI = FORM_BASE + "upload.html"; +const POST_FORM_URI = FORM_BASE + "post.html"; + +const ACTION_BASE = SCHEME + "://dummy/action/"; +const NORMAL_ACTION_URI = ACTION_BASE + "normal.html"; +const UPLOAD_ACTION_URI = ACTION_BASE + "upload.html"; +const POST_ACTION_URI = ACTION_BASE + "post.html"; + +function CustomProtocolHandler() {} +CustomProtocolHandler.prototype = { + /** nsIProtocolHandler */ + get scheme() { + return SCHEME; + }, + get defaultPort() { + return -1; + }, + get protocolFlags() { + return ( + Ci.nsIProtocolHandler.URI_NORELATIVE | + Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE + ); + }, + newChannel(aURI, aLoadInfo) { + return new CustomChannel(aURI, aLoadInfo); + }, + allowPort(port, scheme) { + return port != -1; + }, + + /** nsIFactory */ + createInstance(aOuter, aIID) { + if (aOuter) { + throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION); + } + return this.QueryInterface(aIID); + }, + lockFactory() {}, + + /** nsISupports */ + QueryInterface: ChromeUtils.generateQI(["nsIProtocolHandler", "nsIFactory"]), + classID: Components.ID("{16d594bc-d9d8-47ae-a139-ea714dc0c35c}"), +}; + +function CustomChannel(aURI, aLoadInfo) { + this.uri = aURI; + this.loadInfo = aLoadInfo; + + this._uploadStream = null; + + var interfaces = [Ci.nsIRequest, Ci.nsIChannel]; + if (this.uri.spec == POST_ACTION_URI) { + interfaces.push(Ci.nsIFormPOSTActionChannel); + } else if (this.uri.spec == UPLOAD_ACTION_URI) { + interfaces.push(Ci.nsIUploadChannel); + } + this.QueryInterface = ChromeUtils.generateQI(interfaces); +} +CustomChannel.prototype = { + /** nsIUploadChannel */ + get uploadStream() { + return this._uploadStream; + }, + set uploadStream(val) { + throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED); + }, + setUploadStream(aStream, aContentType, aContentLength) { + this._uploadStream = aStream; + }, + + /** nsIChannel */ + get originalURI() { + return this.uri; + }, + get URI() { + return this.uri; + }, + owner: null, + notificationCallbacks: null, + get securityInfo() { + return null; + }, + get contentType() { + return "text/html"; + }, + set contentType(val) {}, + contentCharset: "UTF-8", + get contentLength() { + return -1; + }, + set contentLength(val) { + throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED); + }, + open() { + throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED); + }, + asyncOpen(aListener) { + var data = ` +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>test bug 1241377</title> +</head> +<body> +`; + + if (this.uri.spec.startsWith(FORM_BASE)) { + data += ` +<form id="form" action="${this.uri.spec.replace(FORM_BASE, ACTION_BASE)}" + method="post" enctype="text/plain" target="frame"> +<input type="hidden" name="foo" value="bar"> +<input type="submit"> +</form> + +<iframe id="frame" name="frame" width="200" height="200"></iframe> + +<script type="text/javascript"> +<!-- +document.getElementById('form').submit(); +//--> +</script> +`; + } else if (this.uri.spec.startsWith(ACTION_BASE)) { + var postData = ""; + var headers = {}; + if (this._uploadStream) { + var bstream = Cc["@mozilla.org/binaryinputstream;1"].createInstance( + Ci.nsIBinaryInputStream + ); + bstream.setInputStream(this._uploadStream); + postData = bstream.readBytes(bstream.available()); + + if (this._uploadStream instanceof Ci.nsIMIMEInputStream) { + this._uploadStream.visitHeaders((name, value) => { + headers[name] = value; + }); + } + } + data += ` +<input id="upload_stream" value="${this._uploadStream ? "yes" : "no"}"> +<input id="post_data" value="${btoa(postData)}"> +<input id="upload_headers" value='${JSON.stringify(headers)}'> +`; + } + + data += ` +</body> +</html> +`; + + var stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance( + Ci.nsIStringInputStream + ); + stream.setData(data, data.length); + + var runnable = { + run: () => { + try { + aListener.onStartRequest(this, null); + } catch (e) {} + try { + aListener.onDataAvailable(this, stream, 0, stream.available()); + } catch (e) {} + try { + aListener.onStopRequest(this, null, Cr.NS_OK); + } catch (e) {} + }, + }; + Services.tm.dispatchToMainThread(runnable); + }, + + /** nsIRequest */ + get name() { + return this.uri.spec; + }, + isPending() { + return false; + }, + get status() { + return Cr.NS_OK; + }, + cancel(status) {}, + loadGroup: null, + loadFlags: + Ci.nsIRequest.LOAD_NORMAL | + Ci.nsIRequest.INHIBIT_CACHING | + Ci.nsIRequest.LOAD_BYPASS_CACHE, +}; + +function frameScript() { + addMessageListener("Test:WaitForIFrame", function() { + var check = function() { + if (content) { + var frame = content.document.getElementById("frame"); + if (frame) { + var upload_stream = frame.contentDocument.getElementById( + "upload_stream" + ); + var post_data = frame.contentDocument.getElementById("post_data"); + var headers = frame.contentDocument.getElementById("upload_headers"); + if (upload_stream && post_data && headers) { + sendAsyncMessage("Test:IFrameLoaded", [ + upload_stream.value, + post_data.value, + headers.value, + ]); + return; + } + } + } + + setTimeout(check, 100); + }; + + check(); + }); +} + +function loadTestTab(uri) { + gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, uri); + var browser = gBrowser.selectedBrowser; + + let manager = browser.messageManager; + browser.messageManager.loadFrameScript( + "data:,(" + frameScript.toString() + ")();", + true + ); + + return new Promise(resolve => { + function listener({ data: [hasUploadStream, postData, headers] }) { + manager.removeMessageListener("Test:IFrameLoaded", listener); + resolve([hasUploadStream, atob(postData), JSON.parse(headers)]); + } + + manager.addMessageListener("Test:IFrameLoaded", listener); + manager.sendAsyncMessage("Test:WaitForIFrame"); + }); +} + +add_task(async function() { + var handler = new CustomProtocolHandler(); + var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); + registrar.registerFactory( + handler.classID, + "", + "@mozilla.org/network/protocol;1?name=" + handler.scheme, + handler + ); + registerCleanupFunction(function() { + registrar.unregisterFactory(handler.classID, handler); + }); +}); + +add_task(async function() { + var [hasUploadStream] = await loadTestTab(NORMAL_FORM_URI); + is(hasUploadStream, "no", "normal action should not have uploadStream"); + + gBrowser.removeCurrentTab(); +}); + +add_task(async function() { + var [hasUploadStream] = await loadTestTab(UPLOAD_FORM_URI); + is(hasUploadStream, "no", "upload action should not have uploadStream"); + + gBrowser.removeCurrentTab(); +}); + +add_task(async function() { + var [hasUploadStream, postData, headers] = await loadTestTab(POST_FORM_URI); + + is(hasUploadStream, "yes", "post action should have uploadStream"); + is(postData, "foo=bar\r\n", "POST data is received correctly"); + + is(headers["Content-Type"], "text/plain", "Content-Type header is correct"); + is(headers["Content-Length"], undefined, "Content-Length header is correct"); + + gBrowser.removeCurrentTab(); +}); |