summaryrefslogtreecommitdiffstats
path: root/netwerk/test/browser/browser_nsIFormPOSTActionChannel.js
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/test/browser/browser_nsIFormPOSTActionChannel.js')
-rw-r--r--netwerk/test/browser/browser_nsIFormPOSTActionChannel.js292
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();
+});