netwerk/test/unit/head_channels.js

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

     1 /**
     2  * Read count bytes from stream and return as a String object
     3  */
     4 function read_stream(stream, count) {
     5   /* assume stream has non-ASCII data */
     6   var wrapper =
     7       Components.classes["@mozilla.org/binaryinputstream;1"]
     8                 .createInstance(Components.interfaces.nsIBinaryInputStream);
     9   wrapper.setInputStream(stream);
    10   /* JS methods can be called with a maximum of 65535 arguments, and input
    11      streams don't have to return all the data they make .available() when
    12      asked to .read() that number of bytes. */
    13   var data = [];
    14   while (count > 0) {
    15     var bytes = wrapper.readByteArray(Math.min(65535, count));
    16     data.push(String.fromCharCode.apply(null, bytes));
    17     count -= bytes.length;
    18     if (bytes.length == 0)
    19       do_throw("Nothing read from input stream!");
    20   }
    21   return data.join('');
    22 }
    24 const CL_EXPECT_FAILURE = 0x1;
    25 const CL_EXPECT_GZIP = 0x2;
    26 const CL_EXPECT_3S_DELAY = 0x4;
    27 const CL_SUSPEND = 0x8;
    28 const CL_ALLOW_UNKNOWN_CL = 0x10;
    29 const CL_EXPECT_LATE_FAILURE = 0x20;
    30 const CL_FROM_CACHE = 0x40; // Response must be from the cache
    31 const CL_NOT_FROM_CACHE = 0x80; // Response must NOT be from the cache
    33 const SUSPEND_DELAY = 3000;
    35 /**
    36  * A stream listener that calls a callback function with a specified
    37  * context and the received data when the channel is loaded.
    38  *
    39  * Signature of the closure:
    40  *   void closure(in nsIRequest request, in ACString data, in JSObject context);
    41  *
    42  * This listener makes sure that various parts of the channel API are
    43  * implemented correctly and that the channel's status is a success code
    44  * (you can pass CL_EXPECT_FAILURE or CL_EXPECT_LATE_FAILURE as flags
    45  * to allow a failure code)
    46  *
    47  * Note that it also requires a valid content length on the channel and
    48  * is thus not fully generic.
    49  */
    50 function ChannelListener(closure, ctx, flags) {
    51   this._closure = closure;
    52   this._closurectx = ctx;
    53   this._flags = flags;
    54 }
    55 ChannelListener.prototype = {
    56   _closure: null,
    57   _closurectx: null,
    58   _buffer: "",
    59   _got_onstartrequest: false,
    60   _got_onstoprequest: false,
    61   _contentLen: -1,
    62   _lastEvent: 0,
    64   QueryInterface: function(iid) {
    65     if (iid.equals(Components.interfaces.nsIStreamListener) ||
    66         iid.equals(Components.interfaces.nsIRequestObserver) ||
    67         iid.equals(Components.interfaces.nsISupports))
    68       return this;
    69     throw Components.results.NS_ERROR_NO_INTERFACE;
    70   },
    72   onStartRequest: function(request, context) {
    73     try {
    74       if (this._got_onstartrequest)
    75         do_throw("Got second onStartRequest event!");
    76       this._got_onstartrequest = true;
    77       this._lastEvent = Date.now();
    79       request.QueryInterface(Components.interfaces.nsIChannel);
    80       try {
    81         this._contentLen = request.contentLength;
    82       }
    83       catch (ex) {
    84         if (!(this._flags & (CL_EXPECT_FAILURE | CL_ALLOW_UNKNOWN_CL)))
    85           do_throw("Could not get contentLength");
    86       }
    87       if (this._contentLen == -1 && !(this._flags & (CL_EXPECT_FAILURE | CL_ALLOW_UNKNOWN_CL)))
    88         do_throw("Content length is unknown in onStartRequest!");
    90       if ((this._flags & CL_FROM_CACHE)) {
    91         request.QueryInterface(Ci.nsICachingChannel);
    92         if (!request.isFromCache()) {
    93           do_throw("Response is not from the cache (CL_FROM_CACHE)");
    94         }
    95       }
    96       if ((this._flags & CL_NOT_FROM_CACHE)) {
    97         request.QueryInterface(Ci.nsICachingChannel);
    98         if (request.isFromCache()) {
    99           do_throw("Response is from the cache (CL_NOT_FROM_CACHE)");
   100         }
   101       }
   103       if (this._flags & CL_SUSPEND) {
   104         request.suspend();
   105         do_timeout(SUSPEND_DELAY, function() { request.resume(); });
   106       }
   108     } catch (ex) {
   109       do_throw("Error in onStartRequest: " + ex);
   110     }
   111   },
   113   onDataAvailable: function(request, context, stream, offset, count) {
   114     try {
   115       let current = Date.now();
   117       if (!this._got_onstartrequest)
   118         do_throw("onDataAvailable without onStartRequest event!");
   119       if (this._got_onstoprequest)
   120         do_throw("onDataAvailable after onStopRequest event!");
   121       if (!request.isPending())
   122         do_throw("request reports itself as not pending from onDataAvailable!");
   123       if (this._flags & CL_EXPECT_FAILURE)
   124         do_throw("Got data despite expecting a failure");
   126       if (current - this._lastEvent >= SUSPEND_DELAY &&
   127           !(this._flags & CL_EXPECT_3S_DELAY))
   128        do_throw("Data received after significant unexpected delay");
   129       else if (current - this._lastEvent < SUSPEND_DELAY &&
   130                this._flags & CL_EXPECT_3S_DELAY)
   131         do_throw("Data received sooner than expected");
   132       else if (current - this._lastEvent >= SUSPEND_DELAY &&
   133                this._flags & CL_EXPECT_3S_DELAY)
   134         this._flags &= ~CL_EXPECT_3S_DELAY; // No more delays expected
   136       this._buffer = this._buffer.concat(read_stream(stream, count));
   137       this._lastEvent = current;
   138     } catch (ex) {
   139       do_throw("Error in onDataAvailable: " + ex);
   140     }
   141   },
   143   onStopRequest: function(request, context, status) {
   144     try {
   145       var success = Components.isSuccessCode(status);
   146       if (!this._got_onstartrequest)
   147         do_throw("onStopRequest without onStartRequest event!");
   148       if (this._got_onstoprequest)
   149         do_throw("Got second onStopRequest event!");
   150       this._got_onstoprequest = true;
   151       if ((this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) && success)
   152         do_throw("Should have failed to load URL (status is " + status.toString(16) + ")");
   153       else if (!(this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) && !success)
   154         do_throw("Failed to load URL: " + status.toString(16));
   155       if (status != request.status)
   156         do_throw("request.status does not match status arg to onStopRequest!");
   157       if (request.isPending())
   158         do_throw("request reports itself as pending from onStopRequest!");
   159       if (!(this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) &&
   160           !(this._flags & CL_EXPECT_GZIP) &&
   161           this._contentLen != -1)
   162           do_check_eq(this._buffer.length, this._contentLen)
   163     } catch (ex) {
   164       do_throw("Error in onStopRequest: " + ex);
   165     }
   166     try {
   167       this._closure(request, this._buffer, this._closurectx);
   168     } catch (ex) {
   169       do_throw("Error in closure function: " + ex);
   170     }
   171   }
   172 };
   174 var ES_ABORT_REDIRECT = 0x01;
   176 function ChannelEventSink(flags)
   177 {
   178   this._flags = flags;
   179 }
   181 ChannelEventSink.prototype = {
   182   QueryInterface: function(iid) {
   183     if (iid.equals(Ci.nsIInterfaceRequestor) ||
   184         iid.equals(Ci.nsISupports))
   185       return this;
   186     throw Cr.NS_ERROR_NO_INTERFACE;
   187   },
   189   getInterface: function(iid) {
   190     if (iid.equals(Ci.nsIChannelEventSink))
   191       return this;
   192     throw Cr.NS_ERROR_NO_INTERFACE;
   193   },
   195   asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) {
   196     if (this._flags & ES_ABORT_REDIRECT)
   197       throw Cr.NS_BINDING_ABORTED;
   199     callback.onRedirectVerifyCallback(Cr.NS_OK);
   200   }
   201 };
   204 /**
   205  * Class that implements nsILoadContext.  Use it as callbacks for channel when
   206  * test needs it.
   207  */
   208 function LoadContextCallback(appId, inBrowserElement, isPrivate, isContent) {
   209   this.appId = appId;
   210   this.isInBrowserElement = inBrowserElement;
   211   this.usePrivateBrowsing = isPrivate;
   212   this.isContent = isContent;
   213 }
   215 LoadContextCallback.prototype = {
   216   associatedWindow: null,
   217   topWindow : null,
   218   isAppOfType: function(appType) {
   219     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   220   },
   221   QueryInterface: function(iid) {
   222     if (iid.equals(Ci.nsILoadContext) ||
   223         iid.equals(Ci.nsIInterfaceRequestor) ||
   224         iid.equals(Ci.nsISupports)) {
   225         return this;
   226     }
   227     throw Cr.NS_ERROR_NO_INTERFACE;
   228   },
   229   getInterface: function(iid) {
   230     if (iid.equals(Ci.nsILoadContext))
   231       return this;
   232     throw Cr.NS_ERROR_NO_INTERFACE;
   233   },
   234 }

mercurial