addon-sdk/source/lib/sdk/io/text-streams.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 "use strict";
     7 module.metadata = {
     8   "stability": "experimental"
     9 };
    11 const {Cc,Ci,Cu,components} = require("chrome");
    12 var NetUtil = {};
    13 Cu.import("resource://gre/modules/NetUtil.jsm", NetUtil);
    14 NetUtil = NetUtil.NetUtil;
    16 // NetUtil.asyncCopy() uses this buffer length, and since we call it, for best
    17 // performance we use it, too.
    18 const BUFFER_BYTE_LEN = 0x8000;
    19 const PR_UINT32_MAX = 0xffffffff;
    20 const DEFAULT_CHARSET = "UTF-8";
    22 exports.TextReader = TextReader;
    23 exports.TextWriter = TextWriter;
    25 /**
    26  * An input stream that reads text from a backing stream using a given text
    27  * encoding.
    28  *
    29  * @param inputStream
    30  *        The stream is backed by this nsIInputStream.  It must already be
    31  *        opened.
    32  * @param charset
    33  *        Text in inputStream is expected to be in this character encoding.  If
    34  *        not given, "UTF-8" is assumed.  See nsICharsetConverterManager.idl for
    35  *        documentation on how to determine other valid values for this.
    36  */
    37 function TextReader(inputStream, charset) {
    38   const self = this;
    39   charset = checkCharset(charset);
    41   let stream = Cc["@mozilla.org/intl/converter-input-stream;1"].
    42                createInstance(Ci.nsIConverterInputStream);
    43   stream.init(inputStream, charset, BUFFER_BYTE_LEN,
    44               Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
    46   let manager = new StreamManager(this, stream);
    48   /**
    49    * Reads a string from the stream.  If the stream is closed, an exception is
    50    * thrown.
    51    *
    52    * @param  numChars
    53    *         The number of characters to read.  If not given, the remainder of
    54    *         the stream is read.
    55    * @return The string read.  If the stream is already at EOS, returns the
    56    *         empty string.
    57    */
    58   this.read = function TextReader_read(numChars) {
    59     manager.ensureOpened();
    61     let readAll = false;
    62     if (typeof(numChars) === "number")
    63       numChars = Math.max(numChars, 0);
    64     else
    65       readAll = true;
    67     let str = "";
    68     let totalRead = 0;
    69     let chunkRead = 1;
    71     // Read in numChars or until EOS, whichever comes first.  Note that the
    72     // units here are characters, not bytes.
    73     while (true) {
    74       let chunk = {};
    75       let toRead = readAll ?
    76                    PR_UINT32_MAX :
    77                    Math.min(numChars - totalRead, PR_UINT32_MAX);
    78       if (toRead <= 0 || chunkRead <= 0)
    79         break;
    81       // The converter stream reads in at most BUFFER_BYTE_LEN bytes in a call
    82       // to readString, enough to fill its byte buffer.  chunkRead will be the
    83       // number of characters encoded by the bytes in that buffer.
    84       chunkRead = stream.readString(toRead, chunk);
    85       str += chunk.value;
    86       totalRead += chunkRead;
    87     }
    89     return str;
    90   };
    91 }
    93 /**
    94  * A buffered output stream that writes text to a backing stream using a given
    95  * text encoding.
    96  *
    97  * @param outputStream
    98  *        The stream is backed by this nsIOutputStream.  It must already be
    99  *        opened.
   100  * @param charset
   101  *        Text will be written to outputStream using this character encoding.
   102  *        If not given, "UTF-8" is assumed.  See nsICharsetConverterManager.idl
   103  *        for documentation on how to determine other valid values for this.
   104  */
   105 function TextWriter(outputStream, charset) {
   106   const self = this;
   107   charset = checkCharset(charset);
   109   let stream = outputStream;
   111   // Buffer outputStream if it's not already.
   112   let ioUtils = Cc["@mozilla.org/io-util;1"].getService(Ci.nsIIOUtil);
   113   if (!ioUtils.outputStreamIsBuffered(outputStream)) {
   114     stream = Cc["@mozilla.org/network/buffered-output-stream;1"].
   115              createInstance(Ci.nsIBufferedOutputStream);
   116     stream.init(outputStream, BUFFER_BYTE_LEN);
   117   }
   119   // I'd like to use nsIConverterOutputStream.  But NetUtil.asyncCopy(), which
   120   // we use below in writeAsync(), naturally expects its sink to be an instance
   121   // of nsIOutputStream, which nsIConverterOutputStream's only implementation is
   122   // not.  So we use uconv and manually convert all strings before writing to
   123   // outputStream.
   124   let uconv = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
   125               createInstance(Ci.nsIScriptableUnicodeConverter);
   126   uconv.charset = charset;
   128   let manager = new StreamManager(this, stream);
   130   /**
   131    * Flushes the backing stream's buffer.
   132    */
   133   this.flush = function TextWriter_flush() {
   134     manager.ensureOpened();
   135     stream.flush();
   136   };
   138   /**
   139    * Writes a string to the stream.  If the stream is closed, an exception is
   140    * thrown.
   141    *
   142    * @param str
   143    *        The string to write.
   144    */
   145   this.write = function TextWriter_write(str) {
   146     manager.ensureOpened();
   147     let istream = uconv.convertToInputStream(str);
   148     let len = istream.available();
   149     while (len > 0) {
   150       stream.writeFrom(istream, len);
   151       len = istream.available();
   152     }
   153     istream.close();
   154   };
   156   /**
   157    * Writes a string on a background thread.  After the write completes, the
   158    * backing stream's buffer is flushed, and both the stream and the backing
   159    * stream are closed, also on the background thread.  If the stream is already
   160    * closed, an exception is thrown immediately.
   161    *
   162    * @param str
   163    *        The string to write.
   164    * @param callback
   165    *        An optional function.  If given, it's called as callback(error) when
   166    *        the write completes.  error is an Error object or undefined if there
   167    *        was no error.  Inside callback, |this| is the stream object.
   168    */
   169   this.writeAsync = function TextWriter_writeAsync(str, callback) {
   170     manager.ensureOpened();
   171     let istream = uconv.convertToInputStream(str);
   172     NetUtil.asyncCopy(istream, stream, function (result) {
   173         let err = components.isSuccessCode(result) ? undefined :
   174         new Error("An error occured while writing to the stream: " + result);
   175       if (err)
   176         console.error(err);
   178       // asyncCopy() closes its output (and input) stream.
   179       manager.opened = false;
   181       if (typeof(callback) === "function") {
   182         try {
   183           callback.call(self, err);
   184         }
   185         catch (exc) {
   186           console.exception(exc);
   187         }
   188       }
   189     });
   190   };
   191 }
   193 // This manages the lifetime of stream, a TextReader or TextWriter.  It defines
   194 // closed and close() on stream and registers an unload listener that closes
   195 // rawStream if it's still opened.  It also provides ensureOpened(), which
   196 // throws an exception if the stream is closed.
   197 function StreamManager(stream, rawStream) {
   198   const self = this;
   199   this.rawStream = rawStream;
   200   this.opened = true;
   202   /**
   203    * True iff the stream is closed.
   204    */
   205   stream.__defineGetter__("closed", function stream_closed() {
   206     return !self.opened;
   207   });
   209   /**
   210    * Closes both the stream and its backing stream.  If the stream is already
   211    * closed, an exception is thrown.  For TextWriters, this first flushes the
   212    * backing stream's buffer.
   213    */
   214   stream.close = function stream_close() {
   215     self.ensureOpened();
   216     self.unload();
   217   };
   219   require("../system/unload").ensure(this);
   220 }
   222 StreamManager.prototype = {
   223   ensureOpened: function StreamManager_ensureOpened() {
   224     if (!this.opened)
   225       throw new Error("The stream is closed and cannot be used.");
   226   },
   227   unload: function StreamManager_unload() {
   228     // TextWriter.writeAsync() causes rawStream to close and therefore sets
   229     // opened to false, so check that we're still opened.
   230     if (this.opened) {
   231       // Calling close() on both an nsIUnicharInputStream and
   232       // nsIBufferedOutputStream closes their backing streams.  It also forces
   233       // nsIOutputStreams to flush first.
   234       this.rawStream.close();
   235       this.opened = false;
   236     }
   237   }
   238 };
   240 function checkCharset(charset) {
   241   return typeof(charset) === "string" ? charset : DEFAULT_CHARSET;
   242 }

mercurial