toolkit/devtools/webconsole/network-helper.js

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 /* vim:set ts=2 sw=2 sts=2 et: */
     2 /*
     3  * Software License Agreement (BSD License)
     4  *
     5  * Copyright (c) 2007, Parakey Inc.
     6  * All rights reserved.
     7  *
     8  * Redistribution and use of this software in source and binary forms, with or without modification,
     9  * are permitted provided that the following conditions are met:
    10  *
    11  * * Redistributions of source code must retain the above
    12  *   copyright notice, this list of conditions and the
    13  *   following disclaimer.
    14  *
    15  * * Redistributions in binary form must reproduce the above
    16  *   copyright notice, this list of conditions and the
    17  *   following disclaimer in the documentation and/or other
    18  *   materials provided with the distribution.
    19  *
    20  * * Neither the name of Parakey Inc. nor the names of its
    21  *   contributors may be used to endorse or promote products
    22  *   derived from this software without specific prior
    23  *   written permission of Parakey Inc.
    24  *
    25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
    26  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    27  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    28  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
    31  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    32  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    33  */
    35 /*
    36  * Creator:
    37  *  Joe Hewitt
    38  * Contributors
    39  *  John J. Barton (IBM Almaden)
    40  *  Jan Odvarko (Mozilla Corp.)
    41  *  Max Stepanov (Aptana Inc.)
    42  *  Rob Campbell (Mozilla Corp.)
    43  *  Hans Hillen (Paciello Group, Mozilla)
    44  *  Curtis Bartley (Mozilla Corp.)
    45  *  Mike Collins (IBM Almaden)
    46  *  Kevin Decker
    47  *  Mike Ratcliffe (Comartis AG)
    48  *  Hernan Rodríguez Colmeiro
    49  *  Austin Andrews
    50  *  Christoph Dorn
    51  *  Steven Roussey (AppCenter Inc, Network54)
    52  *  Mihai Sucan (Mozilla Corp.)
    53  */
    55 "use strict";
    57 const {components, Cc, Ci, Cu} = require("chrome");
    58 loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
    60 /**
    61  * Helper object for networking stuff.
    62  *
    63  * Most of the following functions have been taken from the Firebug source. They
    64  * have been modified to match the Firefox coding rules.
    65  */
    66 let NetworkHelper = {
    67   /**
    68    * Converts aText with a given aCharset to unicode.
    69    *
    70    * @param string aText
    71    *        Text to convert.
    72    * @param string aCharset
    73    *        Charset to convert the text to.
    74    * @returns string
    75    *          Converted text.
    76    */
    77   convertToUnicode: function NH_convertToUnicode(aText, aCharset)
    78   {
    79     let conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
    80                createInstance(Ci.nsIScriptableUnicodeConverter);
    81     try {
    82       conv.charset = aCharset || "UTF-8";
    83       return conv.ConvertToUnicode(aText);
    84     }
    85     catch (ex) {
    86       return aText;
    87     }
    88   },
    90   /**
    91    * Reads all available bytes from aStream and converts them to aCharset.
    92    *
    93    * @param nsIInputStream aStream
    94    * @param string aCharset
    95    * @returns string
    96    *          UTF-16 encoded string based on the content of aStream and aCharset.
    97    */
    98   readAndConvertFromStream: function NH_readAndConvertFromStream(aStream, aCharset)
    99   {
   100     let text = null;
   101     try {
   102       text = NetUtil.readInputStreamToString(aStream, aStream.available())
   103       return this.convertToUnicode(text, aCharset);
   104     }
   105     catch (err) {
   106       return text;
   107     }
   108   },
   110    /**
   111    * Reads the posted text from aRequest.
   112    *
   113    * @param nsIHttpChannel aRequest
   114    * @param string aCharset
   115    *        The content document charset, used when reading the POSTed data.
   116    * @returns string or null
   117    *          Returns the posted string if it was possible to read from aRequest
   118    *          otherwise null.
   119    */
   120   readPostTextFromRequest: function NH_readPostTextFromRequest(aRequest, aCharset)
   121   {
   122     if (aRequest instanceof Ci.nsIUploadChannel) {
   123       let iStream = aRequest.uploadStream;
   125       let isSeekableStream = false;
   126       if (iStream instanceof Ci.nsISeekableStream) {
   127         isSeekableStream = true;
   128       }
   130       let prevOffset;
   131       if (isSeekableStream) {
   132         prevOffset = iStream.tell();
   133         iStream.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
   134       }
   136       // Read data from the stream.
   137       let text = this.readAndConvertFromStream(iStream, aCharset);
   139       // Seek locks the file, so seek to the beginning only if necko hasn't
   140       // read it yet, since necko doesn't seek to 0 before reading (at lest
   141       // not till 459384 is fixed).
   142       if (isSeekableStream && prevOffset == 0) {
   143         iStream.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
   144       }
   145       return text;
   146     }
   147     return null;
   148   },
   150   /**
   151    * Reads the posted text from the page's cache.
   152    *
   153    * @param nsIDocShell aDocShell
   154    * @param string aCharset
   155    * @returns string or null
   156    *          Returns the posted string if it was possible to read from
   157    *          aDocShell otherwise null.
   158    */
   159   readPostTextFromPage: function NH_readPostTextFromPage(aDocShell, aCharset)
   160   {
   161     let webNav = aDocShell.QueryInterface(Ci.nsIWebNavigation);
   162     return this.readPostTextFromPageViaWebNav(webNav, aCharset);
   163   },
   165   /**
   166    * Reads the posted text from the page's cache, given an nsIWebNavigation
   167    * object.
   168    *
   169    * @param nsIWebNavigation aWebNav
   170    * @param string aCharset
   171    * @returns string or null
   172    *          Returns the posted string if it was possible to read from
   173    *          aWebNav, otherwise null.
   174    */
   175   readPostTextFromPageViaWebNav:
   176   function NH_readPostTextFromPageViaWebNav(aWebNav, aCharset)
   177   {
   178     if (aWebNav instanceof Ci.nsIWebPageDescriptor) {
   179       let descriptor = aWebNav.currentDescriptor;
   181       if (descriptor instanceof Ci.nsISHEntry && descriptor.postData &&
   182           descriptor instanceof Ci.nsISeekableStream) {
   183         descriptor.seek(NS_SEEK_SET, 0);
   185         return this.readAndConvertFromStream(descriptor, aCharset);
   186       }
   187     }
   188     return null;
   189   },
   191   /**
   192    * Gets the web appId that is associated with aRequest.
   193    *
   194    * @param nsIHttpChannel aRequest
   195    * @returns number|null
   196    *          The appId for the given request, if available.
   197    */
   198   getAppIdForRequest: function NH_getAppIdForRequest(aRequest)
   199   {
   200     try {
   201       return this.getRequestLoadContext(aRequest).appId;
   202     } catch (ex) {
   203       // request loadContent is not always available.
   204     }
   205     return null;
   206   },
   208   /**
   209    * Gets the topFrameElement that is associated with aRequest.
   210    *
   211    * @param nsIHttpChannel aRequest
   212    * @returns nsIDOMElement|null
   213    *          The top frame element for the given request, if available.
   214    */
   215   getTopFrameForRequest: function NH_getTopFrameForRequest(aRequest)
   216   {
   217     try {
   218       return this.getRequestLoadContext(aRequest).topFrameElement;
   219     } catch (ex) {
   220       // request loadContent is not always available.
   221     }
   222     return null;
   223   },
   225   /**
   226    * Gets the nsIDOMWindow that is associated with aRequest.
   227    *
   228    * @param nsIHttpChannel aRequest
   229    * @returns nsIDOMWindow or null
   230    */
   231   getWindowForRequest: function NH_getWindowForRequest(aRequest)
   232   {
   233     try {
   234       return this.getRequestLoadContext(aRequest).associatedWindow;
   235     } catch (ex) {
   236       // TODO: bug 802246 - getWindowForRequest() throws on b2g: there is no
   237       // associatedWindow property.
   238     }
   239     return null;
   240   },
   242   /**
   243    * Gets the nsILoadContext that is associated with aRequest.
   244    *
   245    * @param nsIHttpChannel aRequest
   246    * @returns nsILoadContext or null
   247    */
   248   getRequestLoadContext: function NH_getRequestLoadContext(aRequest)
   249   {
   250     try {
   251       return aRequest.notificationCallbacks.getInterface(Ci.nsILoadContext);
   252     } catch (ex) { }
   254     try {
   255       return aRequest.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
   256     } catch (ex) { }
   258     return null;
   259   },
   261   /**
   262    * Loads the content of aUrl from the cache.
   263    *
   264    * @param string aUrl
   265    *        URL to load the cached content for.
   266    * @param string aCharset
   267    *        Assumed charset of the cached content. Used if there is no charset
   268    *        on the channel directly.
   269    * @param function aCallback
   270    *        Callback that is called with the loaded cached content if available
   271    *        or null if something failed while getting the cached content.
   272    */
   273   loadFromCache: function NH_loadFromCache(aUrl, aCharset, aCallback)
   274   {
   275     let channel = NetUtil.newChannel(aUrl);
   277     // Ensure that we only read from the cache and not the server.
   278     channel.loadFlags = Ci.nsIRequest.LOAD_FROM_CACHE |
   279       Ci.nsICachingChannel.LOAD_ONLY_FROM_CACHE |
   280       Ci.nsICachingChannel.LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
   282     NetUtil.asyncFetch(channel, (aInputStream, aStatusCode, aRequest) => {
   283       if (!components.isSuccessCode(aStatusCode)) {
   284         aCallback(null);
   285         return;
   286       }
   288       // Try to get the encoding from the channel. If there is none, then use
   289       // the passed assumed aCharset.
   290       let aChannel = aRequest.QueryInterface(Ci.nsIChannel);
   291       let contentCharset = aChannel.contentCharset || aCharset;
   293       // Read the content of the stream using contentCharset as encoding.
   294       aCallback(this.readAndConvertFromStream(aInputStream, contentCharset));
   295     });
   296   },
   298   /**
   299    * Parse a raw Cookie header value.
   300    *
   301    * @param string aHeader
   302    *        The raw Cookie header value.
   303    * @return array
   304    *         Array holding an object for each cookie. Each object holds the
   305    *         following properties: name and value.
   306    */
   307   parseCookieHeader: function NH_parseCookieHeader(aHeader)
   308   {
   309     let cookies = aHeader.split(";");
   310     let result = [];
   312     cookies.forEach(function(aCookie) {
   313       let equal = aCookie.indexOf("=");
   314       let name = aCookie.substr(0, equal);
   315       let value = aCookie.substr(equal + 1);
   316       result.push({name: unescape(name.trim()),
   317                    value: unescape(value.trim())});
   318     });
   320     return result;
   321   },
   323   /**
   324    * Parse a raw Set-Cookie header value.
   325    *
   326    * @param string aHeader
   327    *        The raw Set-Cookie header value.
   328    * @return array
   329    *         Array holding an object for each cookie. Each object holds the
   330    *         following properties: name, value, secure (boolean), httpOnly
   331    *         (boolean), path, domain and expires (ISO date string).
   332    */
   333   parseSetCookieHeader: function NH_parseSetCookieHeader(aHeader)
   334   {
   335     let rawCookies = aHeader.split(/\r\n|\n|\r/);
   336     let cookies = [];
   338     rawCookies.forEach(function(aCookie) {
   339       let equal = aCookie.indexOf("=");
   340       let name = unescape(aCookie.substr(0, equal).trim());
   341       let parts = aCookie.substr(equal + 1).split(";");
   342       let value = unescape(parts.shift().trim());
   344       let cookie = {name: name, value: value};
   346       parts.forEach(function(aPart) {
   347         let part = aPart.trim();
   348         if (part.toLowerCase() == "secure") {
   349           cookie.secure = true;
   350         }
   351         else if (part.toLowerCase() == "httponly") {
   352           cookie.httpOnly = true;
   353         }
   354         else if (part.indexOf("=") > -1) {
   355           let pair = part.split("=");
   356           pair[0] = pair[0].toLowerCase();
   357           if (pair[0] == "path" || pair[0] == "domain") {
   358             cookie[pair[0]] = pair[1];
   359           }
   360           else if (pair[0] == "expires") {
   361             try {
   362               pair[1] = pair[1].replace(/-/g, ' ');
   363               cookie.expires = new Date(pair[1]).toISOString();
   364             }
   365             catch (ex) { }
   366           }
   367         }
   368       });
   370       cookies.push(cookie);
   371     });
   373     return cookies;
   374   },
   376   // This is a list of all the mime category maps jviereck could find in the
   377   // firebug code base.
   378   mimeCategoryMap: {
   379     "text/plain": "txt",
   380     "text/html": "html",
   381     "text/xml": "xml",
   382     "text/xsl": "txt",
   383     "text/xul": "txt",
   384     "text/css": "css",
   385     "text/sgml": "txt",
   386     "text/rtf": "txt",
   387     "text/x-setext": "txt",
   388     "text/richtext": "txt",
   389     "text/javascript": "js",
   390     "text/jscript": "txt",
   391     "text/tab-separated-values": "txt",
   392     "text/rdf": "txt",
   393     "text/xif": "txt",
   394     "text/ecmascript": "js",
   395     "text/vnd.curl": "txt",
   396     "text/x-json": "json",
   397     "text/x-js": "txt",
   398     "text/js": "txt",
   399     "text/vbscript": "txt",
   400     "view-source": "txt",
   401     "view-fragment": "txt",
   402     "application/xml": "xml",
   403     "application/xhtml+xml": "xml",
   404     "application/atom+xml": "xml",
   405     "application/rss+xml": "xml",
   406     "application/vnd.mozilla.maybe.feed": "xml",
   407     "application/vnd.mozilla.xul+xml": "xml",
   408     "application/javascript": "js",
   409     "application/x-javascript": "js",
   410     "application/x-httpd-php": "txt",
   411     "application/rdf+xml": "xml",
   412     "application/ecmascript": "js",
   413     "application/http-index-format": "txt",
   414     "application/json": "json",
   415     "application/x-js": "txt",
   416     "multipart/mixed": "txt",
   417     "multipart/x-mixed-replace": "txt",
   418     "image/svg+xml": "svg",
   419     "application/octet-stream": "bin",
   420     "image/jpeg": "image",
   421     "image/jpg": "image",
   422     "image/gif": "image",
   423     "image/png": "image",
   424     "image/bmp": "image",
   425     "application/x-shockwave-flash": "flash",
   426     "video/x-flv": "flash",
   427     "audio/mpeg3": "media",
   428     "audio/x-mpeg-3": "media",
   429     "video/mpeg": "media",
   430     "video/x-mpeg": "media",
   431     "audio/ogg": "media",
   432     "application/ogg": "media",
   433     "application/x-ogg": "media",
   434     "application/x-midi": "media",
   435     "audio/midi": "media",
   436     "audio/x-mid": "media",
   437     "audio/x-midi": "media",
   438     "music/crescendo": "media",
   439     "audio/wav": "media",
   440     "audio/x-wav": "media",
   441     "text/json": "json",
   442     "application/x-json": "json",
   443     "application/json-rpc": "json",
   444     "application/x-web-app-manifest+json": "json",
   445   },
   447   /**
   448    * Check if the given MIME type is a text-only MIME type.
   449    *
   450    * @param string aMimeType
   451    * @return boolean
   452    */
   453   isTextMimeType: function NH_isTextMimeType(aMimeType)
   454   {
   455     if (aMimeType.indexOf("text/") == 0) {
   456       return true;
   457     }
   459     // XML and JSON often come with custom MIME types, so in addition to the
   460     // standard "application/xml" and "application/json", we also look for
   461     // variants like "application/x-bigcorp+xml". For JSON we allow "+json" and
   462     // "-json" as suffixes.
   463     if (/^application\/\w+(?:[\.-]\w+)*(?:\+xml|[-+]json)$/.test(aMimeType)) {
   464       return true;
   465     }
   467     let category = this.mimeCategoryMap[aMimeType] || null;
   468     switch (category) {
   469       case "txt":
   470       case "js":
   471       case "json":
   472       case "css":
   473       case "html":
   474       case "svg":
   475       case "xml":
   476         return true;
   478       default:
   479         return false;
   480     }
   481   },
   482 };
   484 for (let prop of Object.getOwnPropertyNames(NetworkHelper)) {
   485   exports[prop] = NetworkHelper[prop];
   486 }

mercurial