2 * Read count bytes from stream and return as a String object
4 function read_stream(stream
, count
) {
5 /* assume stream has non-ASCII data */
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. */
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!");
24 const CL_EXPECT_FAILURE
= 0x1;
25 const CL_EXPECT_GZIP
= 0x2;
28 * A stream listener that calls a callback function with a specified
29 * context and the received data when the channel is loaded.
31 * Signature of the closure:
32 * void closure(in nsIRequest request, in ACString data, in JSObject context);
34 * This listener makes sure that various parts of the channel API are
35 * implemented correctly and that the channel's status is a success code
36 * (you can pass CL_EXPECT_FAILURE as flags to allow a failure code)
38 * Note that it also requires a valid content length on the channel and
39 * is thus not fully generic.
41 function ChannelListener(closure
, ctx
, flags
) {
42 this._closure
= closure
;
43 this._closurectx
= ctx
;
46 ChannelListener
.prototype = {
50 _got_onstartrequest
: false,
51 _got_onstoprequest
: false,
54 QueryInterface: function(iid
) {
55 if (iid
.equals(Components
.interfaces
.nsIStreamListener
) ||
56 iid
.equals(Components
.interfaces
.nsIRequestObserver
) ||
57 iid
.equals(Components
.interfaces
.nsISupports
))
59 throw Components
.results
.NS_ERROR_NO_INTERFACE
;
62 onStartRequest: function(request
, context
) {
63 if (this._got_onstartrequest
)
64 do_throw("Got second onStartRequest event!");
65 this._got_onstartrequest
= true;
67 request
.QueryInterface(Components
.interfaces
.nsIChannel
);
68 this._contentLen
= request
.contentLength
;
69 if (this._contentLen
== -1)
70 do_throw("Content length is unknown in onStartRequest!");
73 onDataAvailable: function(request
, context
, stream
, offset
, count
) {
74 if (!this._got_onstartrequest
)
75 do_throw("onDataAvailable without onStartRequest event!");
76 if (this._got_onstoprequest
)
77 do_throw("onDataAvailable after onStopRequest event!");
78 if (!request
.isPending())
79 do_throw("request reports itself as not pending from onDataAvailable!");
80 if (this._flags
& CL_EXPECT_FAILURE
)
81 do_throw("Got data despite expecting a failure");
83 this._buffer
= this._buffer
.concat(read_stream(stream
, count
));
86 onStopRequest: function(request
, context
, status
) {
87 if (!this._got_onstartrequest
)
88 do_throw("onStopRequest without onStartRequest event!");
89 if (this._got_onstoprequest
)
90 do_throw("Got second onStopRequest event!");
91 this._got_onstoprequest
= true;
92 var success
= Components
.isSuccessCode(status
);
93 if ((this._flags
& CL_EXPECT_FAILURE
) && success
)
94 do_throw("Should have failed to load URL (status is " + status
.toString(16) + ")");
95 else if (!(this._flags
& CL_EXPECT_FAILURE
) && !success
)
96 do_throw("Failed to load URL: " + status
.toString(16));
97 if (status
!= request
.status
)
98 do_throw("request.status does not match status arg to onStopRequest!");
99 if (request
.isPending())
100 do_throw("request reports itself as pending from onStopRequest!");
101 if (!(this._flags
& CL_EXPECT_FAILURE
) &&
102 !(this._flags
& CL_EXPECT_GZIP
) &&
103 this._contentLen
!= -1)
104 do_check_eq(this._buffer
.length
, this._contentLen
)
106 this._closure(request
, this._buffer
, this._closurectx
);