1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/extensions/cookie/test/channel_utils.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,195 @@ 1.4 +/* 1.5 + * This file is a modified version of netwerk/test/unit/head_channels.js 1.6 + * The changes consist of making it work in mochitest files and removing 1.7 + * unused code. 1.8 + */ 1.9 + 1.10 +/** 1.11 + * Read count bytes from stream and return as a String object 1.12 + */ 1.13 +function read_stream(stream, count) { 1.14 + /* assume stream has non-ASCII data */ 1.15 + var wrapper = 1.16 + Components.classes["@mozilla.org/binaryinputstream;1"] 1.17 + .createInstance(Components.interfaces.nsIBinaryInputStream); 1.18 + wrapper.setInputStream(stream); 1.19 + /* JS methods can be called with a maximum of 65535 arguments, and input 1.20 + streams don't have to return all the data they make .available() when 1.21 + asked to .read() that number of bytes. */ 1.22 + var data = []; 1.23 + while (count > 0) { 1.24 + var bytes = wrapper.readByteArray(Math.min(65535, count)); 1.25 + data.push(String.fromCharCode.apply(null, bytes)); 1.26 + count -= bytes.length; 1.27 + if (bytes.length == 0) 1.28 + throw("Nothing read from input stream!"); 1.29 + } 1.30 + return data.join(''); 1.31 +} 1.32 + 1.33 +const CL_EXPECT_FAILURE = 0x1; 1.34 +const CL_EXPECT_GZIP = 0x2; 1.35 +const CL_EXPECT_3S_DELAY = 0x4; 1.36 +const CL_SUSPEND = 0x8; 1.37 +const CL_ALLOW_UNKNOWN_CL = 0x10; 1.38 +const CL_EXPECT_LATE_FAILURE = 0x20; 1.39 + 1.40 +const SUSPEND_DELAY = 3000; 1.41 + 1.42 +/** 1.43 + * A stream listener that calls a callback function with a specified 1.44 + * context and the received data when the channel is loaded. 1.45 + * 1.46 + * Signature of the closure: 1.47 + * void closure(in nsIRequest request, in ACString data, in JSObject context); 1.48 + * 1.49 + * This listener makes sure that various parts of the channel API are 1.50 + * implemented correctly and that the channel's status is a success code 1.51 + * (you can pass CL_EXPECT_FAILURE or CL_EXPECT_LATE_FAILURE as flags 1.52 + * to allow a failure code) 1.53 + * 1.54 + * Note that it also requires a valid content length on the channel and 1.55 + * is thus not fully generic. 1.56 + */ 1.57 +function ChannelListener(closure, ctx, flags) { 1.58 + this._closure = closure; 1.59 + this._closurectx = ctx; 1.60 + this._flags = flags; 1.61 +} 1.62 +ChannelListener.prototype = { 1.63 + _closure: null, 1.64 + _closurectx: null, 1.65 + _buffer: "", 1.66 + _got_onstartrequest: false, 1.67 + _got_onstoprequest: false, 1.68 + _contentLen: -1, 1.69 + _lastEvent: 0, 1.70 + 1.71 + QueryInterface: function(iid) { 1.72 + if (iid.equals(Components.interfaces.nsIStreamListener) || 1.73 + iid.equals(Components.interfaces.nsIRequestObserver) || 1.74 + iid.equals(Components.interfaces.nsISupports)) 1.75 + return this; 1.76 + throw Components.results.NS_ERROR_NO_INTERFACE; 1.77 + }, 1.78 + 1.79 + onStartRequest: function(request, context) { 1.80 + try { 1.81 + if (this._got_onstartrequest) 1.82 + throw("Got second onStartRequest event!"); 1.83 + this._got_onstartrequest = true; 1.84 + this._lastEvent = Date.now(); 1.85 + 1.86 + request.QueryInterface(Components.interfaces.nsIChannel); 1.87 + try { 1.88 + this._contentLen = request.contentLength; 1.89 + } 1.90 + catch (ex) { 1.91 + if (!(this._flags & (CL_EXPECT_FAILURE | CL_ALLOW_UNKNOWN_CL))) 1.92 + throw("Could not get contentLength"); 1.93 + } 1.94 + if (this._contentLen == -1 && !(this._flags & (CL_EXPECT_FAILURE | CL_ALLOW_UNKNOWN_CL))) 1.95 + throw("Content length is unknown in onStartRequest!"); 1.96 + 1.97 + if (this._flags & CL_SUSPEND) { 1.98 + request.suspend(); 1.99 + do_timeout(SUSPEND_DELAY, function() { request.resume(); }); 1.100 + } 1.101 + 1.102 + } catch (ex) { 1.103 + throw("Error in onStartRequest: " + ex); 1.104 + } 1.105 + }, 1.106 + 1.107 + onDataAvailable: function(request, context, stream, offset, count) { 1.108 + try { 1.109 + var current = Date.now(); 1.110 + 1.111 + if (!this._got_onstartrequest) 1.112 + throw("onDataAvailable without onStartRequest event!"); 1.113 + if (this._got_onstoprequest) 1.114 + throw("onDataAvailable after onStopRequest event!"); 1.115 + if (!request.isPending()) 1.116 + throw("request reports itself as not pending from onDataAvailable!"); 1.117 + if (this._flags & CL_EXPECT_FAILURE) 1.118 + throw("Got data despite expecting a failure"); 1.119 + 1.120 + if (current - this._lastEvent >= SUSPEND_DELAY && 1.121 + !(this._flags & CL_EXPECT_3S_DELAY)) 1.122 + throw("Data received after significant unexpected delay"); 1.123 + else if (current - this._lastEvent < SUSPEND_DELAY && 1.124 + this._flags & CL_EXPECT_3S_DELAY) 1.125 + throw("Data received sooner than expected"); 1.126 + else if (current - this._lastEvent >= SUSPEND_DELAY && 1.127 + this._flags & CL_EXPECT_3S_DELAY) 1.128 + this._flags &= ~CL_EXPECT_3S_DELAY; // No more delays expected 1.129 + 1.130 + this._buffer = this._buffer.concat(read_stream(stream, count)); 1.131 + this._lastEvent = current; 1.132 + } catch (ex) { 1.133 + throw("Error in onDataAvailable: " + ex); 1.134 + } 1.135 + }, 1.136 + 1.137 + onStopRequest: function(request, context, status) { 1.138 + try { 1.139 + var success = Components.isSuccessCode(status); 1.140 + if (!this._got_onstartrequest) 1.141 + throw("onStopRequest without onStartRequest event!"); 1.142 + if (this._got_onstoprequest) 1.143 + throw("Got second onStopRequest event!"); 1.144 + this._got_onstoprequest = true; 1.145 + if ((this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) && success) 1.146 + throw("Should have failed to load URL (status is " + status.toString(16) + ")"); 1.147 + else if (!(this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) && !success) 1.148 + throw("Failed to load URL: " + status.toString(16)); 1.149 + if (status != request.status) 1.150 + throw("request.status does not match status arg to onStopRequest!"); 1.151 + if (request.isPending()) 1.152 + throw("request reports itself as pending from onStopRequest!"); 1.153 + if (!(this._flags & (CL_EXPECT_FAILURE | CL_EXPECT_LATE_FAILURE)) && 1.154 + !(this._flags & CL_EXPECT_GZIP) && 1.155 + this._contentLen != -1) 1.156 + is(this._buffer.length, this._contentLen); 1.157 + } catch (ex) { 1.158 + throw("Error in onStopRequest: " + ex); 1.159 + } 1.160 + try { 1.161 + this._closure(request, this._buffer, this._closurectx); 1.162 + } catch (ex) { 1.163 + throw("Error in closure function: " + ex); 1.164 + } 1.165 + } 1.166 +}; 1.167 + 1.168 +/** 1.169 + * Class that implements nsILoadContext. Use it as callbacks for channel when 1.170 + * test needs it. 1.171 + */ 1.172 +function LoadContextCallback(appId, inBrowserElement, isPrivate, isContent) { 1.173 + this.appId = appId; 1.174 + this.isInBrowserElement = inBrowserElement; 1.175 + this.usePrivateBrowsing = isPrivate; 1.176 + this.isContent = isContent; 1.177 +} 1.178 + 1.179 +LoadContextCallback.prototype = { 1.180 + associatedWindow: null, 1.181 + topWindow : null, 1.182 + isAppOfType: function(appType) { 1.183 + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; 1.184 + }, 1.185 + QueryInterface: function(iid) { 1.186 + if (iid == Ci.nsILoadContext || 1.187 + Ci.nsIInterfaceRequestor || 1.188 + Ci.nsISupports) { 1.189 + return this; 1.190 + } 1.191 + throw Components.results.NS_ERROR_NO_INTERFACE; 1.192 + }, 1.193 + getInterface: function(iid) { 1.194 + if (iid.equals(Ci.nsILoadContext)) 1.195 + return this; 1.196 + throw Components.results.NS_ERROR_NO_INTERFACE; 1.197 + }, 1.198 +}