Bug 1095798 - Add NetUtil.NewChannel2 and NetUtil.asyncFetch2 to NetUtil.jsm (r=sicking)
authorChristoph Kerschbaumer <mozilla@christophkerschbaumer.com>
Mon, 15 Dec 2014 18:38:03 -0800
changeset 219788 b921743d876e978baa61b509bb52ce8b504d7d1e
parent 219787 adc247a722ef1f44b3f6d07eb86bfdc56d9210a7
child 219789 da727b086b56522e59ad2e54ef1852e1d287a313
push id52926
push usermozilla@christophkerschbaumer.com
push dateTue, 16 Dec 2014 02:53:23 +0000
treeherdermozilla-inbound@da727b086b56 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs1095798
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1095798 - Add NetUtil.NewChannel2 and NetUtil.asyncFetch2 to NetUtil.jsm (r=sicking)
netwerk/base/src/NetUtil.jsm
--- a/netwerk/base/src/NetUtil.jsm
+++ b/netwerk/base/src/NetUtil.jsm
@@ -149,16 +149,130 @@ this.NetUtil = {
                 aSource,
                 e
             );
             throw exception;
         }
     },
 
     /**
+     * Asynchronously opens a source and fetches the response.  A source can be
+     * an nsIURI, nsIFile, string spec, nsIChannel, or nsIInputStream.  The
+     * provided callback will get an input stream containing the response, the
+     * result code, and a reference to the request.
+     *
+     * Please note, if aSource is an instance of an nsIChannel, then
+     * aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal, aSecurityFlags,
+     * aContentPolicyType must be "undefined".
+     *
+     * @param aSource
+     *        The nsIURI, nsIFile, string spec, nsIChannel, or nsIInputStream
+     *        to open.
+     * @param aCallback
+     *        The callback function that will be notified upon completion.  It
+     *        will get two arguments:
+     *        1) An nsIInputStream containing the data from aSource, if any.
+     *        2) The status code from opening the source.
+     *        3) Reference to the nsIRequest.
+     * @param aLoadingNode, aLoadingPrincipal, aTriggeringPrincipal
+     *        aSecurityFlags, aContentPolicyType
+     *        See param description in NetUtil_newChannel2.
+     *
+     * Note: As an interim we have asyncFetch as well as asyncFetch2.
+     *       Once Bug 1087720 (which converts all js callers to use
+     *       asyncFetch2) lands, we can remove asyncFetch completely.
+     */
+    asyncFetch2: function NetUtil_asyncFetch2(aSource,
+                                              aCallback,
+                                              aLoadingNode,
+                                              aLoadingPrincipal,
+                                              aTriggeringPrincipal,
+                                              aSecurityFlags,
+                                              aContentPolicyType)
+    {
+        if (!aSource || !aCallback) {
+            let exception = new Components.Exception(
+                "Must have a source and a callback",
+                Cr.NS_ERROR_INVALID_ARG,
+                Components.stack.caller
+            );
+            throw exception;
+        }
+
+        // if aSource is an instance of an nsIChannel, all the individual
+        // args to create a loadInfo must be "undefined".
+        if (aSource instanceof Ci.nsIChannel) {
+          if ((typeof aLoadingNode != "undefined") ||
+              (typeof aLoadingPrincipal != "undefined") ||
+              (typeof aTriggeringPrincipal != "undefined") ||
+              (typeof aSecurityFlags != "undefined") ||
+              (typeof aContentPolicyType != "undefined")) {
+
+            let exception = new Components.Exception(
+                "LoadInfo arguments must be undefined",
+                Cr.NS_ERROR_INVALID_ARG,
+                Components.stack.caller
+            );
+            throw exception;
+          }
+        }
+
+        // Create a pipe that will create our output stream that we can use once
+        // we have gotten all the data.
+        let pipe = Cc["@mozilla.org/pipe;1"].
+                   createInstance(Ci.nsIPipe);
+        pipe.init(true, true, 0, PR_UINT32_MAX, null);
+
+        // Create a listener that will give data to the pipe's output stream.
+        let listener = Cc["@mozilla.org/network/simple-stream-listener;1"].
+                       createInstance(Ci.nsISimpleStreamListener);
+        listener.init(pipe.outputStream, {
+            onStartRequest: function(aRequest, aContext) {},
+            onStopRequest: function(aRequest, aContext, aStatusCode) {
+                pipe.outputStream.close();
+                aCallback(pipe.inputStream, aStatusCode, aRequest);
+            }
+        });
+
+        // Input streams are handled slightly differently from everything else.
+        if (aSource instanceof Ci.nsIInputStream) {
+            let pump = Cc["@mozilla.org/network/input-stream-pump;1"].
+                       createInstance(Ci.nsIInputStreamPump);
+            pump.init(aSource, -1, -1, 0, 0, true);
+            pump.asyncRead(listener, null);
+            return;
+        }
+
+        let channel = aSource;
+        if (!(channel instanceof Ci.nsIChannel)) {
+            channel = this.newChannel2(aSource,
+                                       aLoadingNode,
+                                       aLoadingPrincipal,
+                                       aTriggeringPrincipal,
+                                       aSecurityFlags,
+                                       aContentPolicyType);
+
+        }
+
+        try {
+            channel.asyncOpen(listener, null);
+        }
+        catch (e) {
+            let exception = new Components.Exception(
+                "Failed to open input source '" + channel.originalURI.spec + "'",
+                e.result,
+                Components.stack.caller,
+                aSource,
+                e
+            );
+            throw exception;
+        }
+    },
+
+    /**
      * Constructs a new URI for the given spec, character set, and base URI, or
      * an nsIFile.
      *
      * @param aTarget
      *        The string spec for the desired URI or an nsIFile.
      * @param aOriginCharset [optional]
      *        The character set for the URI.  Only used if aTarget is not an
      *        nsIFile.
@@ -217,16 +331,112 @@ this.NetUtil = {
             // We either have a string or an nsIFile that we'll need a URI for.
             uri = this.newURI(aWhatToLoad, aOriginCharset, aBaseURI);
         }
 
         return this.ioService.newChannelFromURI(uri);
     },
 
     /**
+     * Constructs a new channel for the given spec, character set, and base URI,
+     * or nsIURI, or nsIFile.
+     *
+     * @param aWhatToLoad
+     *        The string spec for the desired URI, an nsIURI, or an nsIFile.
+     * @param aOriginCharset
+     *        The character set for the URI.  Only used if aWhatToLoad is a
+     *        string.
+     * @param aBaseURI
+     *        The base URI for the spec.  Only used if aWhatToLoad is a string.
+     * @param aLoadingNode
+     *        The loadingDocument of the channel.
+     *        The element or document where the result of this request will be
+     *        used. This is the document/element that will get access to the
+     *        result of this request. For example for an image load, it's the
+     *        document in which the image will be loaded. And for a CSS
+     *        stylesheet it's the document whose rendering will be affected by
+     *        the stylesheet.
+     *        If possible, pass in the element which is performing the load. But
+     *        if the load is coming from a JS API (such as XMLHttpRequest) or if
+     *        the load might be coalesced across multiple elements (such as
+     *        for <img>) then pass in the Document node instead.
+     *        For loads that are not related to any document, such as loads coming
+     *        from addons or internal browser features, use null here.
+     * @param aLoadingPrincipal
+     *        The loadingPrincipal of the channel.
+     *        The principal of the document where the result of this request will
+     *        be used.
+     *        This is generally the principal of the aLoadingNode. However for
+     *        loads where aLoadingNode is null this argument still needs to be
+     *        passed. For example for loads from a WebWorker, pass the principal
+     *        of that worker. For loads from an addon or from internal browser
+     *        features, pass the system principal.
+     *        This principal should almost always be the system principal if
+     *        aLoadingNode is null. The only exception to this is for loads
+     *        from WebWorkers since they don't have any nodes to be passed as
+     *        aLoadingNode.
+     *        Please note, aLoadingPrincipal is *not* the principal of the
+     *        resource being loaded. But rather the principal of the context
+     *        where the resource will be used.
+     * @param aTriggeringPrincipal
+     *        The triggeringPrincipal of the load.
+     *        The triggeringPrincipal is the principal of the resource that caused
+     *        this particular URL to be loaded.
+     *        Most likely the triggeringPrincipal and the loadingPrincipal are
+     *        identical, in which case the triggeringPrincipal can be left out.
+     *        In some cases the loadingPrincipal and the triggeringPrincipal are
+     *        different however, e.g. a stylesheet may import a subresource. In
+     *        that case the principal of the stylesheet which contains the
+     *        import command is the triggeringPrincipal, and the principal of
+     *        the document whose rendering is affected is the loadingPrincipal.
+     * @param aSecurityFlags
+     *        The securityFlags of the channel.
+     *        Any of the securityflags defined in nsILoadInfo.idl
+     * @param aContentPolicyType
+     *        The contentPolicyType of the channel.
+     *        Any of the content types defined in nsIContentPolicy.idl
+     * @return an nsIChannel object.
+     *
+     * Note: As an interim we have newChannel as well as newChannel2.
+     *       Once Bug 1087720 (which converts all js callers to use
+     *       newChannel2) lands, we can remove newChannel completely.
+     */
+    newChannel2: function NetUtil_newChannel2(aWhatToLoad,
+                                              aOriginCharset,
+                                              aBaseURI,
+                                              aLoadingNode,
+                                              aLoadingPrincipal,
+                                              aTriggeringPrincipal,
+                                              aSecurityFlags,
+                                              aContentPolicyType)
+    {
+        if (!aWhatToLoad) {
+            let exception = new Components.Exception(
+                "Must have a non-null string spec, nsIURI, or nsIFile object",
+                Cr.NS_ERROR_INVALID_ARG,
+                Components.stack.caller
+            );
+            throw exception;
+        }
+
+        let uri = aWhatToLoad;
+        if (!(aWhatToLoad instanceof Ci.nsIURI)) {
+            // We either have a string or an nsIFile that we'll need a URI for.
+            uri = this.newURI(aWhatToLoad, aOriginCharset, aBaseURI);
+        }
+
+        return this.ioService.newChannelFromURI2(uri,
+                                                 aLoadingNode,
+                                                 aLoadingPrincipal,
+                                                 aTriggeringPrincipal,
+                                                 aSecurityFlags,
+                                                 aContentPolicyType);
+    },
+
+    /**
      * Reads aCount bytes from aInputStream into a string.
      *
      * @param aInputStream
      *        The input stream to read from.
      * @param aCount
      *        The number of bytes to read from the stream.
      * @param aOptions [optional]
      *        charset