|
1 // This file tests channel event sinks (bug 315598 et al) |
|
2 |
|
3 Cu.import("resource://testing-common/httpd.js"); |
|
4 |
|
5 XPCOMUtils.defineLazyGetter(this, "URL", function() { |
|
6 return "http://localhost:" + httpserv.identity.primaryPort; |
|
7 }); |
|
8 |
|
9 const sinkCID = Components.ID("{14aa4b81-e266-45cb-88f8-89595dece114}"); |
|
10 const sinkContract = "@mozilla.org/network/unittest/channeleventsink;1"; |
|
11 |
|
12 const categoryName = "net-channel-event-sinks"; |
|
13 |
|
14 /** |
|
15 * This object is both a factory and an nsIChannelEventSink implementation (so, it |
|
16 * is de-facto a service). It's also an interface requestor that gives out |
|
17 * itself when asked for nsIChannelEventSink. |
|
18 */ |
|
19 var eventsink = { |
|
20 QueryInterface: function eventsink_qi(iid) { |
|
21 if (iid.equals(Components.interfaces.nsISupports) || |
|
22 iid.equals(Components.interfaces.nsIFactory) || |
|
23 iid.equals(Components.interfaces.nsIChannelEventSink)) |
|
24 return this; |
|
25 throw Components.results.NS_ERROR_NO_INTERFACE; |
|
26 }, |
|
27 createInstance: function eventsink_ci(outer, iid) { |
|
28 if (outer) |
|
29 throw Components.results.NS_ERROR_NO_AGGREGATION; |
|
30 return this.QueryInterface(iid); |
|
31 }, |
|
32 lockFactory: function eventsink_lockf(lock) { |
|
33 throw Components.results.NS_ERROR_NOT_IMPLEMENTED; |
|
34 }, |
|
35 |
|
36 asyncOnChannelRedirect: function eventsink_onredir(oldChan, newChan, flags, callback) { |
|
37 // veto |
|
38 this.called = true; |
|
39 throw Components.results.NS_BINDING_ABORTED; |
|
40 }, |
|
41 |
|
42 getInterface: function eventsink_gi(iid) { |
|
43 if (iid.equals(Components.interfaces.nsIChannelEventSink)) |
|
44 return this; |
|
45 throw Components.results.NS_ERROR_NO_INTERFACE; |
|
46 }, |
|
47 |
|
48 called: false |
|
49 }; |
|
50 |
|
51 var listener = { |
|
52 expectSinkCall: true, |
|
53 |
|
54 onStartRequest: function test_onStartR(request, ctx) { |
|
55 try { |
|
56 // Commenting out this check pending resolution of bug 255119 |
|
57 //if (Components.isSuccessCode(request.status)) |
|
58 // do_throw("Channel should have a failure code!"); |
|
59 |
|
60 // The current URI must be the original URI, as all redirects have been |
|
61 // cancelled |
|
62 if (!(request instanceof Components.interfaces.nsIChannel) || |
|
63 !request.URI.equals(request.originalURI)) |
|
64 do_throw("Wrong URI: Is <" + request.URI.spec + ">, should be <" + |
|
65 request.originalURI.spec + ">"); |
|
66 |
|
67 if (request instanceof Components.interfaces.nsIHttpChannel) { |
|
68 // As we expect a blocked redirect, verify that we have a 3xx status |
|
69 do_check_eq(Math.floor(request.responseStatus / 100), 3); |
|
70 do_check_eq(request.requestSucceeded, false); |
|
71 } |
|
72 |
|
73 do_check_eq(eventsink.called, this.expectSinkCall); |
|
74 } catch (e) { |
|
75 do_throw("Unexpected exception: " + e); |
|
76 } |
|
77 |
|
78 throw Components.results.NS_ERROR_ABORT; |
|
79 }, |
|
80 |
|
81 onDataAvailable: function test_ODA() { |
|
82 do_throw("Should not get any data!"); |
|
83 }, |
|
84 |
|
85 onStopRequest: function test_onStopR(request, ctx, status) { |
|
86 if (this._iteration <= 2) { |
|
87 run_test_continued(); |
|
88 } else { |
|
89 do_test_pending(); |
|
90 httpserv.stop(do_test_finished); |
|
91 } |
|
92 do_test_finished(); |
|
93 }, |
|
94 |
|
95 _iteration: 1 |
|
96 }; |
|
97 |
|
98 function makeChan(url) { |
|
99 var ios = Components.classes["@mozilla.org/network/io-service;1"] |
|
100 .getService(Components.interfaces.nsIIOService); |
|
101 var chan = ios.newChannel(url, null, null) |
|
102 .QueryInterface(Components.interfaces.nsIHttpChannel); |
|
103 |
|
104 return chan; |
|
105 } |
|
106 |
|
107 var httpserv = null; |
|
108 |
|
109 function run_test() { |
|
110 httpserv = new HttpServer(); |
|
111 httpserv.registerPathHandler("/redirect", redirect); |
|
112 httpserv.registerPathHandler("/redirectfile", redirectfile); |
|
113 httpserv.start(-1); |
|
114 |
|
115 Components.manager.nsIComponentRegistrar.registerFactory(sinkCID, |
|
116 "Unit test Event sink", sinkContract, eventsink); |
|
117 |
|
118 // Step 1: Set the callbacks on the listener itself |
|
119 var chan = makeChan(URL + "/redirect"); |
|
120 chan.notificationCallbacks = eventsink; |
|
121 |
|
122 chan.asyncOpen(listener, null); |
|
123 |
|
124 do_test_pending(); |
|
125 } |
|
126 |
|
127 function run_test_continued() { |
|
128 eventsink.called = false; |
|
129 |
|
130 var catMan = Components.classes["@mozilla.org/categorymanager;1"] |
|
131 .getService(Components.interfaces.nsICategoryManager); |
|
132 |
|
133 var chan; |
|
134 if (listener._iteration == 1) { |
|
135 // Step 2: Category entry |
|
136 catMan.nsICategoryManager.addCategoryEntry(categoryName, "unit test", |
|
137 sinkContract, false, true); |
|
138 chan = makeChan(URL + "/redirect") |
|
139 } else { |
|
140 // Step 3: Global contract id |
|
141 catMan.nsICategoryManager.deleteCategoryEntry(categoryName, "unit test", |
|
142 false); |
|
143 listener.expectSinkCall = false; |
|
144 chan = makeChan(URL + "/redirectfile"); |
|
145 } |
|
146 |
|
147 listener._iteration++; |
|
148 chan.asyncOpen(listener, null); |
|
149 |
|
150 do_test_pending(); |
|
151 } |
|
152 |
|
153 // PATHS |
|
154 |
|
155 // /redirect |
|
156 function redirect(metadata, response) { |
|
157 response.setStatusLine(metadata.httpVersion, 301, "Moved Permanently"); |
|
158 response.setHeader("Location", |
|
159 "http://localhost:" + metadata.port + "/", |
|
160 false); |
|
161 |
|
162 var body = "Moved\n"; |
|
163 response.bodyOutputStream.write(body, body.length); |
|
164 } |
|
165 |
|
166 // /redirectfile |
|
167 function redirectfile(metadata, response) { |
|
168 response.setStatusLine(metadata.httpVersion, 301, "Moved Permanently"); |
|
169 response.setHeader("Content-Type", "text/plain", false); |
|
170 response.setHeader("Location", "file:///etc/", false); |
|
171 |
|
172 var body = "Attempted to move to a file URI, but failed.\n"; |
|
173 response.bodyOutputStream.write(body, body.length); |
|
174 } |