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 219870 b921743d876e978baa61b509bb52ce8b504d7d1e
parent 219869 adc247a722ef1f44b3f6d07eb86bfdc56d9210a7
child 219871 da727b086b56522e59ad2e54ef1852e1d287a313
push id10419
push usercbook@mozilla.com
push dateTue, 16 Dec 2014 12:45:27 +0000
treeherderfx-team@ec87657146eb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs1095798
milestone37.0a1
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