1 // This file tests async handling of a channel suspended in DoAuthRetry
2 // notifying http-on-modify-request and http-on-before-connect observers.
5 const { HttpServer
} = ChromeUtils
.importESModule(
6 "resource://testing-common/httpd.sys.mjs"
9 ChromeUtils
.defineLazyGetter(this, "URL", function () {
10 return "http://localhost:" + httpserv
.identity
.primaryPort
;
13 var obs
= Services
.obs
;
15 var requestObserver
= null;
17 function AuthPrompt() {}
19 AuthPrompt
.prototype = {
23 QueryInterface
: ChromeUtils
.generateQI(["nsIAuthPrompt"]),
25 prompt
: function ap1_prompt() {
26 do_throw("unexpected prompt call");
29 promptUsernameAndPassword
: function promptUP(
37 user
.value
= this.user
;
40 obs
.addObserver(requestObserver
, "http-on-before-connect");
41 obs
.addObserver(requestObserver
, "http-on-modify-request");
45 promptPassword
: function promptPW() {
46 do_throw("unexpected promptPassword call");
50 function requestListenerObserver(
51 suspendOnBeforeConnect
,
52 suspendOnModifyRequest
54 this.suspendOnModifyRequest
= suspendOnModifyRequest
;
55 this.suspendOnBeforeConnect
= suspendOnBeforeConnect
;
58 requestListenerObserver
.prototype = {
59 suspendOnModifyRequest
: false,
60 suspendOnBeforeConnect
: false,
61 gotOnBeforeConnect
: false,
62 resumeOnBeforeConnect
: false,
63 gotOnModifyRequest
: false,
64 resumeOnModifyRequest
: false,
65 QueryInterface
: ChromeUtils
.generateQI(["nsIObserver"]),
67 observe(subject
, topic
) {
69 topic
=== "http-on-before-connect" &&
70 subject
instanceof Ci
.nsIHttpChannel
72 if (this.suspendOnBeforeConnect
) {
73 let chan
= subject
.QueryInterface(Ci
.nsIHttpChannel
);
75 this.resumeOnBeforeConnect
= true;
78 this.gotOnBeforeConnect
= true;
82 topic
=== "http-on-modify-request" &&
83 subject
instanceof Ci
.nsIHttpChannel
85 if (this.suspendOnModifyRequest
) {
86 let chan
= subject
.QueryInterface(Ci
.nsIHttpChannel
);
88 this.resumeOnModifyRequest
= true;
91 this.gotOnModifyRequest
= true;
98 function Requestor() {}
100 Requestor
.prototype = {
101 QueryInterface
: ChromeUtils
.generateQI(["nsIInterfaceRequestor"]),
103 getInterface
: function requestor_gi(iid
) {
104 if (iid
.equals(Ci
.nsIAuthPrompt
)) {
105 // Allow the prompt to store state by caching it here
107 this.prompt
= new AuthPrompt();
112 throw Components
.Exception("", Cr
.NS_ERROR_NO_INTERFACE
);
119 expectedCode
: -1, // Uninitialized
121 onStartRequest
: function test_onStartR(request
) {
123 if (!Components
.isSuccessCode(request
.status
)) {
124 do_throw("Channel should have a success code!");
127 if (!(request
instanceof Ci
.nsIHttpChannel
)) {
128 do_throw("Expecting an HTTP channel");
131 Assert
.equal(request
.responseStatus
, this.expectedCode
);
132 // The request should be succeeded iff we expect 200
133 Assert
.equal(request
.requestSucceeded
, this.expectedCode
== 200);
135 do_throw("Unexpected exception: " + e
);
137 throw Components
.Exception("", Cr
.NS_ERROR_ABORT
);
140 onDataAvailable
: function test_ODA() {
141 do_throw("Should not get any data!");
144 onStopRequest
: function test_onStopR(request
, status
) {
145 Assert
.equal(status
, Cr
.NS_ERROR_ABORT
);
146 if (requestObserver
.suspendOnBeforeConnect
) {
148 requestObserver
.gotOnBeforeConnect
&&
149 requestObserver
.resumeOnBeforeConnect
152 if (requestObserver
.suspendOnModifyRequest
) {
154 requestObserver
.gotOnModifyRequest
&&
155 requestObserver
.resumeOnModifyRequest
158 obs
.removeObserver(requestObserver
, "http-on-before-connect");
159 obs
.removeObserver(requestObserver
, "http-on-modify-request");
164 function makeChan(url
, loadingUrl
) {
165 var principal
= Services
.scriptSecurityManager
.createContentPrincipal(
166 Services
.io
.newURI(loadingUrl
),
169 return NetUtil
.newChannel({
171 loadingPrincipal
: principal
,
172 securityFlags
: Ci
.nsILoadInfo
.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL
,
173 contentPolicyType
: Ci
.nsIContentPolicy
.TYPE_OTHER
,
178 test_suspend_on_before_connect
,
179 test_suspend_on_modify_request
,
183 var current_test
= 0;
187 function moveToNextTest() {
188 if (current_test
< tests
.length
- 1) {
189 // First, gotta clear the auth cache
190 Cc
["@mozilla.org/network/http-auth-manager;1"]
191 .getService(Ci
.nsIHttpAuthManager
)
195 tests
[current_test
]();
198 httpserv
.stop(do_test_finished
);
204 function run_test() {
205 httpserv
= new HttpServer();
207 httpserv
.registerPathHandler("/auth", authHandler
);
214 function test_suspend_on_auth(suspendOnBeforeConnect
, suspendOnModifyRequest
) {
215 var chan
= makeChan(URL
+ "/auth", URL
);
216 requestObserver
= new requestListenerObserver(
217 suspendOnBeforeConnect
,
218 suspendOnModifyRequest
220 chan
.notificationCallbacks
= new Requestor();
221 listener
.expectedCode
= 200; // OK
222 chan
.asyncOpen(listener
);
227 function test_suspend_on_before_connect() {
228 test_suspend_on_auth(true, false);
231 function test_suspend_on_modify_request() {
232 test_suspend_on_auth(false, true);
235 function test_suspend_all() {
236 test_suspend_on_auth(true, true);
242 function authHandler(metadata
, response
) {
243 // btoa("guest:guest"), but that function is not available here
244 var expectedHeader
= "Basic Z3Vlc3Q6Z3Vlc3Q=";
248 metadata
.hasHeader("Authorization") &&
249 metadata
.getHeader("Authorization") == expectedHeader
251 response
.setStatusLine(metadata
.httpVersion
, 200, "OK, authorized");
252 response
.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
256 // didn't know guest:guest, failure
257 response
.setStatusLine(metadata
.httpVersion
, 401, "Unauthorized");
258 response
.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
263 response
.bodyOutputStream
.write(body
, body
.length
);