Follow-on fix for bug 457825. Use sheet principal for agent and user sheets. r=dbaron...
[wine-gecko.git] / netwerk / test / unit / test_resumable_channel.js
blob9446b924597c0ad6e83939d54a0f373fdf9f7da8
1 /* Tests various aspects of nsIResumableChannel in combination with HTTP */
3 do_import_script("netwerk/test/httpserver/httpd.js");
5 var httpserver = null;
7 const NS_ERROR_ENTITY_CHANGED = 0x804b0020;
8 const NS_ERROR_NOT_RESUMABLE = 0x804b0019;
10 const rangeBody = "Body of the range request handler.\r\n";
12 function make_channel(url, callback, ctx) {
13 var ios = Cc["@mozilla.org/network/io-service;1"].
14 getService(Ci.nsIIOService);
15 return ios.newChannel(url, "", null);
18 function AuthPrompt2() {
21 AuthPrompt2.prototype = {
22 user: "guest",
23 pass: "guest",
25 QueryInterface: function authprompt2_qi(iid) {
26 if (iid.equals(Components.interfaces.nsISupports) ||
27 iid.equals(Components.interfaces.nsIAuthPrompt2))
28 return this;
29 throw Components.results.NS_ERROR_NO_INTERFACE;
32 promptAuth:
33 function ap2_promptAuth(channel, level, authInfo)
35 authInfo.username = this.user;
36 authInfo.password = this.pass;
37 return true;
40 asyncPromptAuth: function ap2_async(chan, cb, ctx, lvl, info) {
41 do_throw("not implemented yet")
45 function Requestor() {
48 Requestor.prototype = {
49 QueryInterface: function requestor_qi(iid) {
50 if (iid.equals(Components.interfaces.nsISupports) ||
51 iid.equals(Components.interfaces.nsIInterfaceRequestor))
52 return this;
53 throw Components.results.NS_ERROR_NO_INTERFACE;
56 getInterface: function requestor_gi(iid) {
57 if (iid.equals(Components.interfaces.nsIAuthPrompt2)) {
58 // Allow the prompt to store state by caching it here
59 if (!this.prompt2)
60 this.prompt2 = new AuthPrompt2();
61 return this.prompt2;
64 throw Components.results.NS_ERROR_NO_INTERFACE;
67 prompt2: null
70 function run_test() {
71 dump("*** run_test\n");
72 httpserver = new nsHttpServer();
73 httpserver.registerPathHandler("/auth", authHandler);
74 httpserver.registerPathHandler("/range", rangeHandler);
75 httpserver.registerPathHandler("/redir", redirHandler);
77 var entityID;
79 function get_entity_id(request, data, ctx) {
80 do_check_true(request instanceof Ci.nsIResumableChannel,
81 "must be a resumable channel");
82 entityID = request.entityID;
83 dump("*** entity id = " + entityID + "\n");
85 // Try a non-resumable URL (responds with 200)
86 var chan = make_channel("http://localhost:4444/");
87 chan.nsIResumableChannel.resumeAt(1, entityID);
88 chan.asyncOpen(new ChannelListener(try_resume, null, CL_EXPECT_FAILURE), null);
91 function try_resume(request, data, ctx) {
92 do_check_eq(request.status, NS_ERROR_NOT_RESUMABLE);
94 // Try a successful resume
95 var chan = make_channel("http://localhost:4444/range");
96 chan.nsIResumableChannel.resumeAt(1, entityID);
97 chan.asyncOpen(new ChannelListener(try_resume_zero, null), null);
100 function try_resume_zero(request, data, ctx) {
101 do_check_true(request.nsIHttpChannel.requestSucceeded);
102 do_check_eq(data, rangeBody.substring(1));
104 // Try a successful resume from 0
105 var chan = make_channel("http://localhost:4444/range");
106 chan.nsIResumableChannel.resumeAt(0, entityID);
107 chan.asyncOpen(new ChannelListener(success, null), null);
110 function success(request, data, ctx) {
111 do_check_true(request.nsIHttpChannel.requestSucceeded);
112 do_check_eq(data, rangeBody);
114 // Authentication (no password; working resume)
115 // (should not give us any data)
116 var chan = make_channel("http://localhost:4444/range");
117 chan.nsIResumableChannel.resumeAt(1, entityID);
118 chan.nsIHttpChannel.setRequestHeader("X-Need-Auth", "true", false);
119 chan.asyncOpen(new ChannelListener(test_auth_nopw, null, CL_EXPECT_FAILURE), null);
122 function test_auth_nopw(request, data, ctx) {
123 do_check_false(request.nsIHttpChannel.requestSucceeded);
124 do_check_eq(request.status, NS_ERROR_ENTITY_CHANGED);
126 // Authentication + not working resume
127 var chan = make_channel("http://localhost:4444/auth");
128 chan.nsIResumableChannel.resumeAt(1, entityID);
129 chan.notificationCallbacks = new Requestor();
130 chan.asyncOpen(new ChannelListener(test_auth, null, CL_EXPECT_FAILURE), null);
132 function test_auth(request, data, ctx) {
133 do_check_eq(request.status, NS_ERROR_NOT_RESUMABLE);
134 do_check_true(request.nsIHttpChannel.responseStatus < 300);
136 // Authentication + working resume
137 var chan = make_channel("http://localhost:4444/range");
138 chan.nsIResumableChannel.resumeAt(1, entityID);
139 chan.notificationCallbacks = new Requestor();
140 chan.nsIHttpChannel.setRequestHeader("X-Need-Auth", "true", false);
141 chan.asyncOpen(new ChannelListener(test_auth_resume, null), null);
144 function test_auth_resume(request, data, ctx) {
145 do_check_eq(data, rangeBody.substring(1));
146 do_check_true(request.nsIHttpChannel.requestSucceeded);
148 // 404 page (same content length as real content)
149 var chan = make_channel("http://localhost:4444/range");
150 chan.nsIResumableChannel.resumeAt(1, entityID);
151 chan.nsIHttpChannel.setRequestHeader("X-Want-404", "true", false);
152 chan.asyncOpen(new ChannelListener(test_404, null, CL_EXPECT_FAILURE), null);
155 function test_404(request, data, ctx) {
156 do_check_eq(request.status, NS_ERROR_ENTITY_CHANGED);
157 do_check_eq(request.nsIHttpChannel.responseStatus, 404);
159 // 416 Requested Range Not Satisfiable
160 var chan = make_channel("http://localhost:4444/range");
161 chan.nsIResumableChannel.resumeAt(1000, entityID);
162 chan.asyncOpen(new ChannelListener(test_416, null, CL_EXPECT_FAILURE), null);
165 function test_416(request, data, ctx) {
166 do_check_eq(request.status, NS_ERROR_ENTITY_CHANGED);
167 do_check_eq(request.nsIHttpChannel.responseStatus, 416);
169 // Redirect + successful resume
170 var chan = make_channel("http://localhost:4444/redir");
171 chan.nsIHttpChannel.setRequestHeader("X-Redir-To", "http://localhost:4444/range", false);
172 chan.nsIResumableChannel.resumeAt(1, entityID);
173 chan.asyncOpen(new ChannelListener(test_redir_resume, null), null);
176 function test_redir_resume(request, data, ctx) {
177 do_check_true(request.nsIHttpChannel.requestSucceeded);
178 do_check_eq(data, rangeBody.substring(1));
179 do_check_eq(request.nsIHttpChannel.responseStatus, 206);
181 // Redirect + failed resume
182 var chan = make_channel("http://localhost:4444/redir");
183 chan.nsIHttpChannel.setRequestHeader("X-Redir-To", "http://localhost:4444/", false);
184 chan.nsIResumableChannel.resumeAt(1, entityID);
185 chan.asyncOpen(new ChannelListener(test_redir_noresume, null, CL_EXPECT_FAILURE), null);
188 function test_redir_noresume(request, data, ctx) {
189 do_check_eq(request.status, NS_ERROR_NOT_RESUMABLE);
191 httpserver.stop();
192 do_test_finished();
195 httpserver.start(4444);
196 var chan = make_channel("http://localhost:4444/range");
197 chan.asyncOpen(new ChannelListener(get_entity_id, null), null);
198 do_test_pending();
201 // HANDLERS
203 function handleAuth(metadata, response) {
204 // btoa("guest:guest"), but that function is not available here
205 var expectedHeader = "Basic Z3Vlc3Q6Z3Vlc3Q=";
207 var body;
208 if (metadata.hasHeader("Authorization") &&
209 metadata.getHeader("Authorization") == expectedHeader)
211 response.setStatusLine(metadata.httpVersion, 200, "OK, authorized");
212 response.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
214 return true;
216 else
218 // didn't know guest:guest, failure
219 response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
220 response.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
222 return false;
226 // /auth
227 function authHandler(metadata, response) {
228 response.setHeader("Content-Type", "text/html", false);
229 body = handleAuth(metadata, response) ? "success" : "failure";
230 response.bodyOutputStream.write(body, body.length);
233 // /range
234 function rangeHandler(metadata, response) {
235 response.setHeader("Content-Type", "text/html", false);
237 if (metadata.hasHeader("X-Need-Auth")) {
238 if (!handleAuth(metadata, response)) {
239 body = "auth failed";
240 response.bodyOutputStream.write(body, body.length);
241 return;
245 if (metadata.hasHeader("X-Want-404")) {
246 response.setStatusLine(metadata.httpVersion, 404, "Not Found");
247 body = rangeBody;
248 response.bodyOutputStream.write(body, body.length);
249 return;
252 var body = rangeBody;
254 if (metadata.hasHeader("Range")) {
255 // Syntax: bytes=[from]-[to] (we don't support multiple ranges)
256 var matches = metadata.getHeader("Range").match(/^\s*bytes=(\d+)?-(\d+)?\s*$/);
257 var from = (matches[1] === undefined) ? 0 : matches[1];
258 var to = (matches[2] === undefined) ? rangeBody.length - 1 : matches[2];
259 if (from >= rangeBody.length) {
260 response.setStatusLine(metadata.httpVersion, 416, "Start pos too high");
261 response.setHeader("Content-Range", "*/" + rangeBody.length, false);
262 return;
264 body = body.substring(from, to + 1);
265 // always respond to successful range requests with 206
266 response.setStatusLine(metadata.httpVersion, 206, "Partial Content");
267 response.setHeader("Content-Range", from + "-" + to + "/" + rangeBody.length, false);
270 response.bodyOutputStream.write(body, body.length);
273 // /redir
274 function redirHandler(metadata, response) {
275 response.setStatusLine(metadata.httpVersion, 302, "Found");
276 response.setHeader("Content-Type", "text/html", false);
277 response.setHeader("Location", metadata.getHeader("X-Redir-To"), false);
278 var body = "redirect\r\n";
279 response.bodyOutputStream.write(body, body.length);