blob: 69f9caa6125c27e29dde6ed1e8f6e317ef6ee81a [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
/** @suppress {duplicate} */
var remoting = remoting || {};
(function() {
/** @enum */
var BlackholeState = {
PENDING: 0,
OPEN: 1,
BLOCKED: 2
};
/**
* A SignalStrategy wrapper that performs DNS blackhole check.
*
* @param {remoting.SignalStrategy} signalStrategy
* @constructor
* @implements {remoting.SignalStrategy}
*/
remoting.DnsBlackholeChecker = function(signalStrategy) {
/** @private */
this.signalStrategy_ = signalStrategy;
this.signalStrategy_.setStateChangedCallback(
this.onWrappedSignalStrategyStateChanged_.bind(this));
/** @private {?function(remoting.SignalStrategy.State):void} */
this.onStateChangedCallback_ = null;
/** @private */
this.state_ = remoting.SignalStrategy.State.NOT_CONNECTED;
/** @private */
this.blackholeState_ = BlackholeState.PENDING;
/** @private {?remoting.Xhr} */
this.xhr_ = null;
/** @const @private */
this.url_ =
remoting.settings.TALK_GADGET_URL + '/oauth/chrome-remote-desktop-client';
};
/**
* @param {?function(remoting.SignalStrategy.State):void} onStateChangedCallback
* Callback to call on state change.
*/
remoting.DnsBlackholeChecker.prototype.setStateChangedCallback = function(
onStateChangedCallback) {
this.onStateChangedCallback_ = onStateChangedCallback;
};
/**
* @param {?function(Element):void} onIncomingStanzaCallback Callback to call on
* incoming messages.
*/
remoting.DnsBlackholeChecker.prototype.setIncomingStanzaCallback =
function(onIncomingStanzaCallback) {
this.signalStrategy_.setIncomingStanzaCallback(onIncomingStanzaCallback);
};
/** @return {remoting.SignalStrategy.Type} The signal strategy type. */
remoting.DnsBlackholeChecker.prototype.getType = function() {
return this.signalStrategy_.getType();
};
/**
* @param {string} server
* @param {string} username
* @param {string} authToken
*/
remoting.DnsBlackholeChecker.prototype.connect = function(server,
username,
authToken) {
console.assert(this.onStateChangedCallback_ != null,
'No state change callback registered.');
this.signalStrategy_.connect(server, username, authToken);
this.xhr_ = new remoting.Xhr({
method: 'GET',
url: this.url_
});
this.xhr_.start().then(this.onHttpRequestDone_.bind(this));
};
remoting.DnsBlackholeChecker.prototype.getState = function() {
return this.state_;
};
remoting.DnsBlackholeChecker.prototype.getError = function() {
if (this.blackholeState_ == BlackholeState.BLOCKED) {
return new remoting.Error(remoting.Error.Tag.NOT_AUTHORIZED);
}
return this.signalStrategy_.getError();
};
remoting.DnsBlackholeChecker.prototype.getJid = function() {
console.assert(this.state_ == remoting.SignalStrategy.State.CONNECTED,
'getJid() called in state ' + this.state_ + '.');
return this.signalStrategy_.getJid();
};
remoting.DnsBlackholeChecker.prototype.dispose = function() {
this.xhr_ = null;
base.dispose(this.signalStrategy_);
this.setState_(remoting.SignalStrategy.State.CLOSED);
};
/** @param {string} message */
remoting.DnsBlackholeChecker.prototype.sendMessage = function(message) {
console.assert(this.state_ == remoting.SignalStrategy.State.CONNECTED,
'sendMessage() called in state ' + this.state_ + '.');
this.signalStrategy_.sendMessage(message);
};
/** @param {remoting.SignalStrategy.State} state */
remoting.DnsBlackholeChecker.prototype.onWrappedSignalStrategyStateChanged_ =
function(state) {
switch (this.blackholeState_) {
case BlackholeState.PENDING:
// Stay in HANDSHAKE state if we are still waiting for the HTTP request.
if (state != remoting.SignalStrategy.State.CONNECTED) {
this.setState_(state);
}
break;
case BlackholeState.OPEN:
this.setState_(state);
break;
case BlackholeState.BLOCKED:
// In case DNS blackhole is active the external state stays FAILED.
break;
}
};
/**
* @param {!remoting.Xhr.Response} response
* @private
*/
remoting.DnsBlackholeChecker.prototype.onHttpRequestDone_ = function(response) {
if (this.xhr_ == null) {
// This happens when the dispose() method is called while a
// request is pending.
return;
}
this.xhr_ = null;
if (response.status >= 200 && response.status <= 299) {
console.log("DNS blackhole check succeeded.");
this.blackholeState_ = BlackholeState.OPEN;
if (this.signalStrategy_.getState() ==
remoting.SignalStrategy.State.CONNECTED) {
this.setState_(remoting.SignalStrategy.State.CONNECTED);
}
} else {
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
* @private
*/
remoting.DnsBlackholeChecker.prototype.setState_ = function(newState) {
if (this.state_ != newState) {
this.state_ = newState;
this.onStateChangedCallback_(this.state_);
}
};
}());