netwerk/base/src/NetUtil.jsm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: sw=4 ts=4 sts=4 et filetype=javascript
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 this.EXPORTED_SYMBOLS = [
     8   "NetUtil",
     9 ];
    11 /**
    12  * Necko utilities
    13  */
    15 ////////////////////////////////////////////////////////////////////////////////
    16 //// Constants
    18 const Ci = Components.interfaces;
    19 const Cc = Components.classes;
    20 const Cr = Components.results;
    21 const Cu = Components.utils;
    23 const PR_UINT32_MAX = 0xffffffff;
    25 ////////////////////////////////////////////////////////////////////////////////
    26 //// NetUtil Object
    28 this.NetUtil = {
    29     /**
    30      * Function to perform simple async copying from aSource (an input stream)
    31      * to aSink (an output stream).  The copy will happen on some background
    32      * thread.  Both streams will be closed when the copy completes.
    33      *
    34      * @param aSource
    35      *        The input stream to read from
    36      * @param aSink
    37      *        The output stream to write to
    38      * @param aCallback [optional]
    39      *        A function that will be called at copy completion with a single
    40      *        argument: the nsresult status code for the copy operation.
    41      *
    42      * @return An nsIRequest representing the copy operation (for example, this
    43      *         can be used to cancel the copying).  The consumer can ignore the
    44      *         return value if desired.
    45      */
    46     asyncCopy: function NetUtil_asyncCopy(aSource, aSink,
    47                                           aCallback = null)
    48     {
    49         if (!aSource || !aSink) {
    50             let exception = new Components.Exception(
    51                 "Must have a source and a sink",
    52                 Cr.NS_ERROR_INVALID_ARG,
    53                 Components.stack.caller
    54             );
    55             throw exception;
    56         }
    58         // make a stream copier
    59         var copier = Cc["@mozilla.org/network/async-stream-copier;1"].
    60             createInstance(Ci.nsIAsyncStreamCopier2);
    61         copier.init(aSource, aSink,
    62                     null /* Default event target */,
    63                     0 /* Default length */,
    64                     true, true /* Auto-close */);
    66         var observer;
    67         if (aCallback) {
    68             observer = {
    69                 onStartRequest: function(aRequest, aContext) {},
    70                 onStopRequest: function(aRequest, aContext, aStatusCode) {
    71                     aCallback(aStatusCode);
    72                 }
    73             }
    74         } else {
    75             observer = null;
    76         }
    78         // start the copying
    79         copier.QueryInterface(Ci.nsIAsyncStreamCopier).asyncCopy(observer, null);
    80         return copier;
    81     },
    83     /**
    84      * Asynchronously opens a source and fetches the response.  A source can be
    85      * an nsIURI, nsIFile, string spec, nsIChannel, or nsIInputStream.  The
    86      * provided callback will get an input stream containing the response, the
    87      * result code, and a reference to the request.
    88      *
    89      * @param aSource
    90      *        The nsIURI, nsIFile, string spec, nsIChannel, or nsIInputStream
    91      *        to open.
    92      * @param aCallback
    93      *        The callback function that will be notified upon completion.  It
    94      *        will get two arguments:
    95      *        1) An nsIInputStream containing the data from aSource, if any.
    96      *        2) The status code from opening the source.
    97      *        3) Reference to the nsIRequest.
    98      */
    99     asyncFetch: function NetUtil_asyncOpen(aSource, aCallback)
   100     {
   101         if (!aSource || !aCallback) {
   102             let exception = new Components.Exception(
   103                 "Must have a source and a callback",
   104                 Cr.NS_ERROR_INVALID_ARG,
   105                 Components.stack.caller
   106             );
   107             throw exception;
   108         }
   110         // Create a pipe that will create our output stream that we can use once
   111         // we have gotten all the data.
   112         let pipe = Cc["@mozilla.org/pipe;1"].
   113                    createInstance(Ci.nsIPipe);
   114         pipe.init(true, true, 0, PR_UINT32_MAX, null);
   116         // Create a listener that will give data to the pipe's output stream.
   117         let listener = Cc["@mozilla.org/network/simple-stream-listener;1"].
   118                        createInstance(Ci.nsISimpleStreamListener);
   119         listener.init(pipe.outputStream, {
   120             onStartRequest: function(aRequest, aContext) {},
   121             onStopRequest: function(aRequest, aContext, aStatusCode) {
   122                 pipe.outputStream.close();
   123                 aCallback(pipe.inputStream, aStatusCode, aRequest);
   124             }
   125         });
   127         // Input streams are handled slightly differently from everything else.
   128         if (aSource instanceof Ci.nsIInputStream) {
   129             let pump = Cc["@mozilla.org/network/input-stream-pump;1"].
   130                        createInstance(Ci.nsIInputStreamPump);
   131             pump.init(aSource, -1, -1, 0, 0, true);
   132             pump.asyncRead(listener, null);
   133             return;
   134         }
   136         let channel = aSource;
   137         if (!(channel instanceof Ci.nsIChannel)) {
   138             channel = this.newChannel(aSource);
   139         }
   141         try {
   142             channel.asyncOpen(listener, null);
   143         }
   144         catch (e) {
   145             let exception = new Components.Exception(
   146                 "Failed to open input source '" + channel.originalURI.spec + "'",
   147                 e.result,
   148                 Components.stack.caller,
   149                 aSource,
   150                 e
   151             );
   152             throw exception;
   153         }
   154     },
   156     /**
   157      * Constructs a new URI for the given spec, character set, and base URI, or
   158      * an nsIFile.
   159      *
   160      * @param aTarget
   161      *        The string spec for the desired URI or an nsIFile.
   162      * @param aOriginCharset [optional]
   163      *        The character set for the URI.  Only used if aTarget is not an
   164      *        nsIFile.
   165      * @param aBaseURI [optional]
   166      *        The base URI for the spec.  Only used if aTarget is not an
   167      *        nsIFile.
   168      *
   169      * @return an nsIURI object.
   170      */
   171     newURI: function NetUtil_newURI(aTarget, aOriginCharset, aBaseURI)
   172     {
   173         if (!aTarget) {
   174             let exception = new Components.Exception(
   175                 "Must have a non-null string spec or nsIFile object",
   176                 Cr.NS_ERROR_INVALID_ARG,
   177                 Components.stack.caller
   178             );
   179             throw exception;
   180         }
   182         if (aTarget instanceof Ci.nsIFile) {
   183             return this.ioService.newFileURI(aTarget);
   184         }
   186         return this.ioService.newURI(aTarget, aOriginCharset, aBaseURI);
   187     },
   189     /**
   190      * Constructs a new channel for the given spec, character set, and base URI,
   191      * or nsIURI, or nsIFile.
   192      *
   193      * @param aWhatToLoad
   194      *        The string spec for the desired URI, an nsIURI, or an nsIFile.
   195      * @param aOriginCharset [optional]
   196      *        The character set for the URI.  Only used if aWhatToLoad is a
   197      *        string.
   198      * @param aBaseURI [optional]
   199      *        The base URI for the spec.  Only used if aWhatToLoad is a string.
   200      *
   201      * @return an nsIChannel object.
   202      */
   203     newChannel: function NetUtil_newChannel(aWhatToLoad, aOriginCharset,
   204                                             aBaseURI)
   205     {
   206         if (!aWhatToLoad) {
   207             let exception = new Components.Exception(
   208                 "Must have a non-null string spec, nsIURI, or nsIFile object",
   209                 Cr.NS_ERROR_INVALID_ARG,
   210                 Components.stack.caller
   211             );
   212             throw exception;
   213         }
   215         let uri = aWhatToLoad;
   216         if (!(aWhatToLoad instanceof Ci.nsIURI)) {
   217             // We either have a string or an nsIFile that we'll need a URI for.
   218             uri = this.newURI(aWhatToLoad, aOriginCharset, aBaseURI);
   219         }
   221         return this.ioService.newChannelFromURI(uri);
   222     },
   224     /**
   225      * Reads aCount bytes from aInputStream into a string.
   226      *
   227      * @param aInputStream
   228      *        The input stream to read from.
   229      * @param aCount
   230      *        The number of bytes to read from the stream.
   231      * @param aOptions [optional]
   232      *        charset
   233      *          The character encoding of stream data.
   234      *        replacement
   235      *          The character to replace unknown byte sequences.
   236      *          If unset, it causes an exceptions to be thrown.
   237      *
   238      * @return the bytes from the input stream in string form.
   239      *
   240      * @throws NS_ERROR_INVALID_ARG if aInputStream is not an nsIInputStream.
   241      * @throws NS_BASE_STREAM_WOULD_BLOCK if reading from aInputStream would
   242      *         block the calling thread (non-blocking mode only).
   243      * @throws NS_ERROR_FAILURE if there are not enough bytes available to read
   244      *         aCount amount of data.
   245      * @throws NS_ERROR_ILLEGAL_INPUT if aInputStream has invalid sequences
   246      */
   247     readInputStreamToString: function NetUtil_readInputStreamToString(aInputStream,
   248                                                                       aCount,
   249                                                                       aOptions)
   250     {
   251         if (!(aInputStream instanceof Ci.nsIInputStream)) {
   252             let exception = new Components.Exception(
   253                 "First argument should be an nsIInputStream",
   254                 Cr.NS_ERROR_INVALID_ARG,
   255                 Components.stack.caller
   256             );
   257             throw exception;
   258         }
   260         if (!aCount) {
   261             let exception = new Components.Exception(
   262                 "Non-zero amount of bytes must be specified",
   263                 Cr.NS_ERROR_INVALID_ARG,
   264                 Components.stack.caller
   265             );
   266             throw exception;
   267         }
   269         if (aOptions && "charset" in aOptions) {
   270           let cis = Cc["@mozilla.org/intl/converter-input-stream;1"].
   271                     createInstance(Ci.nsIConverterInputStream);
   272           try {
   273             // When replacement is set, the character that is unknown sequence 
   274             // replaces with aOptions.replacement character.
   275             if (!("replacement" in aOptions)) {
   276               // aOptions.replacement isn't set.
   277               // If input stream has unknown sequences for aOptions.charset,
   278               // throw NS_ERROR_ILLEGAL_INPUT.
   279               aOptions.replacement = 0;
   280             }
   282             cis.init(aInputStream, aOptions.charset, aCount,
   283                      aOptions.replacement);
   284             let str = {};
   285             cis.readString(-1, str);
   286             cis.close();
   287             return str.value;
   288           }
   289           catch (e) {
   290             // Adjust the stack so it throws at the caller's location.
   291             throw new Components.Exception(e.message, e.result,
   292                                            Components.stack.caller, e.data);
   293           }
   294         }
   296         let sis = Cc["@mozilla.org/scriptableinputstream;1"].
   297                   createInstance(Ci.nsIScriptableInputStream);
   298         sis.init(aInputStream);
   299         try {
   300             return sis.readBytes(aCount);
   301         }
   302         catch (e) {
   303             // Adjust the stack so it throws at the caller's location.
   304             throw new Components.Exception(e.message, e.result,
   305                                            Components.stack.caller, e.data);
   306         }
   307     },
   309     /**
   310      * Returns a reference to nsIIOService.
   311      *
   312      * @return a reference to nsIIOService.
   313      */
   314     get ioService()
   315     {
   316         delete this.ioService;
   317         return this.ioService = Cc["@mozilla.org/network/io-service;1"].
   318                                 getService(Ci.nsIIOService);
   319     },
   320 };
   322 ////////////////////////////////////////////////////////////////////////////////
   323 //// Initialization
   325 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
   327 // Define our lazy getters.
   328 XPCOMUtils.defineLazyServiceGetter(this, "ioUtil", "@mozilla.org/io-util;1",
   329                                    "nsIIOUtil");

mercurial