Commit 5b7c9e08 authored by jrw's avatar jrw Committed by Commit bot

Updated remoting.xhr API to use promises.

Removed access to the native XHR object used by the API.

This is a larger change than one might expect for two reasons: First,
because the native XHR object only allows the response content to be
retrieved while the onreadystatechange handler is executing, and
second, because the unit test for dns_blackhole_checker.js relied on
synchronous semantics which cannot be duplicated with promises because
when a promise is resolved, its "then" handlers are not called until
the next event cycle.

Review URL: https://codereview.chromium.org/1003433002

Cr-Commit-Position: refs/heads/master@{#321608}
parent c29919ce
......@@ -105,11 +105,11 @@ remoting.AppRemoting.prototype.start = function(connector, token) {
/** @type {remoting.AppRemoting} */
var that = this;
/** @param {XMLHttpRequest} xhr */
var parseAppHostResponse = function(xhr) {
if (xhr.status == 200) {
/** @param {!remoting.Xhr.Response} xhrResponse */
var parseAppHostResponse = function(xhrResponse) {
if (xhrResponse.status == 200) {
var response = /** @type {remoting.AppRemoting.AppHostResponse} */
(base.jsonParseSafe(xhr.responseText));
(base.jsonParseSafe(xhrResponse.getText()));
if (response &&
response.status &&
response.status == 'done' &&
......@@ -157,16 +157,16 @@ remoting.AppRemoting.prototype.start = function(connector, token) {
// TODO(garykac) Start using remoting.Error.fromHttpStatus once it has
// been updated to properly report 'unknown' errors (rather than
// reporting them as AUTHENTICATION_FAILED).
if (xhr.status == 0) {
if (xhrResponse.status == 0) {
that.handleError(new remoting.Error(
remoting.Error.Tag.NETWORK_FAILURE));
} else if (xhr.status == 401) {
} else if (xhrResponse.status == 401) {
that.handleError(new remoting.Error(
remoting.Error.Tag.AUTHENTICATION_FAILED));
} else if (xhr.status == 403) {
} else if (xhrResponse.status == 403) {
that.handleError(new remoting.Error(
remoting.Error.Tag.APP_NOT_AUTHORIZED));
} else if (xhr.status == 502 || xhr.status == 503) {
} else if (xhrResponse.status == 502 || xhrResponse.status == 503) {
that.handleError(new remoting.Error(
remoting.Error.Tag.SERVICE_UNAVAILABLE));
} else {
......@@ -175,12 +175,11 @@ remoting.AppRemoting.prototype.start = function(connector, token) {
}
};
remoting.xhr.start({
new remoting.Xhr({
method: 'POST',
url: that.runApplicationUrl(),
onDone: parseAppHostResponse,
oauthToken: token
});
}).start().then(parseAppHostResponse);
};
/**
......
......@@ -127,21 +127,19 @@ function onToken(token) {
'/applications/' + remoting.settings.getAppRemotingApplicationId() +
'/hosts/' + hostId +
'/reportIssue';
/** @param {XMLHttpRequest} xhr */
var onDone = function(xhr) {
if (xhr.status >= 200 && xhr.status < 300) {
var onDone = function(/** !remoting.Xhr.Response */ response) {
if (response.status >= 200 && response.status < 300) {
getUserInfo();
} else {
showError();
}
};
remoting.xhr.start({
new remoting.Xhr({
method: 'POST',
url: uri,
onDone: onDone,
jsonContent: body,
oauthToken: token
});
}).start().then(onDone);
} else {
getUserInfo();
}
......
......@@ -38,7 +38,7 @@ remoting.DnsBlackholeChecker = function(signalStrategy) {
/** @private */
this.blackholeState_ = BlackholeState.PENDING;
/** @private {?XMLHttpRequest} */
/** @private {?remoting.Xhr} */
this.xhr_ = null;
};
......@@ -85,11 +85,11 @@ remoting.DnsBlackholeChecker.prototype.connect = function(server,
this.signalStrategy_.connect(server, username, authToken);
this.xhr_ = remoting.xhr.start({
this.xhr_ = new remoting.Xhr({
method: 'GET',
url: remoting.DnsBlackholeChecker.URL_TO_REQUEST_,
onDone: this.onHttpRequestDone_.bind(this)
url: remoting.DnsBlackholeChecker.URL_TO_REQUEST_
});
this.xhr_.start().then(this.onHttpRequestDone_.bind(this));
};
remoting.DnsBlackholeChecker.prototype.getState = function() {
......@@ -153,12 +153,12 @@ remoting.DnsBlackholeChecker.prototype.onWrappedSignalStrategyStateChanged_ =
};
/**
* @param {XMLHttpRequest} xhr
* @param {!remoting.Xhr.Response} response
* @private
*/
remoting.DnsBlackholeChecker.prototype.onHttpRequestDone_ = function(xhr) {
remoting.DnsBlackholeChecker.prototype.onHttpRequestDone_ = function(response) {
this.xhr_ = null;
if (xhr.status >= 200 && xhr.status <= 299) {
if (response.status >= 200 && response.status <= 299) {
console.log("DNS blackhole check succeeded.");
this.blackholeState_ = BlackholeState.OPEN;
if (this.signalStrategy_.getState() ==
......@@ -166,14 +166,15 @@ remoting.DnsBlackholeChecker.prototype.onHttpRequestDone_ = function(xhr) {
this.setState_(remoting.SignalStrategy.State.CONNECTED);
}
} else {
console.error("DNS blackhole check failed: " + xhr.status + " " +
xhr.statusText + ". Response URL: " + xhr.responseURL +
". Response Text: " + xhr.responseText);
console.error("DNS blackhole check failed: " + response.status + " " +
response.statusText + ". Response URL: " +
response.url + ". Response Text: " +
response.getText());
this.blackholeState_ = BlackholeState.BLOCKED;
base.dispose(this.signalStrategy_);
this.setState_(remoting.SignalStrategy.State.FAILED);
}
}
};
/**
* @param {remoting.SignalStrategy.State} newState
......
......@@ -23,13 +23,15 @@ var checker = null;
/** @type {remoting.MockSignalStrategy} */
var signalStrategy = null;
var fakeXhrs;
/** @type {sinon.FakeXhr} */
var fakeXhr = null;
QUnit.module('dns_blackhole_checker', {
beforeEach: function(assert) {
fakeXhrs = [];
sinon.useFakeXMLHttpRequest().onCreate = function(xhr) {
fakeXhrs.push(xhr);
QUnit.equal(fakeXhr, null, 'exactly one XHR is issued');
fakeXhr = xhr;
};
onStateChange = sinon.spy();
......@@ -46,9 +48,8 @@ QUnit.module('dns_blackhole_checker', {
sinon.assert.calledWith(signalStrategy.connect, 'server', 'username',
'authToken');
assert.equal(fakeXhrs.length, 1, 'exactly one XHR is issued');
assert.equal(
fakeXhrs[0].url, remoting.DnsBlackholeChecker.URL_TO_REQUEST_,
fakeXhr.url, remoting.DnsBlackholeChecker.URL_TO_REQUEST_,
'the correct URL is requested');
},
afterEach: function() {
......@@ -59,112 +60,136 @@ QUnit.module('dns_blackhole_checker', {
onStateChange = null;
onIncomingStanzaCallback = null;
checker = null;
},
fakeXhr = null;
}
});
QUnit.test('success',
function(assert) {
fakeXhrs[0].respond(200);
sinon.assert.notCalled(onStateChange);
[
remoting.SignalStrategy.State.CONNECTING,
remoting.SignalStrategy.State.HANDSHAKE,
remoting.SignalStrategy.State.CONNECTED
].forEach(function(state) {
function checkState(state) {
signalStrategy.setStateForTesting(state);
sinon.assert.calledWith(onStateChange, state);
assert.equal(checker.getState(), state);
}
return base.SpyPromise.run(function() {
fakeXhr.respond(200);
}).then(function() {
sinon.assert.notCalled(onStateChange);
checkState(remoting.SignalStrategy.State.CONNECTING);
checkState(remoting.SignalStrategy.State.HANDSHAKE);
checkState(remoting.SignalStrategy.State.CONNECTED);
});
}
);
});
QUnit.test('http response after connected',
function(assert) {
[
remoting.SignalStrategy.State.CONNECTING,
remoting.SignalStrategy.State.HANDSHAKE,
].forEach(function(state) {
function checkState(state) {
signalStrategy.setStateForTesting(state);
sinon.assert.calledWith(onStateChange, state);
assert.equal(checker.getState(), state);
});
}
checkState(remoting.SignalStrategy.State.CONNECTING);
checkState(remoting.SignalStrategy.State.HANDSHAKE);
onStateChange.reset();
// Verify that DnsBlackholeChecker stays in HANDSHAKE state even if the
// signal strategy has connected.
signalStrategy.setStateForTesting(remoting.SignalStrategy.State.CONNECTED);
sinon.assert.notCalled(onStateChange);
return base.SpyPromise.run(function() {
signalStrategy.setStateForTesting(
remoting.SignalStrategy.State.CONNECTED);
}).then(function() {
sinon.assert.notCalled(onStateChange);
assert.equal(checker.getState(), remoting.SignalStrategy.State.HANDSHAKE);
// Verify that DnsBlackholeChecker goes to CONNECTED state after the
// the HTTP request has succeeded.
fakeXhrs[0].respond(200);
sinon.assert.calledWith(onStateChange,
remoting.SignalStrategy.State.CONNECTED);
}
);
// Verify that DnsBlackholeChecker goes to CONNECTED state after the
// the HTTP request has succeeded.
return base.SpyPromise.run(function() {
fakeXhr.respond(200);
});
}).then(function() {
sinon.assert.calledWith(onStateChange,
remoting.SignalStrategy.State.CONNECTED);
});
});
QUnit.test('connect failed',
function(assert) {
fakeXhrs[0].respond(200);
sinon.assert.notCalled(onStateChange);
[
remoting.SignalStrategy.State.CONNECTING,
remoting.SignalStrategy.State.FAILED
].forEach(function(state) {
function checkState(state) {
signalStrategy.setStateForTesting(state);
sinon.assert.calledWith(onStateChange, state);
};
return base.SpyPromise.run(function() {
fakeXhr.respond(200);
}).then(function() {
sinon.assert.notCalled(onStateChange);
checkState(remoting.SignalStrategy.State.CONNECTING);
checkState(remoting.SignalStrategy.State.FAILED);
});
}
);
});
QUnit.test('blocked',
function(assert) {
fakeXhrs[0].respond(400);
sinon.assert.calledWith(onStateChange,
remoting.SignalStrategy.State.FAILED);
function checkState(state) {
assert.equal(checker.getError().getTag(),
remoting.Error.Tag.NOT_AUTHORIZED);
onStateChange.reset();
[
remoting.SignalStrategy.State.CONNECTING,
remoting.SignalStrategy.State.HANDSHAKE,
remoting.SignalStrategy.State.CONNECTED
].forEach(function(state) {
onStateChange.reset();
signalStrategy.setStateForTesting(state);
sinon.assert.notCalled(onStateChange);
assert.equal(checker.getState(), remoting.SignalStrategy.State.FAILED);
assert.equal(checker.getState(),
checker.getState(),
remoting.SignalStrategy.State.FAILED,
'checker state is still FAILED');
};
return base.SpyPromise.run(function() {
fakeXhr.respond(400);
}).then(function() {
sinon.assert.calledWith(
onStateChange, remoting.SignalStrategy.State.FAILED);
assert.equal(
checker.getError().getTag(),
remoting.Error.Tag.NOT_AUTHORIZED,
'checker error is NOT_AUTHORIZED');
checkState(remoting.SignalStrategy.State.CONNECTING);
checkState(remoting.SignalStrategy.State.HANDSHAKE);
checkState(remoting.SignalStrategy.State.FAILED);
});
}
);
});
QUnit.test('blocked after connected',
function(assert) {
[
remoting.SignalStrategy.State.CONNECTING,
remoting.SignalStrategy.State.HANDSHAKE,
].forEach(function(state) {
function checkState(state) {
signalStrategy.setStateForTesting(state);
sinon.assert.calledWith(onStateChange, state);
assert.equal(checker.getState(), state);
});
};
checkState(remoting.SignalStrategy.State.CONNECTING);
checkState(remoting.SignalStrategy.State.HANDSHAKE);
onStateChange.reset();
// Verify that DnsBlackholeChecker stays in HANDSHAKE state even if the
// signal strategy has connected.
signalStrategy.setStateForTesting(remoting.SignalStrategy.State.CONNECTED);
sinon.assert.notCalled(onStateChange);
// Verify that DnsBlackholeChecker stays in HANDSHAKE state even
// if the signal strategy has connected.
return base.SpyPromise.run(function() {
signalStrategy.setStateForTesting(
remoting.SignalStrategy.State.CONNECTED);
}).then(function() {
sinon.assert.notCalled(onStateChange);
assert.equal(checker.getState(), remoting.SignalStrategy.State.HANDSHAKE);
// Verify that DnsBlackholeChecker goes to FAILED state after it gets the
// blocked HTTP response.
fakeXhrs[0].respond(400);
sinon.assert.calledWith(onStateChange,
remoting.SignalStrategy.State.FAILED);
// Verify that DnsBlackholeChecker goes to FAILED state after it
// gets the blocked HTTP response.
return base.SpyPromise.run(function() {
fakeXhr.respond(400);
});
}).then(function() {
sinon.assert.calledWith(onStateChange,
remoting.SignalStrategy.State.FAILED);
assert.ok(checker.getError().hasTag(remoting.Error.Tag.NOT_AUTHORIZED));
});
}
);
......
......@@ -234,14 +234,14 @@ remoting.HostController.prototype.start = function(hostPin, consent, onDone,
* @param {string} hostName
* @param {string} publicKey
* @param {string} privateKey
* @param {XMLHttpRequest} xhr
* @param {!remoting.Xhr.Response} response
*/
function onRegistered(
hostName, publicKey, privateKey, xhr) {
var success = (xhr.status == 200);
hostName, publicKey, privateKey, response) {
var success = (response.status == 200);
if (success) {
var result = base.jsonParseSafe(xhr.responseText);
var result = base.jsonParseSafe(response.getText());
if ('data' in result && 'authorizationCode' in result['data']) {
that.hostDaemonFacade_.getCredentialsFromAuthCode(
result['data']['authorizationCode'],
......@@ -260,8 +260,8 @@ remoting.HostController.prototype.start = function(hostPin, consent, onDone,
});
}
} else {
console.log('Failed to register the host. Status: ' + xhr.status +
' response: ' + xhr.responseText);
console.log('Failed to register the host. Status: ' + response.status +
' response: ' + response.getText());
onError(new remoting.Error(remoting.Error.Tag.REGISTRATION_FAILED));
}
}
......@@ -281,16 +281,15 @@ remoting.HostController.prototype.start = function(hostPin, consent, onDone,
publicKey: publicKey
} };
remoting.xhr.start({
new remoting.Xhr({
method: 'POST',
url: remoting.settings.DIRECTORY_API_BASE_URL + '/@me/hosts',
urlParams: {
hostClientId: hostClientId
},
onDone: onRegistered.bind(null, hostName, publicKey, privateKey),
jsonContent: newHostDetails,
oauthToken: oauthToken
});
}).start().then(onRegistered.bind(null, hostName, publicKey, privateKey));
}
/**
......
......@@ -28,17 +28,16 @@ remoting.HostListApiImpl = function() {
* @param {function(!remoting.Error):void} onError
*/
remoting.HostListApiImpl.prototype.get = function(onDone, onError) {
/** @type {function(XMLHttpRequest):void} */
/** @type {function(!remoting.Xhr.Response):void} */
var parseHostListResponse =
this.parseHostListResponse_.bind(this, onDone, onError);
/** @param {string} token */
var onToken = function(token) {
remoting.xhr.start({
new remoting.Xhr({
method: 'GET',
url: remoting.settings.DIRECTORY_API_BASE_URL + '/@me/hosts',
onDone: parseHostListResponse,
oauthToken: token
});
}).start().then(parseHostListResponse);
};
remoting.identity.getToken().then(onToken, remoting.Error.handler(onError));
};
......@@ -63,13 +62,12 @@ remoting.HostListApiImpl.prototype.put =
'publicKey': hostPublicKey
}
};
remoting.xhr.start({
new remoting.Xhr({
method: 'PUT',
url: remoting.settings.DIRECTORY_API_BASE_URL + '/@me/hosts/' + hostId,
onDone: remoting.xhr.defaultResponse(onDone, onError),
jsonContent: newHostDetails,
oauthToken: token
});
}).start().then(remoting.Xhr.defaultResponse(onDone, onError));
};
remoting.identity.getToken().then(onToken, remoting.Error.handler(onError));
};
......@@ -84,13 +82,12 @@ remoting.HostListApiImpl.prototype.put =
remoting.HostListApiImpl.prototype.remove = function(hostId, onDone, onError) {
/** @param {string} token */
var onToken = function(token) {
remoting.xhr.start({
new remoting.Xhr({
method: 'DELETE',
url: remoting.settings.DIRECTORY_API_BASE_URL + '/@me/hosts/' + hostId,
onDone: remoting.xhr.defaultResponse(onDone, onError,
[remoting.Error.Tag.NOT_FOUND]),
oauthToken: token
});
}).start().then(remoting.Xhr.defaultResponse(
onDone, onError, [remoting.Error.Tag.NOT_FOUND]));
};
remoting.identity.getToken().then(onToken, remoting.Error.handler(onError));
};
......@@ -102,19 +99,19 @@ remoting.HostListApiImpl.prototype.remove = function(hostId, onDone, onError) {
*
* @param {function(Array<remoting.Host>):void} onDone
* @param {function(!remoting.Error):void} onError
* @param {XMLHttpRequest} xhr
* @param {!remoting.Xhr.Response} response
* @private
*/
remoting.HostListApiImpl.prototype.parseHostListResponse_ =
function(onDone, onError, xhr) {
if (xhr.status == 200) {
var response = /** @type {{data: {items: Array}}} */
(base.jsonParseSafe(xhr.responseText));
if (!response || !response.data) {
function(onDone, onError, response) {
if (response.status == 200) {
var obj = /** @type {{data: {items: Array}}} */
(base.jsonParseSafe(response.getText()));
if (!obj || !obj.data) {
console.error('Invalid "hosts" response from server.');
onError(remoting.Error.unexpected());
} else {
var items = response.data.items || [];
var items = obj.data.items || [];
var hosts = items.map(
function(/** Object */ item) {
var host = new remoting.Host();
......@@ -134,7 +131,7 @@ remoting.HostListApiImpl.prototype.parseHostListResponse_ =
onDone(hosts);
}
} else {
onError(remoting.Error.fromHttpStatus(xhr.status));
onError(remoting.Error.fromHttpStatus(response.status));
}
};
......@@ -142,4 +139,3 @@ remoting.HostListApiImpl.prototype.parseHostListResponse_ =
remoting.hostListApi = new remoting.HostListApiImpl();
})();
......@@ -54,8 +54,8 @@ remoting.It2MeConnectFlow.prototype.connect_ = function(accessCode) {
return remoting.identity.getToken();
}).then(function(/** string */ token) {
return that.getHostInfo_(token);
}).then(function(/** XMLHttpRequest */ xhr) {
return that.onHostInfo_(xhr);
}).then(function(/** !remoting.Xhr.Response */ response) {
return that.onHostInfo_(response);
}).then(function(/** remoting.Host */ host) {
that.sessionConnector_.connect(
remoting.DesktopConnectedView.Mode.IT2ME,
......@@ -88,33 +88,31 @@ remoting.It2MeConnectFlow.prototype.verifyAccessCode_ = function(accessCode) {
* Continues an IT2Me connection once an access token has been obtained.
*
* @param {string} token An OAuth2 access token.
* @return {Promise<XMLHttpRequest>}
* @return {Promise<!remoting.Xhr.Response>}
* @private
*/
remoting.It2MeConnectFlow.prototype.getHostInfo_ = function(token) {
var that = this;
return new Promise(function(resolve) {
remoting.xhr.start({
method: 'GET',
url: remoting.settings.DIRECTORY_API_BASE_URL + '/support-hosts/' +
encodeURIComponent(that.hostId_),
onDone: resolve,
oauthToken: token
});
});
return new remoting.Xhr({
method: 'GET',
url: remoting.settings.DIRECTORY_API_BASE_URL + '/support-hosts/' +
encodeURIComponent(that.hostId_),
oauthToken: token
}).start();
};
/**
* Continues an IT2Me connection once the host JID has been looked up.
*
* @param {XMLHttpRequest} xhr The server response to the support-hosts query.
* @param {!remoting.Xhr.Response} xhrResponse The server response to the
* support-hosts query.
* @return {!Promise<!remoting.Host>} Rejects on error.
* @private
*/
remoting.It2MeConnectFlow.prototype.onHostInfo_ = function(xhr) {
if (xhr.status == 200) {
remoting.It2MeConnectFlow.prototype.onHostInfo_ = function(xhrResponse) {
if (xhrResponse.status == 200) {
var response = /** @type {{data: {jabberId: string, publicKey: string}}} */
(base.jsonParseSafe(xhr.responseText));
(base.jsonParseSafe(xhrResponse.getText()));
if (response && response.data &&
response.data.jabberId && response.data.publicKey) {
var host = new remoting.Host();
......@@ -128,11 +126,12 @@ remoting.It2MeConnectFlow.prototype.onHostInfo_ = function(xhr) {
return Promise.reject(remoting.Error.unexpected());
}
} else {
return Promise.reject(translateSupportHostsError(xhr.status));
return Promise.reject(translateSupportHostsError(xhrResponse.status));
}
};
/**
* TODO(jrw): Replace with remoting.Error.fromHttpStatus.
* @param {number} error An HTTP error code returned by the support-hosts
* endpoint.
* @return {remoting.Error} The equivalent remoting.Error code.
......
......@@ -250,7 +250,7 @@ remoting.OAuth2.prototype.onTokens_ =
remoting.OAuth2.prototype.getAuthorizationCode = function(onDone) {
var xsrf_token = base.generateXsrfToken();
var GET_CODE_URL = this.getOAuth2AuthEndpoint_() + '?' +
remoting.xhr.urlencodeParamHash({
remoting.Xhr.urlencodeParamHash({
'client_id': this.getClientId_(),
'redirect_uri': this.getRedirectUri_(),
'scope': this.SCOPE_,
......
......@@ -75,37 +75,36 @@ remoting.OAuth2ApiImpl.prototype.interpretXhrStatus_ =
*/
remoting.OAuth2ApiImpl.prototype.refreshAccessToken = function(
onDone, onError, clientId, clientSecret, refreshToken) {
/** @param {XMLHttpRequest} xhr */
var onResponse = function(xhr) {
if (xhr.status == 200) {
/** @param {!remoting.Xhr.Response} response */
var onResponse = function(response) {
if (response.status == 200) {
try {
// Don't use base.jsonParseSafe here unless you also include base.js,
// otherwise this won't work from the OAuth trampoline.
// TODO(jamiewalch): Fix this once we're no longer using the trampoline.
var tokens = JSON.parse(xhr.responseText);
var tokens = JSON.parse(response.getText());
onDone(tokens['access_token'], tokens['expires_in']);
} catch (/** @type {Error} */ err) {
console.error('Invalid "token" response from server:', err);
onError(remoting.Error.unexpected());
}
} else {
console.error('Failed to refresh token. Status: ' + xhr.status +
' response: ' + xhr.responseText);
onError(fromHttpStatus(xhr.status));
console.error('Failed to refresh token. Status: ' + response.status +
' response: ' + response.getText());
onError(remoting.Error.fromHttpStatus(response.status));
}
};
remoting.xhr.start({
new remoting.Xhr({
method: 'POST',
url: this.getOAuth2TokenEndpoint_(),
onDone: onResponse,
formContent: {
'client_id': clientId,
'client_secret': clientSecret,
'refresh_token': refreshToken,
'grant_type': 'refresh_token'
}
});
}).start().then(onResponse);
};
/**
......@@ -124,14 +123,14 @@ remoting.OAuth2ApiImpl.prototype.refreshAccessToken = function(
*/
remoting.OAuth2ApiImpl.prototype.exchangeCodeForTokens = function(
onDone, onError, clientId, clientSecret, code, redirectUri) {
/** @param {XMLHttpRequest} xhr */
var onResponse = function(xhr) {
if (xhr.status == 200) {
/** @param {!remoting.Xhr.Response} response */
var onResponse = function(response) {
if (response.status == 200) {
try {
// Don't use base.jsonParseSafe here unless you also include base.js,
// otherwise this won't work from the OAuth trampoline.
// TODO(jamiewalch): Fix this once we're no longer using the trampoline.
var tokens = JSON.parse(xhr.responseText);
var tokens = JSON.parse(response.getText());
onDone(tokens['refresh_token'],
tokens['access_token'], tokens['expires_in']);
} catch (/** @type {Error} */ err) {
......@@ -139,16 +138,15 @@ remoting.OAuth2ApiImpl.prototype.exchangeCodeForTokens = function(
onError(remoting.Error.unexpected());
}
} else {
console.error('Failed to exchange code for token. Status: ' + xhr.status +
' response: ' + xhr.responseText);
onError(fromHttpStatus(xhr.status));
console.error('Failed to exchange code for token. Status: ' +
response.status + ' response: ' + response.getText());
onError(remoting.Error.fromHttpStatus(response.status));
}
};
remoting.xhr.start({
new remoting.Xhr({
method: 'POST',
url: this.getOAuth2TokenEndpoint_(),
onDone: onResponse,
formContent: {
'client_id': clientId,
'client_secret': clientSecret,
......@@ -156,7 +154,7 @@ remoting.OAuth2ApiImpl.prototype.exchangeCodeForTokens = function(
'code': code,
'grant_type': 'authorization_code'
}
});
}).start().then(onResponse);
};
/**
......@@ -170,28 +168,27 @@ remoting.OAuth2ApiImpl.prototype.exchangeCodeForTokens = function(
* @return {void} Nothing.
*/
remoting.OAuth2ApiImpl.prototype.getEmail = function(onDone, onError, token) {
/** @param {XMLHttpRequest} xhr */
var onResponse = function(xhr) {
if (xhr.status == 200) {
/** @param {!remoting.Xhr.Response} response */
var onResponse = function(response) {
if (response.status == 200) {
try {
var result = JSON.parse(xhr.responseText);
var result = JSON.parse(response.getText());
onDone(result['email']);
} catch (/** @type {Error} */ err) {
console.error('Invalid "userinfo" response from server:', err);
onError(remoting.Error.unexpected());
}
} else {
console.error('Failed to get email. Status: ' + xhr.status +
' response: ' + xhr.responseText);
onError(fromHttpStatus(xhr.status));
console.error('Failed to get email. Status: ' + response.status +
' response: ' + response.getText());
onError(remoting.Error.fromHttpStatus(response.status));
}
};
remoting.xhr.start({
new remoting.Xhr({
method: 'GET',
url: this.getOAuth2ApiUserInfoEndpoint_(),
onDone: onResponse,
oauthToken: token
});
}).start().then(onResponse);
};
/**
......@@ -206,28 +203,27 @@ remoting.OAuth2ApiImpl.prototype.getEmail = function(onDone, onError, token) {
*/
remoting.OAuth2ApiImpl.prototype.getUserInfo =
function(onDone, onError, token) {
/** @param {XMLHttpRequest} xhr */
var onResponse = function(xhr) {
if (xhr.status == 200) {
/** @param {!remoting.Xhr.Response} response */
var onResponse = function(response) {
if (response.status == 200) {
try {
var result = JSON.parse(xhr.responseText);
var result = JSON.parse(response.getText());
onDone(result['email'], result['name']);
} catch (/** @type {Error} */ err) {
console.error('Invalid "userinfo" response from server:', err);
onError(remoting.Error.unexpected());
}
} else {
console.error('Failed to get user info. Status: ' + xhr.status +
' response: ' + xhr.responseText);
onError(fromHttpStatus(xhr.status));
console.error('Failed to get user info. Status: ' + response.status +
' response: ' + response.getText());
onError(remoting.Error.fromHttpStatus(response.status));
}
};
remoting.xhr.start({
new remoting.Xhr({
method: 'GET',
url: this.getOAuth2ApiUserInfoEndpoint_(),
onDone: onResponse,
oauthToken: token
});
}).start().then(onResponse);
};
/** @returns {!remoting.Error} */
......
......@@ -75,6 +75,9 @@ remoting.SessionConnectorImpl = function(clientContainer, onConnected, onError,
remoting.SessionConnectorImpl.prototype.resetConnection_ = function() {
this.closeSession();
// It's OK to initialize these member variables here because the
// constructor calls this method.
/** @private {remoting.Host} */
this.host_ = null;
......@@ -87,8 +90,6 @@ remoting.SessionConnectorImpl.prototype.resetConnection_ = function() {
/** @private {remoting.ClientSession} */
this.clientSession_ = null;
/** @private {XMLHttpRequest} */
this.pendingXhr_ = null;
/** @private {remoting.CredentialsProvider} */
this.credentialsProvider_ = null;
......
......@@ -132,7 +132,7 @@ remoting.ThirdPartyTokenFetcher.prototype.parseRedirectUrl_ =
* @private
*/
remoting.ThirdPartyTokenFetcher.prototype.getFullTokenUrl_ = function() {
return this.tokenUrl_ + '?' + remoting.xhr.urlencodeParamHash({
return this.tokenUrl_ + '?' + remoting.Xhr.urlencodeParamHash({
'redirect_uri': this.redirectUri_,
'scope': this.tokenScope_,
'client_id': this.hostPublicKey_,
......
This diff is collapsed.
This diff is collapsed.
......@@ -100,4 +100,4 @@ QUnit.module = function(desc, opt_args) {};
* @param {string} desc
* @param {function(QUnit.Assert)} f
*/
QUnit.test = function(desc, f) {};
\ No newline at end of file
QUnit.test = function(desc, f) {};
......@@ -126,3 +126,36 @@ sinon.TestStub.prototype.onFirstCall = function() {};
/** @returns {Object} */
sinon.createStubInstance = function (/** * */ constructor) {};
/** @return {sinon.FakeXhr} */
sinon.useFakeXMLHttpRequest = function() {};
/** @interface */
sinon.FakeXhr = function() {};
/** @type {string} */
sinon.FakeXhr.prototype.method;
/** @type {string} */
sinon.FakeXhr.prototype.url;
/** @type {boolean} */
sinon.FakeXhr.prototype.withCredentials;
/** @type {?string} */
sinon.FakeXhr.prototype.requestBody;
/** @type {!Object<string,string>} */
sinon.FakeXhr.prototype.requestHeaders;
/**
* @param {number} status
* @param {!Object<string,string>} headers
* @param {?string} content
*/
sinon.FakeXhr.prototype.respond;
/**
* @type {?function(!sinon.FakeXhr)}
*/
sinon.FakeXhr.prototype.onCreate;
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment