extensions/cookie/test/channel_utils.js

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

mercurial