Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- Manifest: dom/base/test/chrome/chrome.toml
<!DOCTYPE HTML>
<html>
<!--
-->
<head>
  <title>XMLHttpRequest send and channel implemented in JS</title>
  <script type="application/javascript"  src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
</head>
<body>
<a target="_blank"
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
/*
 * Register a custom nsIProtocolHandler service
 * in order to be able to implement *and use* an
 * nsIChannel component written in Javascript.
 */
const { ComponentUtils } = ChromeUtils.importESModule(
  "resource://gre/modules/ComponentUtils.sys.mjs"
);
var contentSecManager = Cc["@mozilla.org/contentsecuritymanager;1"]
                          .getService(Ci.nsIContentSecurityManager);
var PROTOCOL_SCHEME = "jsproto";
function CustomChannel(uri, loadInfo) {
  this.URI = this.originalURI = uri;
  this.loadInfo = loadInfo;
}
CustomChannel.prototype = {
  URI: null,
  originalURI: null,
  loadInfo: null,
  contentCharset: "utf-8",
  contentLength: 0,
  contentType: "text/plain",
  owner: Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal),
  securityInfo: null,
  notificationCallbacks: null,
  loadFlags: 0,
  loadGroup: null,
  name: null,
  status: Cr.NS_OK,
  asyncOpen(listener) {
    // throws an error if security checks fail
    var outListener = contentSecManager.performSecurityCheck(this, listener);
    let stream = this.open();
    try {
      outListener.onStartRequest(this);
    } catch (e) {}
    try {
      outListener.onDataAvailable(this, stream, 0, stream.available());
    } catch (e) {}
    try {
      outListener.onStopRequest(this, Cr.NS_OK);
    } catch (e) {}
  },
  open() {
    // throws an error if security checks fail
    contentSecManager.performSecurityCheck(this, null);
    let data = "bar";
    let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
    stream.setByteStringData(data);
    return stream;
  },
  isPending() {
    return false;
  },
  cancel() {
    throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
  },
  suspend() {
    throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
  },
  resume() {
    throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
  },
  QueryInterface: ChromeUtils.generateQI(["nsIChannel", "nsIRequest"]),
};
function CustomProtocol() {}
CustomProtocol.prototype = {
  get scheme() {
    return PROTOCOL_SCHEME;
  },
  allowPort: function allowPort() {
    return false;
  },
  newChannel: function newChannel(URI, loadInfo) {
    return new CustomChannel(URI, loadInfo);
  },
  QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference", "nsIProtocolHandler"]),
};
var gFactory = {
  register() {
    Services.io.registerProtocolHandler(
      PROTOCOL_SCHEME,
      new CustomProtocol(),
      Ci.nsIProtocolHandler.URI_NORELATIVE |
        Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE |
        Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD,
      -1
    );
    this.unregister = function() {
      Services.io.unregisterProtocolHandler(PROTOCOL_SCHEME);
      delete this.unregister;
    };
  },
};
// Register the custom procotol handler
gFactory.register();
// Then, checks if XHR works with it
var xhr = new XMLHttpRequest();
xhr.open("GET", PROTOCOL_SCHEME + ":foo", true);
xhr.onload = function() {
  is(xhr.responseText, "bar", "protocol doesn't work");
  gFactory.unregister();
  SimpleTest.finish();
};
try {
  xhr.send(null);
} catch (e) {
  ok(false, e);
}
</script>
</pre>
</body>
</html>