mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-06-09 01:48:55 +00:00
286 lines
8.8 KiB
JavaScript
286 lines
8.8 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
Cu.import("resource://testing-common/httpd.js");
|
|
Cu.import("resource:///modules/readinglist/ServerClient.jsm");
|
|
Cu.import("resource://gre/modules/Log.jsm");
|
|
|
|
let appender = new Log.DumpAppender();
|
|
for (let logName of ["FirefoxAccounts", "readinglist.serverclient"]) {
|
|
Log.repository.getLogger(logName).addAppender(appender);
|
|
}
|
|
|
|
// Some test servers we use.
|
|
let Server = function(handlers) {
|
|
this._server = null;
|
|
this._handlers = handlers;
|
|
}
|
|
|
|
Server.prototype = {
|
|
start() {
|
|
this._server = new HttpServer();
|
|
for (let [path, handler] in Iterator(this._handlers)) {
|
|
// httpd.js seems to swallow exceptions
|
|
let thisHandler = handler;
|
|
let wrapper = (request, response) => {
|
|
try {
|
|
thisHandler(request, response);
|
|
} catch (ex) {
|
|
print("**** Handler for", path, "failed:", ex, ex.stack);
|
|
throw ex;
|
|
}
|
|
}
|
|
this._server.registerPathHandler(path, wrapper);
|
|
}
|
|
this._server.start(-1);
|
|
},
|
|
|
|
stop() {
|
|
return new Promise(resolve => {
|
|
this._server.stop(resolve);
|
|
this._server = null;
|
|
});
|
|
},
|
|
|
|
get host() {
|
|
return "http://localhost:" + this._server.identity.primaryPort;
|
|
},
|
|
};
|
|
|
|
// An OAuth server that hands out tokens.
|
|
function OAuthTokenServer() {
|
|
let server;
|
|
let handlers = {
|
|
"/v1/authorization": (request, response) => {
|
|
response.setStatusLine("1.1", 200, "OK");
|
|
let token = "token" + server.numTokenFetches;
|
|
print("Test OAuth server handing out token", token);
|
|
server.numTokenFetches += 1;
|
|
server.activeTokens.add(token);
|
|
response.write(JSON.stringify({access_token: token}));
|
|
},
|
|
"/v1/destroy": (request, response) => {
|
|
// Getting the body seems harder than it should be!
|
|
let sis = Cc["@mozilla.org/scriptableinputstream;1"]
|
|
.createInstance(Ci.nsIScriptableInputStream);
|
|
sis.init(request.bodyInputStream);
|
|
let body = JSON.parse(sis.read(sis.available()));
|
|
sis.close();
|
|
let token = body.token;
|
|
ok(server.activeTokens.delete(token));
|
|
print("after destroy have", server.activeTokens.size, "tokens left.")
|
|
response.setStatusLine("1.1", 200, "OK");
|
|
response.write('{}');
|
|
},
|
|
}
|
|
server = new Server(handlers);
|
|
server.numTokenFetches = 0;
|
|
server.activeTokens = new Set();
|
|
return server;
|
|
}
|
|
|
|
function promiseObserver(topic) {
|
|
return new Promise(resolve => {
|
|
function observe(subject, topic, data) {
|
|
Services.obs.removeObserver(observe, topic);
|
|
resolve(data);
|
|
}
|
|
Services.obs.addObserver(observe, topic, false);
|
|
});
|
|
}
|
|
|
|
// The tests.
|
|
function run_test() {
|
|
run_next_test();
|
|
}
|
|
|
|
// Arrange for the first token we hand out to be rejected - the client should
|
|
// notice the 401 and silently get a new token and retry the request.
|
|
add_task(function testAuthRetry() {
|
|
let handlers = {
|
|
"/v1/batch": (request, response) => {
|
|
// We know the first token we will get is "token0", so we simulate that
|
|
// "expiring" by only accepting "token1". Then we just echo the response
|
|
// back.
|
|
let authHeader;
|
|
try {
|
|
authHeader = request.getHeader("Authorization");
|
|
} catch (ex) {}
|
|
if (authHeader != "Bearer token1") {
|
|
response.setStatusLine("1.1", 401, "Unauthorized");
|
|
response.write("wrong token");
|
|
return;
|
|
}
|
|
response.setStatusLine("1.1", 200, "OK");
|
|
response.write(JSON.stringify({ok: true}));
|
|
}
|
|
};
|
|
let rlserver = new Server(handlers);
|
|
rlserver.start();
|
|
let authServer = OAuthTokenServer();
|
|
authServer.start();
|
|
try {
|
|
Services.prefs.setCharPref("readinglist.server", rlserver.host + "/v1");
|
|
Services.prefs.setCharPref("identity.fxaccounts.remote.oauth.uri", authServer.host + "/v1");
|
|
|
|
let fxa = yield createMockFxA();
|
|
let sc = new ServerClient(fxa);
|
|
|
|
let response = yield sc.request({
|
|
path: "/batch",
|
|
method: "post",
|
|
body: {foo: "bar"},
|
|
});
|
|
equal(response.status, 200, "got the 200 we expected");
|
|
equal(authServer.numTokenFetches, 2, "took 2 tokens to get the 200")
|
|
deepEqual(response.body, {ok: true});
|
|
} finally {
|
|
yield authServer.stop();
|
|
yield rlserver.stop();
|
|
}
|
|
});
|
|
|
|
// Check that specified headers are seen by the server, and that server headers
|
|
// in the response are seen by the client.
|
|
add_task(function testHeaders() {
|
|
let handlers = {
|
|
"/v1/batch": (request, response) => {
|
|
ok(request.hasHeader("x-foo"), "got our foo header");
|
|
equal(request.getHeader("x-foo"), "bar", "foo header has the correct value");
|
|
response.setHeader("Server-Sent-Header", "hello");
|
|
response.setStatusLine("1.1", 200, "OK");
|
|
response.write("{}");
|
|
}
|
|
};
|
|
let rlserver = new Server(handlers);
|
|
rlserver.start();
|
|
try {
|
|
Services.prefs.setCharPref("readinglist.server", rlserver.host + "/v1");
|
|
|
|
let fxa = yield createMockFxA();
|
|
let sc = new ServerClient(fxa);
|
|
sc._getToken = () => Promise.resolve();
|
|
|
|
let response = yield sc.request({
|
|
path: "/batch",
|
|
method: "post",
|
|
headers: {"X-Foo": "bar"},
|
|
body: {foo: "bar"}});
|
|
equal(response.status, 200, "got the 200 we expected");
|
|
equal(response.headers["server-sent-header"], "hello", "got the server header");
|
|
} finally {
|
|
yield rlserver.stop();
|
|
}
|
|
});
|
|
|
|
// Check that a "backoff" header causes the correct notification.
|
|
add_task(function testBackoffHeader() {
|
|
let handlers = {
|
|
"/v1/batch": (request, response) => {
|
|
response.setHeader("Backoff", "123");
|
|
response.setStatusLine("1.1", 200, "OK");
|
|
response.write("{}");
|
|
}
|
|
};
|
|
let rlserver = new Server(handlers);
|
|
rlserver.start();
|
|
|
|
let observerPromise = promiseObserver("readinglist:backoff-requested");
|
|
try {
|
|
Services.prefs.setCharPref("readinglist.server", rlserver.host + "/v1");
|
|
|
|
let fxa = yield createMockFxA();
|
|
let sc = new ServerClient(fxa);
|
|
sc._getToken = () => Promise.resolve();
|
|
|
|
let response = yield sc.request({
|
|
path: "/batch",
|
|
method: "post",
|
|
headers: {"X-Foo": "bar"},
|
|
body: {foo: "bar"}});
|
|
equal(response.status, 200, "got the 200 we expected");
|
|
let data = yield observerPromise;
|
|
equal(data, "123", "got the expected header value.")
|
|
} finally {
|
|
yield rlserver.stop();
|
|
}
|
|
});
|
|
|
|
// Check that a "backoff" header causes the correct notification.
|
|
add_task(function testRetryAfterHeader() {
|
|
let handlers = {
|
|
"/v1/batch": (request, response) => {
|
|
response.setHeader("Retry-After", "456");
|
|
response.setStatusLine("1.1", 500, "Not OK");
|
|
response.write("{}");
|
|
}
|
|
};
|
|
let rlserver = new Server(handlers);
|
|
rlserver.start();
|
|
|
|
let observerPromise = promiseObserver("readinglist:backoff-requested");
|
|
try {
|
|
Services.prefs.setCharPref("readinglist.server", rlserver.host + "/v1");
|
|
|
|
let fxa = yield createMockFxA();
|
|
let sc = new ServerClient(fxa);
|
|
sc._getToken = () => Promise.resolve();
|
|
|
|
let response = yield sc.request({
|
|
path: "/batch",
|
|
method: "post",
|
|
headers: {"X-Foo": "bar"},
|
|
body: {foo: "bar"}});
|
|
equal(response.status, 500, "got the 500 we expected");
|
|
let data = yield observerPromise;
|
|
equal(data, "456", "got the expected header value.")
|
|
} finally {
|
|
yield rlserver.stop();
|
|
}
|
|
});
|
|
|
|
// Check that unicode ends up as utf-8 in requests, and vice-versa in responses.
|
|
// (Note the ServerClient assumes all strings in and out are UCS, and thus have
|
|
// already been encoded/decoded (ie, it never expects to receive stuff already
|
|
// utf-8 encoded, and never returns utf-8 encoded responses.)
|
|
add_task(function testUTF8() {
|
|
let handlers = {
|
|
"/v1/hello": (request, response) => {
|
|
// Get the body as bytes.
|
|
let sis = Cc["@mozilla.org/scriptableinputstream;1"]
|
|
.createInstance(Ci.nsIScriptableInputStream);
|
|
sis.init(request.bodyInputStream);
|
|
let body = sis.read(sis.available());
|
|
sis.close();
|
|
// The client sent "{"copyright: "\xa9"} where \xa9 is the copyright symbol.
|
|
// It should have been encoded as utf-8 which is \xc2\xa9
|
|
equal(body, '{"copyright":"\xc2\xa9"}', "server saw utf-8 encoded data");
|
|
// and just write it back unchanged.
|
|
response.setStatusLine("1.1", 200, "OK");
|
|
response.write(body);
|
|
}
|
|
};
|
|
let rlserver = new Server(handlers);
|
|
rlserver.start();
|
|
try {
|
|
Services.prefs.setCharPref("readinglist.server", rlserver.host + "/v1");
|
|
|
|
let fxa = yield createMockFxA();
|
|
let sc = new ServerClient(fxa);
|
|
sc._getToken = () => Promise.resolve();
|
|
|
|
let body = {copyright: "\xa9"}; // see above - \xa9 is the copyright symbol
|
|
let response = yield sc.request({
|
|
path: "/hello",
|
|
method: "post",
|
|
body: body
|
|
});
|
|
equal(response.status, 200, "got the 200 we expected");
|
|
deepEqual(response.body, body);
|
|
} finally {
|
|
yield rlserver.stop();
|
|
}
|
|
});
|