зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1388224 - Remove SyncStorageRequest HTTP wrapper class, which is no longer used r=kitcambridge
MozReview-Commit-ID: EgExfizNll5 --HG-- extra : rebase_source : 85a6098a5b985990bd3a8483936bf6cf768f1f0b
This commit is contained in:
Родитель
5db1dc8a9d
Коммит
4a77d5a93f
|
@ -778,13 +778,6 @@ this.BrowserIDManager.prototype = {
|
||||||
return this._getAuthenticationHeader.bind(this);
|
return this._getAuthenticationHeader.bind(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a function to be used for adding auth to RESTRequest instances.
|
|
||||||
*/
|
|
||||||
getRESTRequestAuthenticator() {
|
|
||||||
return this._addAuthenticationHeader.bind(this);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a Hawk HTTP Authorization Header, lightly wrapped, for the .uri
|
* @return a Hawk HTTP Authorization Header, lightly wrapped, for the .uri
|
||||||
* of a RESTRequest or AsyncResponse object.
|
* of a RESTRequest or AsyncResponse object.
|
||||||
|
@ -826,15 +819,6 @@ this.BrowserIDManager.prototype = {
|
||||||
return {headers: {authorization: headerValue.field}};
|
return {headers: {authorization: headerValue.field}};
|
||||||
},
|
},
|
||||||
|
|
||||||
_addAuthenticationHeader(request, method) {
|
|
||||||
let header = this._getAuthenticationHeader(request, method);
|
|
||||||
if (!header) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
request.setHeader("authorization", header.headers.authorization);
|
|
||||||
return request;
|
|
||||||
},
|
|
||||||
|
|
||||||
createClusterManager(service) {
|
createClusterManager(service) {
|
||||||
return new BrowserIDClusterManager(service);
|
return new BrowserIDClusterManager(service);
|
||||||
},
|
},
|
||||||
|
|
|
@ -125,12 +125,6 @@ ENGINE_APPLY_FAIL: "error.engine.reason.apply_fail",
|
||||||
// an upload failure where the batch was interrupted with a 412
|
// an upload failure where the batch was interrupted with a 412
|
||||||
ENGINE_BATCH_INTERRUPTED: "error.engine.reason.batch_interrupted",
|
ENGINE_BATCH_INTERRUPTED: "error.engine.reason.batch_interrupted",
|
||||||
|
|
||||||
// info types for Service.getStorageInfo
|
|
||||||
INFO_COLLECTIONS: "collections",
|
|
||||||
INFO_COLLECTION_USAGE: "collection_usage",
|
|
||||||
INFO_COLLECTION_COUNTS: "collection_counts",
|
|
||||||
INFO_QUOTA: "quota",
|
|
||||||
|
|
||||||
// Ways that a sync can be disabled (messages only to be printed in debug log)
|
// Ways that a sync can be disabled (messages only to be printed in debug log)
|
||||||
kSyncMasterPasswordLocked: "User elected to leave Master Password locked",
|
kSyncMasterPasswordLocked: "User elected to leave Master Password locked",
|
||||||
kSyncWeaveDisabled: "Weave is disabled",
|
kSyncWeaveDisabled: "Weave is disabled",
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|
||||||
|
|
||||||
Cu.import("resource://services-common/rest.js");
|
|
||||||
Cu.import("resource://services-sync/util.js");
|
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = ["SyncStorageRequest"];
|
|
||||||
|
|
||||||
const STORAGE_REQUEST_TIMEOUT = 5 * 60; // 5 minutes
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RESTRequest variant for use against a Sync storage server.
|
|
||||||
*/
|
|
||||||
this.SyncStorageRequest = function SyncStorageRequest(uri) {
|
|
||||||
RESTRequest.call(this, uri);
|
|
||||||
|
|
||||||
this.authenticator = null;
|
|
||||||
};
|
|
||||||
SyncStorageRequest.prototype = {
|
|
||||||
|
|
||||||
__proto__: RESTRequest.prototype,
|
|
||||||
|
|
||||||
_logName: "Sync.StorageRequest",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait 5 minutes before killing a request.
|
|
||||||
*/
|
|
||||||
timeout: STORAGE_REQUEST_TIMEOUT,
|
|
||||||
|
|
||||||
dispatch: function dispatch(method, data, onComplete, onProgress) {
|
|
||||||
// Compose a UA string fragment from the various available identifiers.
|
|
||||||
if (Svc.Prefs.get("sendVersionInfo", true)) {
|
|
||||||
this.setHeader("user-agent", Utils.userAgent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.authenticator) {
|
|
||||||
let result = this.authenticator(this, method);
|
|
||||||
if (result && result.headers) {
|
|
||||||
for (let [k, v] of Object.entries(result.headers)) {
|
|
||||||
this.setHeader(k, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this._log.debug("No authenticator found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return RESTRequest.prototype.dispatch.apply(this, arguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
onStartRequest: function onStartRequest(channel) {
|
|
||||||
RESTRequest.prototype.onStartRequest.call(this, channel);
|
|
||||||
if (this.status == this.ABORTED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let headers = this.response.headers;
|
|
||||||
// Save the latest server timestamp when possible.
|
|
||||||
if (headers["x-weave-timestamp"]) {
|
|
||||||
SyncStorageRequest.serverTime = parseFloat(headers["x-weave-timestamp"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a server-side safety valve to allow slowing down
|
|
||||||
// clients without hurting performance.
|
|
||||||
if (headers["x-weave-backoff"]) {
|
|
||||||
Svc.Obs.notify("weave:service:backoff:interval",
|
|
||||||
parseInt(headers["x-weave-backoff"], 10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.response.success && headers["x-weave-quota-remaining"]) {
|
|
||||||
Svc.Obs.notify("weave:service:quota:remaining",
|
|
||||||
parseInt(headers["x-weave-quota-remaining"], 10));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onStopRequest: function onStopRequest(channel, context, statusCode) {
|
|
||||||
if (this.status != this.ABORTED) {
|
|
||||||
let resp = this.response;
|
|
||||||
let contentLength = resp.headers ? resp.headers["content-length"] : "";
|
|
||||||
|
|
||||||
if (resp.success && contentLength &&
|
|
||||||
contentLength != resp.body.length) {
|
|
||||||
this._log.warn("The response body's length of: " + resp.body.length +
|
|
||||||
" doesn't match the header's content-length of: " +
|
|
||||||
contentLength + ".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RESTRequest.prototype.onStopRequest.apply(this, arguments);
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -30,7 +30,6 @@ Cu.import("resource://services-sync/main.js");
|
||||||
Cu.import("resource://services-sync/policies.js");
|
Cu.import("resource://services-sync/policies.js");
|
||||||
Cu.import("resource://services-sync/record.js");
|
Cu.import("resource://services-sync/record.js");
|
||||||
Cu.import("resource://services-sync/resource.js");
|
Cu.import("resource://services-sync/resource.js");
|
||||||
Cu.import("resource://services-sync/rest.js");
|
|
||||||
Cu.import("resource://services-sync/stages/enginesync.js");
|
Cu.import("resource://services-sync/stages/enginesync.js");
|
||||||
Cu.import("resource://services-sync/stages/declined.js");
|
Cu.import("resource://services-sync/stages/declined.js");
|
||||||
Cu.import("resource://services-sync/status.js");
|
Cu.import("resource://services-sync/status.js");
|
||||||
|
@ -63,11 +62,6 @@ function getEngineModules() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const STORAGE_INFO_TYPES = [INFO_COLLECTIONS,
|
|
||||||
INFO_COLLECTION_USAGE,
|
|
||||||
INFO_COLLECTION_COUNTS,
|
|
||||||
INFO_QUOTA];
|
|
||||||
|
|
||||||
// A unique identifier for this browser session. Used for logging so
|
// A unique identifier for this browser session. Used for logging so
|
||||||
// we can easily see whether 2 logs are in the same browser session or
|
// we can easily see whether 2 logs are in the same browser session or
|
||||||
// after the browser restarted.
|
// after the browser restarted.
|
||||||
|
@ -485,16 +479,6 @@ Sync11Service.prototype = {
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a SyncStorageRequest instance with authentication credentials.
|
|
||||||
*/
|
|
||||||
getStorageRequest: function getStorageRequest(url) {
|
|
||||||
let request = new SyncStorageRequest(url);
|
|
||||||
request.authenticator = this.identity.getRESTRequestAuthenticator();
|
|
||||||
|
|
||||||
return request;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the info fetch as part of a login or key fetch, or
|
* Perform the info fetch as part of a login or key fetch, or
|
||||||
* inside engine sync.
|
* inside engine sync.
|
||||||
|
@ -1377,53 +1361,6 @@ Sync11Service.prototype = {
|
||||||
})();
|
})();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch storage info from the server.
|
|
||||||
*
|
|
||||||
* @param type
|
|
||||||
* String specifying what info to fetch from the server. Must be one
|
|
||||||
* of the INFO_* values. See Sync Storage Server API spec for details.
|
|
||||||
* @param callback
|
|
||||||
* Callback function with signature (error, data) where `data' is
|
|
||||||
* the return value from the server already parsed as JSON.
|
|
||||||
*
|
|
||||||
* @return RESTRequest instance representing the request, allowing callers
|
|
||||||
* to cancel the request.
|
|
||||||
*/
|
|
||||||
getStorageInfo: function getStorageInfo(type, callback) {
|
|
||||||
if (STORAGE_INFO_TYPES.indexOf(type) == -1) {
|
|
||||||
throw new Error(`Invalid value for 'type': ${type}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
let info_type = "info/" + type;
|
|
||||||
this._log.trace("Retrieving '" + info_type + "'...");
|
|
||||||
let url = this.userBaseURL + info_type;
|
|
||||||
return this.getStorageRequest(url).get(function onComplete(error) {
|
|
||||||
// Note: 'this' is the request.
|
|
||||||
if (error) {
|
|
||||||
this._log.debug("Failed to retrieve '" + info_type + "'", error);
|
|
||||||
return callback(error);
|
|
||||||
}
|
|
||||||
if (this.response.status != 200) {
|
|
||||||
this._log.debug("Failed to retrieve '" + info_type +
|
|
||||||
"': server responded with HTTP" +
|
|
||||||
this.response.status);
|
|
||||||
return callback(this.response);
|
|
||||||
}
|
|
||||||
|
|
||||||
let result;
|
|
||||||
try {
|
|
||||||
result = JSON.parse(this.response.body);
|
|
||||||
} catch (ex) {
|
|
||||||
this._log.debug("Server returned invalid JSON for '" + info_type +
|
|
||||||
"': " + this.response.body);
|
|
||||||
return callback(ex);
|
|
||||||
}
|
|
||||||
this._log.trace("Successfully retrieved '" + info_type + "'.");
|
|
||||||
return callback(null, result);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
recordTelemetryEvent(object, method, value, extra = undefined) {
|
recordTelemetryEvent(object, method, value, extra = undefined) {
|
||||||
Svc.Obs.notify("weave:telemetry:event", { object, method, value, extra });
|
Svc.Obs.notify("weave:telemetry:event", { object, method, value, extra });
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,7 +32,6 @@ EXTRA_JS_MODULES['services-sync'] += [
|
||||||
'modules/policies.js',
|
'modules/policies.js',
|
||||||
'modules/record.js',
|
'modules/record.js',
|
||||||
'modules/resource.js',
|
'modules/resource.js',
|
||||||
'modules/rest.js',
|
|
||||||
'modules/service.js',
|
'modules/service.js',
|
||||||
'modules/status.js',
|
'modules/status.js',
|
||||||
'modules/SyncedTabs.jsm',
|
'modules/SyncedTabs.jsm',
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/FxAccounts.jsm");
|
Cu.import("resource://gre/modules/FxAccounts.jsm");
|
||||||
Cu.import("resource://services-sync/browserid_identity.js");
|
Cu.import("resource://services-sync/browserid_identity.js");
|
||||||
Cu.import("resource://services-sync/rest.js");
|
Cu.import("resource://services-sync/resource.js");
|
||||||
Cu.import("resource://services-sync/util.js");
|
Cu.import("resource://services-sync/util.js");
|
||||||
Cu.import("resource://services-common/utils.js");
|
Cu.import("resource://services-common/utils.js");
|
||||||
Cu.import("resource://services-crypto/utils.js");
|
Cu.import("resource://services-crypto/utils.js");
|
||||||
|
@ -169,21 +169,6 @@ add_test(function test_getResourceAuthenticator() {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
add_test(function test_getRESTRequestAuthenticator() {
|
|
||||||
_("BrowserIDManager supplies a REST Request Authenticator callback which sets a Hawk header on a request object.");
|
|
||||||
let request = new SyncStorageRequest(
|
|
||||||
"https://example.net/somewhere/over/the/rainbow");
|
|
||||||
let authenticator = globalBrowseridManager.getRESTRequestAuthenticator();
|
|
||||||
do_check_true(!!authenticator);
|
|
||||||
let output = authenticator(request, "GET");
|
|
||||||
do_check_eq(request.uri, output.uri);
|
|
||||||
do_check_true(output._headers.authorization.startsWith("Hawk"));
|
|
||||||
do_check_true(output._headers.authorization.includes("nonce"));
|
|
||||||
do_check_true(globalBrowseridManager.hasValidToken());
|
|
||||||
run_next_test();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
add_test(function test_resourceAuthenticatorSkew() {
|
add_test(function test_resourceAuthenticatorSkew() {
|
||||||
_("BrowserIDManager Resource Authenticator compensates for clock skew in Hawk header.");
|
_("BrowserIDManager Resource Authenticator compensates for clock skew in Hawk header.");
|
||||||
|
|
||||||
|
@ -242,7 +227,7 @@ add_test(function test_resourceAuthenticatorSkew() {
|
||||||
do_check_eq(browseridManager._fxaService.localtimeOffsetMsec,
|
do_check_eq(browseridManager._fxaService.localtimeOffsetMsec,
|
||||||
localtimeOffsetMsec);
|
localtimeOffsetMsec);
|
||||||
|
|
||||||
let request = new SyncStorageRequest("https://example.net/i/like/pie/");
|
let request = new Resource("https://example.net/i/like/pie/");
|
||||||
let authenticator = browseridManager.getResourceAuthenticator();
|
let authenticator = browseridManager.getResourceAuthenticator();
|
||||||
let output = authenticator(request, "GET");
|
let output = authenticator(request, "GET");
|
||||||
dump("output" + JSON.stringify(output));
|
dump("output" + JSON.stringify(output));
|
||||||
|
@ -289,7 +274,7 @@ add_test(function test_RESTResourceAuthenticatorSkew() {
|
||||||
|
|
||||||
do_check_eq(browseridManager._fxaService.internal.now(), now);
|
do_check_eq(browseridManager._fxaService.internal.now(), now);
|
||||||
|
|
||||||
let request = new SyncStorageRequest("https://example.net/i/like/pie/");
|
let request = new Resource("https://example.net/i/like/pie/");
|
||||||
let authenticator = browseridManager.getResourceAuthenticator();
|
let authenticator = browseridManager.getResourceAuthenticator();
|
||||||
let output = authenticator(request, "GET");
|
let output = authenticator(request, "GET");
|
||||||
dump("output" + JSON.stringify(output));
|
dump("output" + JSON.stringify(output));
|
||||||
|
|
|
@ -21,7 +21,6 @@ const modules = [
|
||||||
"policies.js",
|
"policies.js",
|
||||||
"record.js",
|
"record.js",
|
||||||
"resource.js",
|
"resource.js",
|
||||||
"rest.js",
|
|
||||||
"service.js",
|
"service.js",
|
||||||
"stages/declined.js",
|
"stages/declined.js",
|
||||||
"stages/enginesync.js",
|
"stages/enginesync.js",
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
||||||
|
|
||||||
Cu.import("resource://services-common/rest.js");
|
|
||||||
Cu.import("resource://services-sync/constants.js");
|
|
||||||
Cu.import("resource://services-sync/service.js");
|
|
||||||
Cu.import("resource://services-sync/util.js");
|
|
||||||
Cu.import("resource://testing-common/services/sync/utils.js");
|
|
||||||
|
|
||||||
var httpProtocolHandler = Cc["@mozilla.org/network/protocol;1?name=http"]
|
|
||||||
.getService(Ci.nsIHttpProtocolHandler);
|
|
||||||
|
|
||||||
var collections = {steam: 65.11328,
|
|
||||||
petrol: 82.488281,
|
|
||||||
diesel: 2.25488281};
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
|
|
||||||
Log.repository.getLogger("Sync.StorageRequest").level = Log.Level.Trace;
|
|
||||||
initTestLogging();
|
|
||||||
|
|
||||||
run_next_test();
|
|
||||||
}
|
|
||||||
|
|
||||||
add_task(async function test_success() {
|
|
||||||
let handler = httpd_handler(200, "OK", JSON.stringify(collections));
|
|
||||||
let server = httpd_setup({"/1.1/johndoe/info/collections": handler});
|
|
||||||
await configureIdentity({ username: "johndoe" }, server);
|
|
||||||
|
|
||||||
let request = Service.getStorageInfo("collections", function(error, info) {
|
|
||||||
do_check_eq(error, null);
|
|
||||||
do_check_true(Utils.deepEquals(info, collections));
|
|
||||||
|
|
||||||
// Ensure that the request is sent off with the right bits.
|
|
||||||
do_check_true(has_hawk_header(handler.request));
|
|
||||||
let expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
|
|
||||||
" (" + httpProtocolHandler.oscpu + ")" +
|
|
||||||
" FxSync/" + WEAVE_VERSION + "." +
|
|
||||||
Services.appinfo.appBuildID + ".desktop";
|
|
||||||
do_check_eq(handler.request.getHeader("User-Agent"), expectedUA);
|
|
||||||
|
|
||||||
server.stop(run_next_test);
|
|
||||||
});
|
|
||||||
do_check_true(request instanceof RESTRequest);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_test(function test_invalid_type() {
|
|
||||||
do_check_throws(function() {
|
|
||||||
Service.getStorageInfo("invalid", function(error, info) {
|
|
||||||
do_throw("Shouldn't get here!");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
run_next_test();
|
|
||||||
});
|
|
||||||
|
|
||||||
add_test(function test_network_error() {
|
|
||||||
Service.getStorageInfo(INFO_COLLECTIONS, function(error, info) {
|
|
||||||
do_check_eq(error.result, Cr.NS_ERROR_CONNECTION_REFUSED);
|
|
||||||
do_check_eq(info, null);
|
|
||||||
run_next_test();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_http_error() {
|
|
||||||
let handler = httpd_handler(500, "Oh noez", "Something went wrong!");
|
|
||||||
let server = httpd_setup({"/1.1/johndoe/info/collections": handler});
|
|
||||||
await configureIdentity({ username: "johndoe" }, server);
|
|
||||||
|
|
||||||
Service.getStorageInfo(INFO_COLLECTIONS, function(error, info) {
|
|
||||||
do_check_eq(error.status, 500);
|
|
||||||
do_check_eq(info, null);
|
|
||||||
server.stop(run_next_test);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_invalid_json() {
|
|
||||||
let handler = httpd_handler(200, "OK", "Invalid JSON");
|
|
||||||
let server = httpd_setup({"/1.1/johndoe/info/collections": handler});
|
|
||||||
await configureIdentity({ username: "johndoe" }, server);
|
|
||||||
|
|
||||||
Service.getStorageInfo(INFO_COLLECTIONS, function(error, info) {
|
|
||||||
do_check_eq(error.name, "SyntaxError");
|
|
||||||
do_check_eq(info, null);
|
|
||||||
server.stop(run_next_test);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,219 +0,0 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Log.jsm");
|
|
||||||
Cu.import("resource://services-common/utils.js");
|
|
||||||
Cu.import("resource://services-sync/constants.js");
|
|
||||||
Cu.import("resource://services-sync/rest.js");
|
|
||||||
Cu.import("resource://services-sync/service.js");
|
|
||||||
Cu.import("resource://services-sync/util.js");
|
|
||||||
Cu.import("resource://testing-common/services/sync/utils.js");
|
|
||||||
|
|
||||||
var httpProtocolHandler = Cc["@mozilla.org/network/protocol;1?name=http"]
|
|
||||||
.getService(Ci.nsIHttpProtocolHandler);
|
|
||||||
|
|
||||||
function run_test() {
|
|
||||||
Log.repository.getLogger("Sync.RESTRequest").level = Log.Level.Trace;
|
|
||||||
initTestLogging();
|
|
||||||
|
|
||||||
run_next_test();
|
|
||||||
}
|
|
||||||
|
|
||||||
add_test(function test_user_agent_desktop() {
|
|
||||||
let handler = httpd_handler(200, "OK");
|
|
||||||
let server = httpd_setup({"/resource": handler});
|
|
||||||
|
|
||||||
let expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
|
|
||||||
" (" + httpProtocolHandler.oscpu + ")" +
|
|
||||||
" FxSync/" + WEAVE_VERSION + "." +
|
|
||||||
Services.appinfo.appBuildID + ".desktop";
|
|
||||||
|
|
||||||
let request = new SyncStorageRequest(server.baseURI + "/resource");
|
|
||||||
request.onComplete = function onComplete(error) {
|
|
||||||
do_check_eq(error, null);
|
|
||||||
do_check_eq(this.response.status, 200);
|
|
||||||
do_check_eq(handler.request.getHeader("User-Agent"), expectedUA);
|
|
||||||
server.stop(run_next_test);
|
|
||||||
};
|
|
||||||
do_check_eq(request.get(), request);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_test(function test_user_agent_mobile() {
|
|
||||||
let handler = httpd_handler(200, "OK");
|
|
||||||
let server = httpd_setup({"/resource": handler});
|
|
||||||
|
|
||||||
Svc.Prefs.set("client.type", "mobile");
|
|
||||||
let expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
|
|
||||||
" (" + httpProtocolHandler.oscpu + ")" +
|
|
||||||
" FxSync/" + WEAVE_VERSION + "." +
|
|
||||||
Services.appinfo.appBuildID + ".mobile";
|
|
||||||
|
|
||||||
let request = new SyncStorageRequest(server.baseURI + "/resource");
|
|
||||||
request.get(function(error) {
|
|
||||||
do_check_eq(error, null);
|
|
||||||
do_check_eq(this.response.status, 200);
|
|
||||||
do_check_eq(handler.request.getHeader("User-Agent"), expectedUA);
|
|
||||||
Svc.Prefs.resetBranch("");
|
|
||||||
server.stop(run_next_test);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_auth() {
|
|
||||||
let handler = httpd_handler(200, "OK");
|
|
||||||
let server = httpd_setup({"/resource": handler});
|
|
||||||
await configureIdentity({ username: "foo" }, server);
|
|
||||||
|
|
||||||
let request = Service.getStorageRequest(server.baseURI + "/resource");
|
|
||||||
request.get(function(error) {
|
|
||||||
do_check_eq(error, null);
|
|
||||||
do_check_eq(this.response.status, 200);
|
|
||||||
do_check_true(has_hawk_header(handler.request));
|
|
||||||
|
|
||||||
Svc.Prefs.reset("");
|
|
||||||
|
|
||||||
server.stop(run_next_test);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The X-Weave-Timestamp header updates SyncStorageRequest.serverTime.
|
|
||||||
*/
|
|
||||||
add_test(function test_weave_timestamp() {
|
|
||||||
const TIMESTAMP = 1274380461;
|
|
||||||
function handler(request, response) {
|
|
||||||
response.setHeader("X-Weave-Timestamp", "" + TIMESTAMP, false);
|
|
||||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
|
||||||
}
|
|
||||||
let server = httpd_setup({"/resource": handler});
|
|
||||||
|
|
||||||
do_check_eq(SyncStorageRequest.serverTime, undefined);
|
|
||||||
let request = new SyncStorageRequest(server.baseURI + "/resource");
|
|
||||||
request.get(function(error) {
|
|
||||||
do_check_eq(error, null);
|
|
||||||
do_check_eq(this.response.status, 200);
|
|
||||||
do_check_eq(SyncStorageRequest.serverTime, TIMESTAMP);
|
|
||||||
delete SyncStorageRequest.serverTime;
|
|
||||||
server.stop(run_next_test);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The X-Weave-Backoff header notifies an observer.
|
|
||||||
*/
|
|
||||||
add_test(function test_weave_backoff() {
|
|
||||||
function handler(request, response) {
|
|
||||||
response.setHeader("X-Weave-Backoff", "600", false);
|
|
||||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
|
||||||
}
|
|
||||||
let server = httpd_setup({"/resource": handler});
|
|
||||||
|
|
||||||
let backoffInterval;
|
|
||||||
Svc.Obs.add("weave:service:backoff:interval", function onBackoff(subject) {
|
|
||||||
Svc.Obs.remove("weave:service:backoff:interval", onBackoff);
|
|
||||||
backoffInterval = subject;
|
|
||||||
});
|
|
||||||
|
|
||||||
let request = new SyncStorageRequest(server.baseURI + "/resource");
|
|
||||||
request.get(function(error) {
|
|
||||||
do_check_eq(error, null);
|
|
||||||
do_check_eq(this.response.status, 200);
|
|
||||||
do_check_eq(backoffInterval, 600);
|
|
||||||
server.stop(run_next_test);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* X-Weave-Quota-Remaining header notifies observer on successful requests.
|
|
||||||
*/
|
|
||||||
add_test(function test_weave_quota_notice() {
|
|
||||||
function handler(request, response) {
|
|
||||||
response.setHeader("X-Weave-Quota-Remaining", "1048576", false);
|
|
||||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
|
||||||
}
|
|
||||||
let server = httpd_setup({"/resource": handler});
|
|
||||||
|
|
||||||
let quotaValue;
|
|
||||||
Svc.Obs.add("weave:service:quota:remaining", function onQuota(subject) {
|
|
||||||
Svc.Obs.remove("weave:service:quota:remaining", onQuota);
|
|
||||||
quotaValue = subject;
|
|
||||||
});
|
|
||||||
|
|
||||||
let request = new SyncStorageRequest(server.baseURI + "/resource");
|
|
||||||
request.get(function(error) {
|
|
||||||
do_check_eq(error, null);
|
|
||||||
do_check_eq(this.response.status, 200);
|
|
||||||
do_check_eq(quotaValue, 1048576);
|
|
||||||
server.stop(run_next_test);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* X-Weave-Quota-Remaining header doesn't notify observer on failed requests.
|
|
||||||
*/
|
|
||||||
add_test(function test_weave_quota_error() {
|
|
||||||
function handler(request, response) {
|
|
||||||
response.setHeader("X-Weave-Quota-Remaining", "1048576", false);
|
|
||||||
response.setStatusLine(request.httpVersion, 400, "Bad Request");
|
|
||||||
}
|
|
||||||
let server = httpd_setup({"/resource": handler});
|
|
||||||
|
|
||||||
let quotaValue;
|
|
||||||
function onQuota(subject) {
|
|
||||||
quotaValue = subject;
|
|
||||||
}
|
|
||||||
Svc.Obs.add("weave:service:quota:remaining", onQuota);
|
|
||||||
|
|
||||||
let request = new SyncStorageRequest(server.baseURI + "/resource");
|
|
||||||
request.get(function(error) {
|
|
||||||
do_check_eq(error, null);
|
|
||||||
do_check_eq(this.response.status, 400);
|
|
||||||
do_check_eq(quotaValue, undefined);
|
|
||||||
Svc.Obs.remove("weave:service:quota:remaining", onQuota);
|
|
||||||
server.stop(run_next_test);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
add_test(function test_abort() {
|
|
||||||
const TIMESTAMP = 1274380462;
|
|
||||||
function handler(request, response) {
|
|
||||||
response.setHeader("X-Weave-Timestamp", "" + TIMESTAMP, false);
|
|
||||||
response.setHeader("X-Weave-Quota-Remaining", "1048576", false);
|
|
||||||
response.setHeader("X-Weave-Backoff", "600", false);
|
|
||||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
|
||||||
}
|
|
||||||
let server = httpd_setup({"/resource": handler});
|
|
||||||
|
|
||||||
let request = new SyncStorageRequest(server.baseURI + "/resource");
|
|
||||||
|
|
||||||
// Aborting a request that hasn't been sent yet is pointless and will throw.
|
|
||||||
do_check_throws(function() {
|
|
||||||
request.abort();
|
|
||||||
});
|
|
||||||
|
|
||||||
function throwy() {
|
|
||||||
do_throw("Shouldn't have gotten here!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Svc.Obs.add("weave:service:backoff:interval", throwy);
|
|
||||||
Svc.Obs.add("weave:service:quota:remaining", throwy);
|
|
||||||
request.onProgress = request.onComplete = throwy;
|
|
||||||
|
|
||||||
request.get();
|
|
||||||
request.abort();
|
|
||||||
do_check_eq(request.status, request.ABORTED);
|
|
||||||
|
|
||||||
// Aborting an already aborted request is pointless and will throw.
|
|
||||||
do_check_throws(function() {
|
|
||||||
request.abort();
|
|
||||||
});
|
|
||||||
|
|
||||||
CommonUtils.nextTick(function() {
|
|
||||||
// Verify that we didn't try to process any of the values.
|
|
||||||
do_check_eq(SyncStorageRequest.serverTime, undefined);
|
|
||||||
|
|
||||||
Svc.Obs.remove("weave:service:backoff:interval", throwy);
|
|
||||||
Svc.Obs.remove("weave:service:quota:remaining", throwy);
|
|
||||||
|
|
||||||
server.stop(run_next_test);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
Cu.import("resource://testing-common/httpd.js");
|
Cu.import("resource://testing-common/httpd.js");
|
||||||
Cu.import("resource://services-sync/resource.js");
|
Cu.import("resource://services-sync/resource.js");
|
||||||
Cu.import("resource://services-sync/rest.js");
|
|
||||||
|
|
||||||
function run_test() {
|
function run_test() {
|
||||||
initTestLogging("Trace");
|
initTestLogging("Trace");
|
||||||
|
@ -66,28 +65,3 @@ add_task(async function test_async_resource_logs_content_length_mismatch() {
|
||||||
notEqual(content.length, contentLength);
|
notEqual(content.length, contentLength);
|
||||||
await promiseStopServer(httpServer);
|
await promiseStopServer(httpServer);
|
||||||
});
|
});
|
||||||
|
|
||||||
add_test(function test_sync_storage_request_logs_content_length_mismatch() {
|
|
||||||
_("Issuing request.");
|
|
||||||
let httpServer = httpd_setup({"/content": contentHandler});
|
|
||||||
let request = new SyncStorageRequest(httpServer.baseURI + "/content");
|
|
||||||
let warnMessages = getWarningMessages(request._log);
|
|
||||||
|
|
||||||
// Setting this affects how received data is read from the underlying
|
|
||||||
// nsIHttpChannel in rest.js. If it's left as UTF-8 (the default) an
|
|
||||||
// nsIConverterInputStream is used and the data read from channel's stream
|
|
||||||
// isn't truncated at the null byte mark (\u0000). Therefore the
|
|
||||||
// content-length mismatch being tested for doesn't occur. Setting it to
|
|
||||||
// a falsy value results in an nsIScriptableInputStream being used to read
|
|
||||||
// the stream, which stops reading at the null byte mark resulting in a
|
|
||||||
// content-length mismatch.
|
|
||||||
request.charset = "";
|
|
||||||
|
|
||||||
request.get(function(error) {
|
|
||||||
equal(error, null);
|
|
||||||
equal(this.response.body, BODY);
|
|
||||||
notEqual(warnMessages.length, 0, "test that a warning was logged");
|
|
||||||
notEqual(BODY.length, contentLength);
|
|
||||||
httpServer.stop(run_next_test);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
|
@ -44,7 +44,6 @@ tags = addons
|
||||||
[test_resource.js]
|
[test_resource.js]
|
||||||
[test_resource_header.js]
|
[test_resource_header.js]
|
||||||
[test_resource_ua.js]
|
[test_resource_ua.js]
|
||||||
[test_syncstoragerequest.js]
|
|
||||||
|
|
||||||
# Generic Sync types.
|
# Generic Sync types.
|
||||||
[test_browserid_identity.js]
|
[test_browserid_identity.js]
|
||||||
|
@ -73,7 +72,6 @@ run-sequentially = Frequent timeouts, bug 1395148
|
||||||
skip-if = os == "mac" || os == "linux"
|
skip-if = os == "mac" || os == "linux"
|
||||||
[test_service_cluster.js]
|
[test_service_cluster.js]
|
||||||
[test_service_detect_upgrade.js]
|
[test_service_detect_upgrade.js]
|
||||||
[test_service_getStorageInfo.js]
|
|
||||||
[test_service_login.js]
|
[test_service_login.js]
|
||||||
[test_service_startOver.js]
|
[test_service_startOver.js]
|
||||||
[test_service_startup.js]
|
[test_service_startup.js]
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
"collection_repair.js": ["getRepairRequestor", "getAllRepairRequestors", "CollectionRepairRequestor", "getRepairResponder", "CollectionRepairResponder"],
|
"collection_repair.js": ["getRepairRequestor", "getAllRepairRequestors", "CollectionRepairRequestor", "getRepairResponder", "CollectionRepairResponder"],
|
||||||
"collection_validator.js": ["CollectionValidator", "CollectionProblemData"],
|
"collection_validator.js": ["CollectionValidator", "CollectionProblemData"],
|
||||||
"Console.jsm": ["console", "ConsoleAPI"],
|
"Console.jsm": ["console", "ConsoleAPI"],
|
||||||
"constants.js": ["WEAVE_VERSION", "SYNC_API_VERSION", "USER_API_VERSION", "MISC_API_VERSION", "STORAGE_VERSION", "PREFS_BRANCH", "PWDMGR_HOST", "PWDMGR_PASSWORD_REALM", "PWDMGR_PASSPHRASE_REALM", "PWDMGR_KEYBUNDLE_REALM", "DEFAULT_KEYBUNDLE_NAME", "HMAC_INPUT", "SYNC_KEY_ENCODED_LENGTH", "SYNC_KEY_DECODED_LENGTH", "SYNC_KEY_HYPHENATED_LENGTH", "NO_SYNC_NODE_INTERVAL", "MAX_ERROR_COUNT_BEFORE_BACKOFF", "MAX_IGNORE_ERROR_COUNT", "MINIMUM_BACKOFF_INTERVAL", "MAXIMUM_BACKOFF_INTERVAL", "HMAC_EVENT_INTERVAL", "MASTER_PASSWORD_LOCKED_RETRY_INTERVAL", "DEFAULT_BLOCK_PERIOD", "DEFAULT_GUID_FETCH_BATCH_SIZE", "DEFAULT_MOBILE_GUID_FETCH_BATCH_SIZE", "DEFAULT_STORE_BATCH_SIZE", "HISTORY_STORE_BATCH_SIZE", "FORMS_STORE_BATCH_SIZE", "PASSWORDS_STORE_BATCH_SIZE", "ADDONS_STORE_BATCH_SIZE", "APPS_STORE_BATCH_SIZE", "DEFAULT_DOWNLOAD_BATCH_SIZE", "DEFAULT_MAX_RECORD_PAYLOAD_BYTES", "SINGLE_USER_THRESHOLD", "MULTI_DEVICE_THRESHOLD", "SCORE_INCREMENT_SMALL", "SCORE_INCREMENT_MEDIUM", "SCORE_INCREMENT_XLARGE", "SCORE_UPDATE_DELAY", "IDLE_OBSERVER_BACK_DELAY", "URI_LENGTH_MAX", "MAX_HISTORY_UPLOAD", "MAX_HISTORY_DOWNLOAD", "STATUS_OK", "SYNC_FAILED", "LOGIN_FAILED", "SYNC_FAILED_PARTIAL", "CLIENT_NOT_CONFIGURED", "STATUS_DISABLED", "MASTER_PASSWORD_LOCKED", "LOGIN_SUCCEEDED", "SYNC_SUCCEEDED", "ENGINE_SUCCEEDED", "LOGIN_FAILED_NO_USERNAME", "LOGIN_FAILED_NO_PASSWORD", "LOGIN_FAILED_NO_PASSPHRASE", "LOGIN_FAILED_NETWORK_ERROR", "LOGIN_FAILED_SERVER_ERROR", "LOGIN_FAILED_INVALID_PASSPHRASE", "LOGIN_FAILED_LOGIN_REJECTED", "METARECORD_DOWNLOAD_FAIL", "VERSION_OUT_OF_DATE", "DESKTOP_VERSION_OUT_OF_DATE", "SETUP_FAILED_NO_PASSPHRASE", "CREDENTIALS_CHANGED", "ABORT_SYNC_COMMAND", "NO_SYNC_NODE_FOUND", "OVER_QUOTA", "PROLONGED_SYNC_FAILURE", "SERVER_MAINTENANCE", "RESPONSE_OVER_QUOTA", "ENGINE_UPLOAD_FAIL", "ENGINE_DOWNLOAD_FAIL", "ENGINE_UNKNOWN_FAIL", "ENGINE_APPLY_FAIL", "ENGINE_METARECORD_DOWNLOAD_FAIL", "ENGINE_METARECORD_UPLOAD_FAIL", "ENGINE_BATCH_INTERRUPTED", "JPAKE_ERROR_CHANNEL", "JPAKE_ERROR_NETWORK", "JPAKE_ERROR_SERVER", "JPAKE_ERROR_TIMEOUT", "JPAKE_ERROR_INTERNAL", "JPAKE_ERROR_INVALID", "JPAKE_ERROR_NODATA", "JPAKE_ERROR_KEYMISMATCH", "JPAKE_ERROR_WRONGMESSAGE", "JPAKE_ERROR_USERABORT", "JPAKE_ERROR_DELAYUNSUPPORTED", "INFO_COLLECTIONS", "INFO_COLLECTION_USAGE", "INFO_COLLECTION_COUNTS", "INFO_QUOTA", "kSyncNotConfigured", "kSyncMasterPasswordLocked", "kSyncWeaveDisabled", "kSyncNetworkOffline", "kSyncBackoffNotMet", "kFirstSyncChoiceNotMade", "FIREFOX_ID", "FENNEC_ID", "SEAMONKEY_ID", "TEST_HARNESS_ID", "MIN_PP_LENGTH", "MIN_PASS_LENGTH", "DEVICE_TYPE_DESKTOP", "DEVICE_TYPE_MOBILE", "SQLITE_MAX_VARIABLE_NUMBER"],
|
"constants.js": ["WEAVE_VERSION", "SYNC_API_VERSION", "USER_API_VERSION", "MISC_API_VERSION", "STORAGE_VERSION", "PREFS_BRANCH", "PWDMGR_HOST", "PWDMGR_PASSWORD_REALM", "PWDMGR_PASSPHRASE_REALM", "PWDMGR_KEYBUNDLE_REALM", "DEFAULT_KEYBUNDLE_NAME", "HMAC_INPUT", "SYNC_KEY_ENCODED_LENGTH", "SYNC_KEY_DECODED_LENGTH", "SYNC_KEY_HYPHENATED_LENGTH", "NO_SYNC_NODE_INTERVAL", "MAX_ERROR_COUNT_BEFORE_BACKOFF", "MAX_IGNORE_ERROR_COUNT", "MINIMUM_BACKOFF_INTERVAL", "MAXIMUM_BACKOFF_INTERVAL", "HMAC_EVENT_INTERVAL", "MASTER_PASSWORD_LOCKED_RETRY_INTERVAL", "DEFAULT_BLOCK_PERIOD", "DEFAULT_GUID_FETCH_BATCH_SIZE", "DEFAULT_MOBILE_GUID_FETCH_BATCH_SIZE", "DEFAULT_STORE_BATCH_SIZE", "HISTORY_STORE_BATCH_SIZE", "FORMS_STORE_BATCH_SIZE", "PASSWORDS_STORE_BATCH_SIZE", "ADDONS_STORE_BATCH_SIZE", "APPS_STORE_BATCH_SIZE", "DEFAULT_DOWNLOAD_BATCH_SIZE", "DEFAULT_MAX_RECORD_PAYLOAD_BYTES", "SINGLE_USER_THRESHOLD", "MULTI_DEVICE_THRESHOLD", "SCORE_INCREMENT_SMALL", "SCORE_INCREMENT_MEDIUM", "SCORE_INCREMENT_XLARGE", "SCORE_UPDATE_DELAY", "IDLE_OBSERVER_BACK_DELAY", "URI_LENGTH_MAX", "MAX_HISTORY_UPLOAD", "MAX_HISTORY_DOWNLOAD", "STATUS_OK", "SYNC_FAILED", "LOGIN_FAILED", "SYNC_FAILED_PARTIAL", "CLIENT_NOT_CONFIGURED", "STATUS_DISABLED", "MASTER_PASSWORD_LOCKED", "LOGIN_SUCCEEDED", "SYNC_SUCCEEDED", "ENGINE_SUCCEEDED", "LOGIN_FAILED_NO_USERNAME", "LOGIN_FAILED_NO_PASSWORD", "LOGIN_FAILED_NO_PASSPHRASE", "LOGIN_FAILED_NETWORK_ERROR", "LOGIN_FAILED_SERVER_ERROR", "LOGIN_FAILED_INVALID_PASSPHRASE", "LOGIN_FAILED_LOGIN_REJECTED", "METARECORD_DOWNLOAD_FAIL", "VERSION_OUT_OF_DATE", "DESKTOP_VERSION_OUT_OF_DATE", "SETUP_FAILED_NO_PASSPHRASE", "CREDENTIALS_CHANGED", "ABORT_SYNC_COMMAND", "NO_SYNC_NODE_FOUND", "OVER_QUOTA", "PROLONGED_SYNC_FAILURE", "SERVER_MAINTENANCE", "RESPONSE_OVER_QUOTA", "ENGINE_UPLOAD_FAIL", "ENGINE_DOWNLOAD_FAIL", "ENGINE_UNKNOWN_FAIL", "ENGINE_APPLY_FAIL", "ENGINE_METARECORD_DOWNLOAD_FAIL", "ENGINE_METARECORD_UPLOAD_FAIL", "ENGINE_BATCH_INTERRUPTED", "JPAKE_ERROR_CHANNEL", "JPAKE_ERROR_NETWORK", "JPAKE_ERROR_SERVER", "JPAKE_ERROR_TIMEOUT", "JPAKE_ERROR_INTERNAL", "JPAKE_ERROR_INVALID", "JPAKE_ERROR_NODATA", "JPAKE_ERROR_KEYMISMATCH", "JPAKE_ERROR_WRONGMESSAGE", "JPAKE_ERROR_USERABORT", "JPAKE_ERROR_DELAYUNSUPPORTED", "kSyncNotConfigured", "kSyncMasterPasswordLocked", "kSyncWeaveDisabled", "kSyncNetworkOffline", "kSyncBackoffNotMet", "kFirstSyncChoiceNotMade", "FIREFOX_ID", "FENNEC_ID", "SEAMONKEY_ID", "TEST_HARNESS_ID", "MIN_PP_LENGTH", "MIN_PASS_LENGTH", "DEVICE_TYPE_DESKTOP", "DEVICE_TYPE_MOBILE", "SQLITE_MAX_VARIABLE_NUMBER"],
|
||||||
"Constants.jsm": ["Roles", "Events", "Relations", "Filters", "States", "Prefilters"],
|
"Constants.jsm": ["Roles", "Events", "Relations", "Filters", "States", "Prefilters"],
|
||||||
"ContactDB.jsm": ["ContactDB", "DB_NAME", "STORE_NAME", "SAVED_GETALL_STORE_NAME", "REVISION_STORE", "DB_VERSION"],
|
"ContactDB.jsm": ["ContactDB", "DB_NAME", "STORE_NAME", "SAVED_GETALL_STORE_NAME", "REVISION_STORE", "DB_VERSION"],
|
||||||
"content-server.jsm": ["init"],
|
"content-server.jsm": ["init"],
|
||||||
|
@ -183,7 +183,7 @@
|
||||||
"RemotePageManager.jsm": ["RemotePages", "RemotePageManager", "PageListener"],
|
"RemotePageManager.jsm": ["RemotePages", "RemotePageManager", "PageListener"],
|
||||||
"RemoteWebProgress.jsm": ["RemoteWebProgressManager"],
|
"RemoteWebProgress.jsm": ["RemoteWebProgressManager"],
|
||||||
"resource.js": ["AsyncResource", "Resource"],
|
"resource.js": ["AsyncResource", "Resource"],
|
||||||
"rest.js": ["RESTRequest", "RESTResponse", "TokenAuthenticatedRESTRequest", "SyncStorageRequest"],
|
"rest.js": ["RESTRequest", "RESTResponse", "TokenAuthenticatedRESTRequest"],
|
||||||
"rotaryengine.js": ["RotaryEngine", "RotaryRecord", "RotaryStore", "RotaryTracker"],
|
"rotaryengine.js": ["RotaryEngine", "RotaryRecord", "RotaryStore", "RotaryTracker"],
|
||||||
"require.js": ["require"],
|
"require.js": ["require"],
|
||||||
"RTCStatsReport.jsm": ["convertToRTCStatsReport"],
|
"RTCStatsReport.jsm": ["convertToRTCStatsReport"],
|
||||||
|
|
Загрузка…
Ссылка в новой задаче