summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorsergeyu <sergeyu@chromium.org>2014-09-04 18:17:38 -0700
committerCommit bot <commit-bot@chromium.org>2014-09-05 01:19:13 +0000
commita55e1da00db331b8199a6a396fae7fc7a0ad715c (patch)
tree0506d91f978665851660046ab4394c8380ef4b8b /remoting
parente3f27656a03bda92753dfdb1cf9ef7243d366e94 (diff)
downloadchromium_src-a55e1da00db331b8199a6a396fae7fc7a0ad715c.zip
chromium_src-a55e1da00db331b8199a6a396fae7fc7a0ad715c.tar.gz
chromium_src-a55e1da00db331b8199a6a396fae7fc7a0ad715c.tar.bz2
Reduce number of roundtrips required in XMPP handshake
Previously XMPP handshake implemented in XmppLoginHandler required 7 roundtrips (excluding TLS handshake). With this change it will be sending each message as soon as possible without waiting response to the previous message. This effectivelly reduces number of required roundtrips to 3. BUG=274652 Review URL: https://codereview.chromium.org/534853002 Cr-Commit-Position: refs/heads/master@{#293389}
Diffstat (limited to 'remoting')
-rw-r--r--remoting/webapp/unittests/xmpp_login_handler_unittest.js94
-rw-r--r--remoting/webapp/xmpp_login_handler.js127
2 files changed, 112 insertions, 109 deletions
diff --git a/remoting/webapp/unittests/xmpp_login_handler_unittest.js b/remoting/webapp/unittests/xmpp_login_handler_unittest.js
index 339ceba..8a74652 100644
--- a/remoting/webapp/unittests/xmpp_login_handler_unittest.js
+++ b/remoting/webapp/unittests/xmpp_login_handler_unittest.js
@@ -38,20 +38,23 @@ function handshakeBase() {
sinon.assert.calledWith(
sendMessage,
'<stream:stream to="google.com" version="1.0" xmlns="jabber:client" ' +
- 'xmlns:stream="http://etherx.jabber.org/streams">');
+ 'xmlns:stream="http://etherx.jabber.org/streams">' +
+ '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>');
sendMessage.reset();
loginHandler.onDataReceived(base.encodeUtf8(
'<stream:stream from="google.com" id="78A87C70559EF28A" version="1.0" ' +
- 'xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client">' +
- '<stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls">' +
- '<required/></starttls><mechanisms ' +
- 'xmlns="urn:ietf:params:xml:ns:xmpp-sasl">' +
- '<mechanism>X-OAUTH2</mechanism><mechanism>X-GOOGLE-TOKEN</mechanism>' +
- '</mechanisms></stream:features>'));
- sinon.assert.calledWith(
- sendMessage, '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>');
- sendMessage.reset();
+ 'xmlns:stream="http://etherx.jabber.org/streams"' +
+ 'xmlns="jabber:client">' +
+ '<stream:features>' +
+ '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls">' +
+ '<required/>' +
+ '</starttls>' +
+ '<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">' +
+ '<mechanism>X-OAUTH2</mechanism>' +
+ '<mechanism>X-GOOGLE-TOKEN</mechanism>' +
+ '</mechanisms>' +
+ '</stream:features>'));
loginHandler.onDataReceived(
base.encodeUtf8('<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>'));
@@ -59,29 +62,30 @@ function handshakeBase() {
startTls.reset();
loginHandler.onTlsStarted();
- sinon.assert.calledWith(
- sendMessage,
- '<stream:stream to="google.com" version="1.0" xmlns="jabber:client" ' +
- 'xmlns:stream="http://etherx.jabber.org/streams">');
- sendMessage.reset();
-
- loginHandler.onDataReceived(base.encodeUtf8(
- '<stream:stream from="google.com" id="DCDDE5171CB2154A" version="1.0" ' +
- 'xmlns:stream="http://etherx.jabber.org/streams" ' +
- 'xmlns="jabber:client"><stream:features>' +
- '<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">' +
- '<mechanism>X-OAUTH2</mechanism><mechanism>X-GOOGLE-TOKEN</mechanism>' +
- '<mechanism>PLAIN</mechanism></mechanisms></stream:features>'));
var cookie = window.btoa("\0" + testUsername + "\0" + testToken);
sinon.assert.calledWith(
sendMessage,
+ '<stream:stream to="google.com" version="1.0" xmlns="jabber:client" ' +
+ 'xmlns:stream="http://etherx.jabber.org/streams">' +
'<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="X-OAUTH2" ' +
'auth:service="oauth2" auth:allow-generated-jid="true" ' +
'auth:client-uses-full-bind-result="true" ' +
'auth:allow-non-google-login="true" ' +
'xmlns:auth="http://www.google.com/talk/protocol/auth">' + cookie +
- '</auth>');
+ '</auth>');
sendMessage.reset();
+
+ loginHandler.onDataReceived(base.encodeUtf8(
+ '<stream:stream from="google.com" id="DCDDE5171CB2154A" version="1.0" ' +
+ 'xmlns:stream="http://etherx.jabber.org/streams" ' +
+ 'xmlns="jabber:client">' +
+ '<stream:features>' +
+ '<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">' +
+ '<mechanism>X-OAUTH2</mechanism>' +
+ '<mechanism>X-GOOGLE-TOKEN</mechanism>' +
+ '<mechanism>PLAIN</mechanism>' +
+ '</mechanisms>' +
+ '</stream:features>'));
}
test('should authenticate', function() {
@@ -92,32 +96,32 @@ test('should authenticate', function() {
sinon.assert.calledWith(
sendMessage,
'<stream:stream to="google.com" version="1.0" xmlns="jabber:client" ' +
- 'xmlns:stream="http://etherx.jabber.org/streams">');
+ 'xmlns:stream="http://etherx.jabber.org/streams">' +
+ '<iq type="set" id="0">' +
+ '<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">' +
+ '<resource>chromoting</resource>' +
+ '</bind>' +
+ '</iq>' +
+ '<iq type="set" id="1">' +
+ '<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>' +
+ '</iq>');
sendMessage.reset();
loginHandler.onDataReceived(base.encodeUtf8(
'<stream:stream from="google.com" id="104FA10576E2AA80" version="1.0" ' +
- 'xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client">' +
- '<stream:features><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/>' +
- '<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>' +
- '</stream:features>'));
- sinon.assert.calledWith(
- sendMessage,
- '<iq type="set" id="0"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">' +
- '<resource>chromoting</resource></bind></iq>');
- sendMessage.reset();
-
- loginHandler.onDataReceived(
- base.encodeUtf8('<iq id="0" type="result">' +
- '<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>' +
- testUsername + '/chromoting52B4920E</jid></bind></iq>'));
- sinon.assert.calledWith(
- sendMessage,
- '<iq type="set" id="1"><session ' +
- 'xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>');
- sendMessage.reset();
+ 'xmlns:stream="http://etherx.jabber.org/streams" ' +
+ 'xmlns="jabber:client">' +
+ '<stream:features>' +
+ '<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/>' +
+ '<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>' +
+ '</stream:features>' +
+ '<iq id="0" type="result">' +
+ '<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">' +
+ '<jid>' + testUsername + '/chromoting52B4920E</jid>' +
+ '</bind>' +
+ '</iq>' +
+ '<iq type="result" id="1"/>'));
- loginHandler.onDataReceived(base.encodeUtf8('<iq type="result" id="1"/>'));
sinon.assert.calledWith(onHandshakeDone);
});
diff --git a/remoting/webapp/xmpp_login_handler.js b/remoting/webapp/xmpp_login_handler.js
index bddc48e..f2034f4 100644
--- a/remoting/webapp/xmpp_login_handler.js
+++ b/remoting/webapp/xmpp_login_handler.js
@@ -66,53 +66,53 @@ remoting.XmppLoginHandler = function(server,
*
* Following messages are sent/received in each state:
* INIT
- * client -> server: Stream header
- * START_SENT
- * client <- server: Stream header with list of supported features which
- * should include starttls.
- * client -> server: <starttls>
- * STARTTLS_SENT
- * client <- server: <proceed>
+ * client -> server: Stream header
+ * client -> server: <starttls>
+ * WAIT_STREAM_HEADER
+ * client <- server: Stream header with list of supported features which
+ * should include starttls.
+ * WAIT_STARTTLS_RESPONSE
+ * client <- server: <proceed>
* STARTING_TLS
* TLS handshake
* client -> server: Stream header
- * START_SENT_AFTER_TLS
+ * client -> server: <auth> message with the OAuth2 token.
+ * WAIT_STREAM_HEADER_AFTER_TLS
* client <- server: Stream header with list of supported authentication
* methods which is expected to include X-OAUTH2
- * client -> server: <auth> message with the OAuth2 token.
- * AUTH_SENT
+ * WAIT_AUTH_RESULT
* client <- server: <success> or <failure>
* client -> server: Stream header
- * AUTH_ACCEPTED
+ * client -> server: <bind>
+ * client -> server: <iq><session/></iq> to start the session
+ * WAIT_STREAM_HEADER_AFTER_AUTH
* client <- server: Stream header with list of features that should
* include <bind>.
- * client -> server: <bind>
- * BIND_SENT
+ * WAIT_BIND_RESULT
* client <- server: <bind> result with JID.
- * client -> server: <iq><session/></iq> to start the session
- * SESSION_IQ_SENT
- * client <- server: iq result
+ * WAIT_SESSION_IQ_RESULT
+ * client <- server: result for <iq><session/></iq>
* DONE
*
* @enum {number}
*/
remoting.XmppLoginHandler.State = {
INIT: 0,
- START_SENT: 1,
- STARTTLS_SENT: 2,
+ WAIT_STREAM_HEADER: 1,
+ WAIT_STARTTLS_RESPONSE: 2,
STARTING_TLS: 3,
- START_SENT_AFTER_TLS: 4,
- AUTH_SENT: 5,
- AUTH_ACCEPTED: 6,
- BIND_SENT: 7,
- SESSION_IQ_SENT: 8,
+ WAIT_STREAM_HEADER_AFTER_TLS: 4,
+ WAIT_AUTH_RESULT: 5,
+ WAIT_STREAM_HEADER_AFTER_AUTH: 6,
+ WAIT_BIND_RESULT: 7,
+ WAIT_SESSION_IQ_RESULT: 8,
DONE: 9,
ERROR: 10
};
remoting.XmppLoginHandler.prototype.start = function() {
- this.state_ = remoting.XmppLoginHandler.State.START_SENT;
- this.startStream_();
+ this.state_ = remoting.XmppLoginHandler.State.WAIT_STREAM_HEADER;
+ this.startStream_('<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>');
}
/** @param {ArrayBuffer} data */
@@ -130,17 +130,15 @@ remoting.XmppLoginHandler.prototype.onDataReceived = function(data) {
*/
remoting.XmppLoginHandler.prototype.onStanza_ = function(stanza) {
switch (this.state_) {
- case remoting.XmppLoginHandler.State.START_SENT:
+ case remoting.XmppLoginHandler.State.WAIT_STREAM_HEADER:
if (stanza.querySelector('features>starttls')) {
- this.sendMessageCallback_(
- '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>');
- this.state_ = remoting.XmppLoginHandler.State.STARTTLS_SENT;
+ this.state_ = remoting.XmppLoginHandler.State.WAIT_STARTTLS_RESPONSE;
} else {
this.onError_(remoting.Error.UNEXPECTED, "Server doesn't support TLS.");
}
break;
- case remoting.XmppLoginHandler.State.STARTTLS_SENT:
+ case remoting.XmppLoginHandler.State.WAIT_STARTTLS_RESPONSE:
if (stanza.localName == "proceed") {
this.state_ = remoting.XmppLoginHandler.State.STARTING_TLS;
this.startTlsCallback_();
@@ -151,7 +149,7 @@ remoting.XmppLoginHandler.prototype.onStanza_ = function(stanza) {
}
break;
- case remoting.XmppLoginHandler.State.START_SENT_AFTER_TLS:
+ case remoting.XmppLoginHandler.State.WAIT_STREAM_HEADER_AFTER_TLS:
var mechanisms = Array.prototype.map.call(
stanza.querySelectorAll('features>mechanisms>mechanism'),
/** @param {Element} m */
@@ -162,24 +160,23 @@ remoting.XmppLoginHandler.prototype.onStanza_ = function(stanza) {
return;
}
- var cookie = window.btoa("\0" + this.username_ + "\0" + this.authToken_);
+ this.state_ = remoting.XmppLoginHandler.State.WAIT_AUTH_RESULT;
- this.state_ = remoting.XmppLoginHandler.State.AUTH_SENT;
- this.sendMessageCallback_(
- '<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" ' +
- 'mechanism="X-OAUTH2" auth:service="oauth2" ' +
- 'auth:allow-generated-jid="true" ' +
- 'auth:client-uses-full-bind-result="true" ' +
- 'auth:allow-non-google-login="true" ' +
- 'xmlns:auth="http://www.google.com/talk/protocol/auth">' +
- cookie +
- '</auth>');
break;
- case remoting.XmppLoginHandler.State.AUTH_SENT:
+ case remoting.XmppLoginHandler.State.WAIT_AUTH_RESULT:
if (stanza.localName == 'success') {
- this.state_ = remoting.XmppLoginHandler.State.AUTH_ACCEPTED;
- this.startStream_();
+ this.state_ =
+ remoting.XmppLoginHandler.State.WAIT_STREAM_HEADER_AFTER_AUTH;
+ this.startStream_(
+ '<iq type="set" id="0">' +
+ '<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">' +
+ '<resource>chromoting</resource>'+
+ '</bind>' +
+ '</iq>' +
+ '<iq type="set" id="1">' +
+ '<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>' +
+ '</iq>');
} else {
this.onError_(remoting.Error.AUTHENTICATION_FAILED,
'Failed to authenticate: ' +
@@ -187,22 +184,16 @@ remoting.XmppLoginHandler.prototype.onStanza_ = function(stanza) {
}
break;
- case remoting.XmppLoginHandler.State.AUTH_ACCEPTED:
+ case remoting.XmppLoginHandler.State.WAIT_STREAM_HEADER_AFTER_AUTH:
if (stanza.querySelector('features>bind')) {
- this.sendMessageCallback_(
- '<iq type="set" id="0">' +
- '<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">' +
- '<resource>chromoting</resource>'+
- '</bind>' +
- '</iq>');
- this.state_ = remoting.XmppLoginHandler.State.BIND_SENT;
+ this.state_ = remoting.XmppLoginHandler.State.WAIT_BIND_RESULT;
} else {
this.onError_(remoting.Error.UNEXPECTED,
"Server doesn't support bind after authentication.");
}
break;
- case remoting.XmppLoginHandler.State.BIND_SENT:
+ case remoting.XmppLoginHandler.State.WAIT_BIND_RESULT:
var jidElement = stanza.querySelector('iq>bind>jid');
if (stanza.getAttribute('id') != '0' ||
stanza.getAttribute('type') != 'result' || !jidElement) {
@@ -212,14 +203,10 @@ remoting.XmppLoginHandler.prototype.onStanza_ = function(stanza) {
return;
}
this.jid_ = jidElement.textContent;
- this.sendMessageCallback_(
- '<iq type="set" id="1">' +
- '<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>' +
- '</iq>');
- this.state_ = remoting.XmppLoginHandler.State.SESSION_IQ_SENT;
+ this.state_ = remoting.XmppLoginHandler.State.WAIT_SESSION_IQ_RESULT;
break;
- case remoting.XmppLoginHandler.State.SESSION_IQ_SENT:
+ case remoting.XmppLoginHandler.State.WAIT_SESSION_IQ_RESULT:
if (stanza.getAttribute('id') != '1' ||
stanza.getAttribute('type') != 'result') {
this.onError_(remoting.Error.UNEXPECTED,
@@ -240,8 +227,18 @@ remoting.XmppLoginHandler.prototype.onStanza_ = function(stanza) {
remoting.XmppLoginHandler.prototype.onTlsStarted = function() {
base.debug.assert(this.state_ ==
remoting.XmppLoginHandler.State.STARTING_TLS);
- this.state_ = remoting.XmppLoginHandler.State.START_SENT_AFTER_TLS;
- this.startStream_();
+ this.state_ = remoting.XmppLoginHandler.State.WAIT_STREAM_HEADER_AFTER_TLS;
+ var cookie = window.btoa("\0" + this.username_ + "\0" + this.authToken_);
+
+ this.startStream_(
+ '<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" ' +
+ 'mechanism="X-OAUTH2" auth:service="oauth2" ' +
+ 'auth:allow-generated-jid="true" ' +
+ 'auth:client-uses-full-bind-result="true" ' +
+ 'auth:allow-non-google-login="true" ' +
+ 'xmlns:auth="http://www.google.com/talk/protocol/auth">' +
+ cookie +
+ '</auth>');
};
/**
@@ -253,12 +250,14 @@ remoting.XmppLoginHandler.prototype.onParserError_ = function(text) {
}
/**
+ * @param {string} firstMessage Message to send after stream header.
* @private
*/
-remoting.XmppLoginHandler.prototype.startStream_ = function() {
+remoting.XmppLoginHandler.prototype.startStream_ = function(firstMessage) {
this.sendMessageCallback_('<stream:stream to="' + this.server_ +
'" version="1.0" xmlns="jabber:client" ' +
- 'xmlns:stream="http://etherx.jabber.org/streams">');
+ 'xmlns:stream="http://etherx.jabber.org/streams">' +
+ firstMessage);
this.streamParser_ = new remoting.XmppStreamParser();
this.streamParser_.setCallbacks(this.onStanza_.bind(this),
this.onParserError_.bind(this));