summaryrefslogtreecommitdiffstats
path: root/blimp/client
diff options
context:
space:
mode:
authorkmarshall <kmarshall@chromium.org>2016-03-02 13:41:39 -0800
committerCommit bot <commit-bot@chromium.org>2016-03-02 21:43:41 +0000
commitc80f5095f045ad1712f1f1075a44547a561f774a (patch)
tree9b23343cb2ad36e6e63ecc7793cb2f93bfd0b23e /blimp/client
parentf0444bfd6b3c6b43f34da7709debdbc248395ef5 (diff)
downloadchromium_src-c80f5095f045ad1712f1f1075a44547a561f774a.zip
chromium_src-c80f5095f045ad1712f1f1075a44547a561f774a.tar.gz
chromium_src-c80f5095f045ad1712f1f1075a44547a561f774a.tar.bz2
Blimp: add support for SSL connections.
This CL allows the Blimp client to establish TLS-protected channels with the backend engine. The authenticity of the engine is validated by checking if its cert is an exact match of a certificate provided separately by the Assigner API. * Create new Blimp SSL transport class: SSLClientTransport. * Create custom CertValidator for checking an exact cert match against the SSL peer's cert * Integrate SSLClientTransport with BlimpClientSession. * Assignment: add certificate field. * AssignmentSource: add certificate file reading; PEM file parsing; X509 certificate parsing. * Created new DEPS entries as appropriate. R=wez@chromium.org CC=rsleevi@chromium.org BUG=585279,589202 Review URL: https://codereview.chromium.org/1696563002 Cr-Commit-Position: refs/heads/master@{#378839}
Diffstat (limited to 'blimp/client')
-rw-r--r--blimp/client/BUILD.gn22
-rw-r--r--blimp/client/DEPS3
-rw-r--r--blimp/client/app/android/blimp_jni_registrar.cc2
-rw-r--r--blimp/client/app/blimp_client_switches.cc12
-rw-r--r--blimp/client/app/blimp_client_switches.h20
-rw-r--r--blimp/client/session/assignment_source.cc239
-rw-r--r--blimp/client/session/assignment_source.h57
-rw-r--r--blimp/client/session/assignment_source_unittest.cc270
-rw-r--r--blimp/client/session/blimp_client_session.cc22
-rw-r--r--blimp/client/session/test_selfsigned_cert.pem11
10 files changed, 413 insertions, 245 deletions
diff --git a/blimp/client/BUILD.gn b/blimp/client/BUILD.gn
index d2ddc2b..465adb7 100644
--- a/blimp/client/BUILD.gn
+++ b/blimp/client/BUILD.gn
@@ -27,6 +27,7 @@ source_set("blimp_client") {
defines = [ "BLIMP_CLIENT_IMPLEMENTATION=1" ]
public_deps = [
+ "//components/safe_json",
"//ui/events",
]
@@ -49,12 +50,6 @@ source_set("blimp_client_unit_tests") {
sources = []
- # TODO(dtrainor): Fix the test harness to allow this to run on Android.
- # See crbug.com/588240.
- if (is_linux) {
- sources += [ "session/assignment_source_unittest.cc" ]
- }
-
deps = [
":blimp_client",
"//base",
@@ -63,6 +58,19 @@ source_set("blimp_client_unit_tests") {
"//testing/gmock",
"//testing/gtest",
]
+
+ data = []
+
+ # TODO(dtrainor): Fix the test harness to allow this to run on Android.
+ # See crbug.com/588240.
+ if (is_linux) {
+ sources += [ "session/assignment_source_unittest.cc" ]
+ deps += [
+ "//components/safe_json:test_support",
+ "//net:test_support",
+ ]
+ data += [ "session/test_selfsigned_cert.pem" ]
+ }
}
source_set("app_unit_tests") {
@@ -342,6 +350,7 @@ if (is_android) {
"//base",
"//blimp/common/proto",
"//blimp/net:blimp_net",
+ "//components/safe_json/android:safe_json_jni_headers",
"//skia",
"//ui/gfx/geometry",
"//ui/gl",
@@ -375,6 +384,7 @@ if (is_android) {
":blimp_java",
":blimp_java_resources",
"//base:base_java",
+ "//components/safe_json/android:safe_json_java",
"//net/android:net_java",
google_play_services_resources,
]
diff --git a/blimp/client/DEPS b/blimp/client/DEPS
index 62e4870..e1fa29a 100644
--- a/blimp/client/DEPS
+++ b/blimp/client/DEPS
@@ -2,7 +2,8 @@ include_rules = [
"+base",
"+cc",
"-cc/blink",
- "-chrome"
+ "-chrome",
+ "+components/safe_json",
"-content",
"+gpu",
"+jni",
diff --git a/blimp/client/app/android/blimp_jni_registrar.cc b/blimp/client/app/android/blimp_jni_registrar.cc
index 0ad0bcb..2f6ad4d 100644
--- a/blimp/client/app/android/blimp_jni_registrar.cc
+++ b/blimp/client/app/android/blimp_jni_registrar.cc
@@ -10,6 +10,7 @@
#include "blimp/client/app/android/blimp_view.h"
#include "blimp/client/app/android/tab_control_feature_android.h"
#include "blimp/client/app/android/toolbar.h"
+#include "components/safe_json/android/component_jni_registrar.h"
namespace blimp {
namespace client {
@@ -20,6 +21,7 @@ base::android::RegistrationMethod kBlimpRegistrationMethods[] = {
{"Toolbar", Toolbar::RegisterJni},
{"BlimpView", BlimpView::RegisterJni},
{"BlimpClientSessionAndroid", BlimpClientSessionAndroid::RegisterJni},
+ {"SafeJson", safe_json::android::RegisterSafeJsonJni},
{"TabControlFeatureAndroid", TabControlFeatureAndroid::RegisterJni},
};
diff --git a/blimp/client/app/blimp_client_switches.cc b/blimp/client/app/blimp_client_switches.cc
index cfcf2a0..da7dcda 100644
--- a/blimp/client/app/blimp_client_switches.cc
+++ b/blimp/client/app/blimp_client_switches.cc
@@ -7,11 +7,13 @@
namespace blimp {
namespace switches {
-// Specifies the blimplet scheme, IP-address and port to connect to, e.g.:
-// --blimplet-host="tcp:127.0.0.1:25467". Valid schemes are "ssl",
-// "tcp", and "quic".
-// TODO(nyquist): Add support for DNS-lookup. See http://crbug.com/576857.
-const char kBlimpletEndpoint[] = "blimplet-endpoint";
+const char kEngineCertPath[] = "engine-cert-path";
+
+const char kEngineIP[] = "engine-ip";
+
+const char kEnginePort[] = "engine-port";
+
+const char kEngineTransport[] = "engine-transport";
} // namespace switches
} // namespace blimp
diff --git a/blimp/client/app/blimp_client_switches.h b/blimp/client/app/blimp_client_switches.h
index 19b91dd..b06958f 100644
--- a/blimp/client/app/blimp_client_switches.h
+++ b/blimp/client/app/blimp_client_switches.h
@@ -10,7 +10,25 @@
namespace blimp {
namespace switches {
-extern const char kBlimpletEndpoint[];
+// The path to the engine's PEM-encoded X509 certificate.
+// If specified, SSL connected Engines must supply this certificate
+// for the connection to be valid.
+// e.g.:
+// --engine-cert-path=/home/blimp/certs/cert.pem
+extern const char kEngineCertPath[];
+
+// Specifies the engine's IP address. Must be used in conjunction with
+// --engine-port and --engine-transport.
+extern const char kEngineIP[];
+
+// Specifies the engine's listening port (1-65535).
+// Must be used in conjunction with --engine-ip and --engine-transport.
+extern const char kEnginePort[];
+
+// Specifies the transport used to communicate with the engine.
+// Can be "tcp" or "ssl".
+// Must be used in conjunction with --engine-ip and --engine-port.
+extern const char kEngineTransport[];
} // namespace switches
} // namespace blimp
diff --git a/blimp/client/session/assignment_source.cc b/blimp/client/session/assignment_source.cc
index 242d783..bbd8d1a 100644
--- a/blimp/client/session/assignment_source.cc
+++ b/blimp/client/session/assignment_source.cc
@@ -7,19 +7,22 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
+#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/location.h"
+#include "base/memory/ref_counted.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
+#include "base/task_runner_util.h"
#include "base/values.h"
#include "blimp/client/app/blimp_client_switches.h"
#include "blimp/common/protocol_version.h"
+#include "components/safe_json/safe_json_parser.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
-#include "net/base/url_util.h"
#include "net/http/http_status_code.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_service.h"
@@ -40,55 +43,11 @@ const char kProtocolVersionKey[] = "protocol_version";
const char kClientTokenKey[] = "clientToken";
const char kHostKey[] = "host";
const char kPortKey[] = "port";
-const char kCertificateFingerprintKey[] = "certificateFingerprint";
const char kCertificateKey[] = "certificate";
-// URL scheme constants for custom assignments. See the '--blimplet-endpoint'
-// documentation in blimp_client_switches.cc for details.
-const char kCustomSSLScheme[] = "ssl";
-const char kCustomTCPScheme[] = "tcp";
-const char kCustomQUICScheme[] = "quic";
-
-Assignment GetCustomBlimpletAssignment() {
- GURL url(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kBlimpletEndpoint));
-
- std::string host;
- int port;
- if (url.is_empty() || !url.is_valid() || !url.has_scheme() ||
- !net::ParseHostAndPort(url.path(), &host, &port)) {
- return Assignment();
- }
-
- net::IPAddress ip_address;
- if (!ip_address.AssignFromIPLiteral(host)) {
- CHECK(false) << "Invalid BlimpletAssignment host " << host;
- }
-
- if (!base::IsValueInRangeForNumericType<uint16_t>(port)) {
- CHECK(false) << "Invalid BlimpletAssignment port " << port;
- }
-
- Assignment::TransportProtocol protocol =
- Assignment::TransportProtocol::UNKNOWN;
- if (url.has_scheme()) {
- if (url.SchemeIs(kCustomSSLScheme)) {
- protocol = Assignment::TransportProtocol::SSL;
- } else if (url.SchemeIs(kCustomTCPScheme)) {
- protocol = Assignment::TransportProtocol::TCP;
- } else if (url.SchemeIs(kCustomQUICScheme)) {
- protocol = Assignment::TransportProtocol::QUIC;
- } else {
- CHECK(false) << "Invalid BlimpletAssignment scheme " << url.scheme();
- }
- }
-
- Assignment assignment;
- assignment.transport_protocol = protocol;
- assignment.ip_endpoint = net::IPEndPoint(ip_address, port);
- assignment.client_token = kDummyClientToken;
- return assignment;
-}
+// Possible arguments for the "--engine-transport" command line parameter.
+const char kSSLTransportValue[] = "ssl";
+const char kTCPTransportValue[] = "tcp";
GURL GetBlimpAssignerURL() {
// TODO(dtrainor): Add a way to specify another assigner.
@@ -98,8 +57,8 @@ GURL GetBlimpAssignerURL() {
class SimpleURLRequestContextGetter : public net::URLRequestContextGetter {
public:
SimpleURLRequestContextGetter(
- const scoped_refptr<base::SingleThreadTaskRunner>& io_loop_task_runner)
- : io_loop_task_runner_(io_loop_task_runner),
+ scoped_refptr<base::SingleThreadTaskRunner> io_loop_task_runner)
+ : io_loop_task_runner_(std::move(io_loop_task_runner)),
proxy_config_service_(net::ProxyService::CreateSystemProxyConfigService(
io_loop_task_runner_,
io_loop_task_runner_)) {}
@@ -136,45 +95,142 @@ class SimpleURLRequestContextGetter : public net::URLRequestContextGetter {
DISALLOW_COPY_AND_ASSIGN(SimpleURLRequestContextGetter);
};
+bool IsValidIpPortNumber(unsigned port) {
+ return port > 0 && port <= 65535;
+}
+
+// Populates an Assignment using command-line parameters, if provided.
+// Returns a null Assignment if no parameters were set.
+// Must be called on a thread suitable for file IO.
+Assignment GetAssignmentFromCommandLine() {
+ Assignment assignment;
+ assignment.client_token = kDummyClientToken;
+
+ unsigned port_parsed = 0;
+ if (!base::StringToUint(
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kEnginePort),
+ &port_parsed) ||
+ !IsValidIpPortNumber(port_parsed)) {
+ DLOG(FATAL) << "--engine-port must be a value between 1 and 65535.";
+ return Assignment();
+ }
+
+ net::IPAddress ip_address;
+ std::string ip_str =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kEngineIP);
+ if (!ip_address.AssignFromIPLiteral(ip_str)) {
+ DLOG(FATAL) << "Invalid engine IP " << ip_str;
+ return Assignment();
+ }
+ assignment.engine_endpoint =
+ net::IPEndPoint(ip_address, base::checked_cast<uint16_t>(port_parsed));
+
+ std::string transport_str =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kEngineTransport);
+ if (transport_str == kSSLTransportValue) {
+ assignment.transport_protocol = Assignment::TransportProtocol::SSL;
+ } else if (transport_str == kTCPTransportValue) {
+ assignment.transport_protocol = Assignment::TransportProtocol::TCP;
+ } else {
+ DLOG(FATAL) << "Invalid engine transport " << transport_str;
+ return Assignment();
+ }
+
+ scoped_refptr<net::X509Certificate> cert;
+ if (assignment.transport_protocol == Assignment::TransportProtocol::SSL) {
+ base::FilePath cert_path =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kEngineCertPath);
+ if (cert_path.empty()) {
+ DLOG(FATAL) << "Missing required parameter --"
+ << switches::kEngineCertPath << ".";
+ return Assignment();
+ }
+ std::string cert_str;
+ if (!base::ReadFileToString(cert_path, &cert_str)) {
+ DLOG(FATAL) << "Couldn't read from file: "
+ << cert_path.LossyDisplayName();
+ return Assignment();
+ }
+ net::CertificateList cert_list =
+ net::X509Certificate::CreateCertificateListFromBytes(
+ cert_str.data(), cert_str.size(),
+ net::X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+ DLOG_IF(FATAL, (cert_list.size() != 1u))
+ << "Only one cert is allowed in PEM cert list.";
+ assignment.cert = std::move(cert_list[0]);
+ }
+
+ if (!assignment.IsValid()) {
+ DLOG(FATAL) << "Invalid command-line assignment.";
+ return Assignment();
+ }
+
+ return assignment;
+}
+
} // namespace
Assignment::Assignment() : transport_protocol(TransportProtocol::UNKNOWN) {}
Assignment::~Assignment() {}
-bool Assignment::is_null() const {
- return ip_endpoint.address().empty() || ip_endpoint.port() == 0 ||
- transport_protocol == TransportProtocol::UNKNOWN;
+bool Assignment::IsValid() const {
+ if (engine_endpoint.address().empty() || engine_endpoint.port() == 0 ||
+ transport_protocol == TransportProtocol::UNKNOWN) {
+ return false;
+ }
+ if (transport_protocol == TransportProtocol::SSL && !cert) {
+ return false;
+ }
+ return true;
}
AssignmentSource::AssignmentSource(
- const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
- const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
- : main_task_runner_(main_task_runner),
- url_request_context_(new SimpleURLRequestContextGetter(io_task_runner)) {}
+ const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner)
+ : file_task_runner_(std::move(file_task_runner)),
+ url_request_context_(
+ new SimpleURLRequestContextGetter(network_task_runner)),
+ weak_factory_(this) {}
AssignmentSource::~AssignmentSource() {}
void AssignmentSource::GetAssignment(const std::string& client_auth_token,
const AssignmentCallback& callback) {
- DCHECK(main_task_runner_->BelongsToCurrentThread());
+ DCHECK(callback_.is_null());
+ callback_ = AssignmentCallback(callback);
- // Cancel any outstanding callback.
- if (!callback_.is_null()) {
- base::ResetAndReturn(&callback_)
- .Run(AssignmentSource::Result::RESULT_SERVER_INTERRUPTED, Assignment());
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEngineIP)) {
+ base::PostTaskAndReplyWithResult(
+ file_task_runner_.get(), FROM_HERE,
+ base::Bind(&GetAssignmentFromCommandLine),
+ base::Bind(&AssignmentSource::OnGetAssignmentFromCommandLineDone,
+ weak_factory_.GetWeakPtr(), client_auth_token));
+ } else {
+ QueryAssigner(client_auth_token);
}
- callback_ = AssignmentCallback(callback);
+}
- Assignment assignment = GetCustomBlimpletAssignment();
- if (!assignment.is_null()) {
- // Post the result so that the behavior of this function is consistent.
- main_task_runner_->PostTask(
- FROM_HERE, base::Bind(base::ResetAndReturn(&callback_),
- AssignmentSource::Result::RESULT_OK, assignment));
+void AssignmentSource::OnGetAssignmentFromCommandLineDone(
+ const std::string& client_auth_token,
+ Assignment parsed_assignment) {
+ // If GetAssignmentFromCommandLine succeeded, then return its output.
+ if (parsed_assignment.IsValid()) {
+ base::ResetAndReturn(&callback_)
+ .Run(AssignmentSource::RESULT_OK, parsed_assignment);
return;
}
+ // If no assignment was passed via the command line, then fall back on
+ // querying the Assigner service.
+ QueryAssigner(client_auth_token);
+}
+
+void AssignmentSource::QueryAssigner(const std::string& client_auth_token) {
// Call out to the network for a real assignment. Build the network request
// to hit the assigner.
url_fetcher_ = net::URLFetcher::Create(GetBlimpAssignerURL(),
@@ -191,12 +247,10 @@ void AssignmentSource::GetAssignment(const std::string& client_auth_token,
std::string json;
base::JSONWriter::Write(dictionary, &json);
url_fetcher_->SetUploadData("application/json", json);
-
url_fetcher_->Start();
}
void AssignmentSource::OnURLFetchComplete(const net::URLFetcher* source) {
- DCHECK(main_task_runner_->BelongsToCurrentThread());
DCHECK(!callback_.is_null());
DCHECK_EQ(url_fetcher_.get(), source);
@@ -253,14 +307,14 @@ void AssignmentSource::ParseAssignerResponse() {
return;
}
- // Attempt to interpret the response as JSON and treat it as a dictionary.
- scoped_ptr<base::Value> json = base::JSONReader::Read(response);
- if (!json) {
- base::ResetAndReturn(&callback_)
- .Run(AssignmentSource::Result::RESULT_BAD_RESPONSE, Assignment());
- return;
- }
+ safe_json::SafeJsonParser::Parse(
+ response,
+ base::Bind(&AssignmentSource::OnJsonParsed, weak_factory_.GetWeakPtr()),
+ base::Bind(&AssignmentSource::OnJsonParseError,
+ weak_factory_.GetWeakPtr()));
+}
+void AssignmentSource::OnJsonParsed(scoped_ptr<base::Value> json) {
const base::DictionaryValue* dict;
if (!json->GetAsDictionary(&dict)) {
base::ResetAndReturn(&callback_)
@@ -272,12 +326,10 @@ void AssignmentSource::ParseAssignerResponse() {
std::string client_token;
std::string host;
int port;
- std::string cert_fingerprint;
- std::string cert;
+ std::string cert_str;
if (!(dict->GetString(kClientTokenKey, &client_token) &&
dict->GetString(kHostKey, &host) && dict->GetInteger(kPortKey, &port) &&
- dict->GetString(kCertificateFingerprintKey, &cert_fingerprint) &&
- dict->GetString(kCertificateKey, &cert))) {
+ dict->GetString(kCertificateKey, &cert_str))) {
base::ResetAndReturn(&callback_)
.Run(AssignmentSource::Result::RESULT_BAD_RESPONSE, Assignment());
return;
@@ -296,18 +348,33 @@ void AssignmentSource::ParseAssignerResponse() {
return;
}
- Assignment assignment;
+ net::CertificateList cert_list =
+ net::X509Certificate::CreateCertificateListFromBytes(
+ cert_str.data(), cert_str.size(),
+ net::X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+ if (cert_list.size() != 1) {
+ base::ResetAndReturn(&callback_)
+ .Run(AssignmentSource::Result::RESULT_INVALID_CERT, Assignment());
+ return;
+ }
+
// The assigner assumes SSL-only and all engines it assigns only communicate
// over SSL.
+ Assignment assignment;
assignment.transport_protocol = Assignment::TransportProtocol::SSL;
- assignment.ip_endpoint = net::IPEndPoint(ip_address, port);
+ assignment.engine_endpoint = net::IPEndPoint(ip_address, port);
assignment.client_token = client_token;
- assignment.certificate = cert;
- assignment.certificate_fingerprint = cert_fingerprint;
+ assignment.cert = std::move(cert_list[0]);
base::ResetAndReturn(&callback_)
.Run(AssignmentSource::Result::RESULT_OK, assignment);
}
+void AssignmentSource::OnJsonParseError(const std::string& error) {
+ DLOG(ERROR) << "Error while parsing assigner JSON: " << error;
+ base::ResetAndReturn(&callback_)
+ .Run(AssignmentSource::Result::RESULT_BAD_RESPONSE, Assignment());
+}
+
} // namespace client
} // namespace blimp
diff --git a/blimp/client/session/assignment_source.h b/blimp/client/session/assignment_source.h
index dabe72c..bafd021 100644
--- a/blimp/client/session/assignment_source.h
+++ b/blimp/client/session/assignment_source.h
@@ -8,17 +8,21 @@
#include <string>
#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
#include "blimp/client/blimp_client_export.h"
#include "net/base/ip_endpoint.h"
#include "net/url_request/url_fetcher_delegate.h"
namespace base {
+class FilePath;
class SingleThreadTaskRunner;
+class Value;
}
namespace net {
class URLFetcher;
class URLRequestContextGetter;
+class X509Certificate;
}
namespace blimp {
@@ -38,21 +42,26 @@ struct BLIMP_CLIENT_EXPORT Assignment {
UNKNOWN = 0,
SSL = 1,
TCP = 2,
- QUIC = 3,
};
Assignment();
~Assignment();
+ // Returns true if the net::IPEndPoint has an unspecified IP, port, or
+ // transport protocol.
+ bool IsValid() const;
+
+ // Specifies the transport to use to connect to the engine.
TransportProtocol transport_protocol;
- net::IPEndPoint ip_endpoint;
+
+ // Specifies the IP address and port on which to reach the engine.
+ net::IPEndPoint engine_endpoint;
+
+ // Used to authenticate to the specified engine.
std::string client_token;
- std::string certificate;
- std::string certificate_fingerprint;
- // Returns true if the net::IPEndPoint has an unspecified IP, port, or
- // transport protocol.
- bool is_null() const;
+ // Specifies the X.509 certificate that the engine must report.
+ scoped_refptr<net::X509Certificate> cert;
};
// AssignmentSource provides functionality to find out how a client should
@@ -72,18 +81,21 @@ class BLIMP_CLIENT_EXPORT AssignmentSource : public net::URLFetcherDelegate {
RESULT_OUT_OF_VMS = 7,
RESULT_SERVER_ERROR = 8,
RESULT_SERVER_INTERRUPTED = 9,
- RESULT_NETWORK_FAILURE = 10
+ RESULT_NETWORK_FAILURE = 10,
+ RESULT_INVALID_CERT = 11,
};
typedef base::Callback<void(AssignmentSource::Result, const Assignment&)>
AssignmentCallback;
- // The |main_task_runner| should be the task runner for the UI thread because
- // this will in some cases be used to trigger user interaction on the UI
- // thread.
+ // |network_task_runner|: The task runner to use for querying the Assigner API
+ // over the network.
+ // |file_task_runner|: The task runner to use for reading cert files from disk
+ // (specified on the command line.)
AssignmentSource(
- const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
- const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
+ const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner);
+
~AssignmentSource() override;
// Retrieves a valid assignment for the client and posts the result to the
@@ -94,20 +106,25 @@ class BLIMP_CLIENT_EXPORT AssignmentSource : public net::URLFetcherDelegate {
void GetAssignment(const std::string& client_auth_token,
const AssignmentCallback& callback);
- // net::URLFetcherDelegate implementation:
- void OnURLFetchComplete(const net::URLFetcher* source) override;
-
private:
+ void OnGetAssignmentFromCommandLineDone(const std::string& client_auth_token,
+ Assignment parsed_assignment);
+ void QueryAssigner(const std::string& client_auth_token);
void ParseAssignerResponse();
+ void OnJsonParsed(scoped_ptr<base::Value> json);
+ void OnJsonParseError(const std::string& error);
+
+ // net::URLFetcherDelegate implementation:
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+ // GetAssignment() callback, invoked after URLFetcher completion.
+ AssignmentCallback callback_;
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
scoped_refptr<net::URLRequestContextGetter> url_request_context_;
scoped_ptr<net::URLFetcher> url_fetcher_;
- // This callback is set during a call to GetAssignment() and is cleared after
- // the request has completed (whether it be a success or failure).
- AssignmentCallback callback_;
+ base::WeakPtrFactory<AssignmentSource> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AssignmentSource);
};
diff --git a/blimp/client/session/assignment_source_unittest.cc b/blimp/client/session/assignment_source_unittest.cc
index d893ae3..54f3e44 100644
--- a/blimp/client/session/assignment_source_unittest.cc
+++ b/blimp/client/session/assignment_source_unittest.cc
@@ -5,68 +5,80 @@
#include "blimp/client/session/assignment_source.h"
#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
#include "base/test/test_simple_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "base/values.h"
#include "blimp/client/app/blimp_client_switches.h"
#include "blimp/common/protocol_version.h"
+#include "components/safe_json/testing_json_parser.h"
+#include "net/base/test_data_directory.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
+using testing::DoAll;
using testing::InSequence;
+using testing::NotNull;
+using testing::Return;
+using testing::SetArgPointee;
namespace blimp {
namespace client {
namespace {
+const uint8_t kTestIpAddress[] = {127, 0, 0, 1};
+const uint16_t kTestPort = 8086;
+const char kTestIpAddressString[] = "127.0.0.1";
+const char kTcpTransportName[] = "tcp";
+const char kSslTransportName[] = "ssl";
+const char kCertRelativePath[] =
+ "blimp/client/session/test_selfsigned_cert.pem";
+const char kTestClientToken[] = "secrett0ken";
+const char kTestAuthToken[] = "UserAuthT0kenz";
+
MATCHER_P(AssignmentEquals, assignment, "") {
return arg.transport_protocol == assignment.transport_protocol &&
- arg.ip_endpoint == assignment.ip_endpoint &&
+ arg.engine_endpoint == assignment.engine_endpoint &&
arg.client_token == assignment.client_token &&
- arg.certificate == assignment.certificate &&
- arg.certificate_fingerprint == assignment.certificate_fingerprint;
-}
-
-net::IPEndPoint BuildIPEndPoint(const std::string& ip, int port) {
- net::IPAddress ip_address;
- EXPECT_TRUE(ip_address.AssignFromIPLiteral(ip));
-
- return net::IPEndPoint(ip_address, port);
-}
-
-Assignment BuildValidAssignment() {
- Assignment assignment;
- assignment.transport_protocol = Assignment::TransportProtocol::SSL;
- assignment.ip_endpoint = BuildIPEndPoint("100.150.200.250", 500);
- assignment.client_token = "SecretT0kenz";
- assignment.certificate_fingerprint = "WhaleWhaleWhale";
- assignment.certificate = "whaaaaaaaaaaaaale";
- return assignment;
+ ((!assignment.cert && !arg.cert) ||
+ (arg.cert && assignment.cert &&
+ arg.cert->Equals(assignment.cert.get())));
}
-std::string BuildResponseFromAssignment(const Assignment& assignment) {
- base::DictionaryValue dict;
- dict.SetString("clientToken", assignment.client_token);
- dict.SetString("host", assignment.ip_endpoint.address().ToString());
- dict.SetInteger("port", assignment.ip_endpoint.port());
- dict.SetString("certificateFingerprint", assignment.certificate_fingerprint);
- dict.SetString("certificate", assignment.certificate);
-
+// Converts |value| to a JSON string.
+std::string ValueToString(const base::Value& value) {
std::string json;
- base::JSONWriter::Write(dict, &json);
+ base::JSONWriter::Write(value, &json);
return json;
}
class AssignmentSourceTest : public testing::Test {
public:
AssignmentSourceTest()
- : task_runner_(new base::TestSimpleTaskRunner),
- task_runner_handle_(task_runner_),
- source_(task_runner_, task_runner_) {}
+ : source_(message_loop_.task_runner(), message_loop_.task_runner()) {}
+
+ void SetUp() override {
+ base::FilePath src_root;
+ PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
+ ASSERT_FALSE(src_root.empty());
+ cert_path_ = src_root.Append(kCertRelativePath);
+ ASSERT_TRUE(base::ReadFileToString(cert_path_, &cert_pem_));
+ net::CertificateList cert_list =
+ net::X509Certificate::CreateCertificateListFromBytes(
+ cert_pem_.data(), cert_pem_.size(),
+ net::X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+ ASSERT_FALSE(cert_list.empty());
+ cert_ = std::move(cert_list[0]);
+ ASSERT_TRUE(cert_);
+ }
// This expects the AssignmentSource::GetAssignment to return a custom
// endpoint without having to hit the network. This will typically be used
@@ -77,7 +89,7 @@ class AssignmentSourceTest : public testing::Test {
base::Bind(&AssignmentSourceTest::AssignmentResponse,
base::Unretained(this)));
EXPECT_EQ(nullptr, factory_.GetFetcherByID(0));
- task_runner_->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
// See net/base/net_errors.h for possible status errors.
@@ -90,11 +102,10 @@ class AssignmentSourceTest : public testing::Test {
source_.GetAssignment(client_auth_token,
base::Bind(&AssignmentSourceTest::AssignmentResponse,
base::Unretained(this)));
+ base::RunLoop().RunUntilIdle();
net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
- task_runner_->RunUntilIdle();
-
EXPECT_NE(nullptr, fetcher);
EXPECT_EQ(kDefaultAssignerURL, fetcher->GetOriginalURL().spec());
@@ -125,30 +136,74 @@ class AssignmentSourceTest : public testing::Test {
fetcher->SetResponseString(response);
fetcher->delegate()->OnURLFetchComplete(fetcher);
- task_runner_->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
}
MOCK_METHOD2(AssignmentResponse,
void(AssignmentSource::Result, const Assignment&));
protected:
+ Assignment BuildSslAssignment();
+
+ // Builds simulated JSON response from the Assigner service.
+ scoped_ptr<base::DictionaryValue> BuildAssignerResponse();
+
// Used to drive all AssignmentSource tasks.
- scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
- base::ThreadTaskRunnerHandle task_runner_handle_;
+ // MessageLoop is required by TestingJsonParser's self-deletion logic.
+ // TODO(bauerb): Replace this with a TestSimpleTaskRunner once
+ // TestingJsonParser no longer requires having a MessageLoop.
+ base::MessageLoop message_loop_;
net::TestURLFetcherFactory factory_;
+ // Path to the PEM-encoded certificate chain.
+ base::FilePath cert_path_;
+
+ // Payload of PEM certificate chain at |cert_path_|.
+ std::string cert_pem_;
+
+ // X509 certificate decoded from |cert_path_|.
+ scoped_refptr<net::X509Certificate> cert_;
+
AssignmentSource source_;
+
+ // Allows safe_json to parse JSON in-process, instead of depending on a
+ // utility proces.
+ safe_json::TestingJsonParser::ScopedFactoryOverride json_parsing_factory_;
};
+Assignment AssignmentSourceTest::BuildSslAssignment() {
+ Assignment assignment;
+ assignment.transport_protocol = Assignment::TransportProtocol::SSL;
+ assignment.engine_endpoint = net::IPEndPoint(kTestIpAddress, kTestPort);
+ assignment.client_token = kTestClientToken;
+ assignment.cert = cert_;
+ return assignment;
+}
+
+scoped_ptr<base::DictionaryValue>
+AssignmentSourceTest::BuildAssignerResponse() {
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
+ dict->SetString("clientToken", kTestClientToken);
+ dict->SetString("host", kTestIpAddressString);
+ dict->SetInteger("port", kTestPort);
+ dict->SetString("certificate", cert_pem_);
+ return dict;
+}
+
TEST_F(AssignmentSourceTest, TestTCPAlternateEndpointSuccess) {
Assignment assignment;
assignment.transport_protocol = Assignment::TransportProtocol::TCP;
- assignment.ip_endpoint = BuildIPEndPoint("100.150.200.250", 500);
+ assignment.engine_endpoint = net::IPEndPoint(kTestIpAddress, kTestPort);
assignment.client_token = kDummyClientToken;
+ assignment.cert = scoped_refptr<net::X509Certificate>(nullptr);
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kBlimpletEndpoint, "tcp:100.150.200.250:500");
+ switches::kEngineIP, kTestIpAddressString);
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kEnginePort, std::to_string(kTestPort));
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kEngineTransport, kTcpTransportName);
EXPECT_CALL(*this, AssignmentResponse(AssignmentSource::Result::RESULT_OK,
AssignmentEquals(assignment)))
@@ -160,27 +215,18 @@ TEST_F(AssignmentSourceTest, TestTCPAlternateEndpointSuccess) {
TEST_F(AssignmentSourceTest, TestSSLAlternateEndpointSuccess) {
Assignment assignment;
assignment.transport_protocol = Assignment::TransportProtocol::SSL;
- assignment.ip_endpoint = BuildIPEndPoint("100.150.200.250", 500);
+ assignment.engine_endpoint = net::IPEndPoint(kTestIpAddress, kTestPort);
assignment.client_token = kDummyClientToken;
+ assignment.cert = cert_;
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kBlimpletEndpoint, "ssl:100.150.200.250:500");
-
- EXPECT_CALL(*this, AssignmentResponse(AssignmentSource::Result::RESULT_OK,
- AssignmentEquals(assignment)))
- .Times(1);
-
- GetAlternateAssignment();
-}
-
-TEST_F(AssignmentSourceTest, TestQUICAlternateEndpointSuccess) {
- Assignment assignment;
- assignment.transport_protocol = Assignment::TransportProtocol::QUIC;
- assignment.ip_endpoint = BuildIPEndPoint("100.150.200.250", 500);
- assignment.client_token = kDummyClientToken;
-
+ switches::kEngineIP, kTestIpAddressString);
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kEnginePort, std::to_string(kTestPort));
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
- switches::kBlimpletEndpoint, "quic:100.150.200.250:500");
+ switches::kEngineTransport, kSslTransportName);
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kEngineCertPath, cert_path_.value());
EXPECT_CALL(*this, AssignmentResponse(AssignmentSource::Result::RESULT_OK,
AssignmentEquals(assignment)))
@@ -190,44 +236,20 @@ TEST_F(AssignmentSourceTest, TestQUICAlternateEndpointSuccess) {
}
TEST_F(AssignmentSourceTest, TestSuccess) {
- Assignment assignment = BuildValidAssignment();
+ Assignment assignment = BuildSslAssignment();
EXPECT_CALL(*this, AssignmentResponse(AssignmentSource::Result::RESULT_OK,
AssignmentEquals(assignment)))
.Times(1);
GetNetworkAssignmentAndWaitForResponse(
- net::HTTP_OK, net::Error::OK, BuildResponseFromAssignment(assignment),
- "UserAuthT0kenz", kEngineVersion);
-}
-
-TEST_F(AssignmentSourceTest, TestSecondRequestInterruptsFirst) {
- InSequence sequence;
- Assignment assignment = BuildValidAssignment();
-
- source_.GetAssignment("",
- base::Bind(&AssignmentSourceTest::AssignmentResponse,
- base::Unretained(this)));
-
- EXPECT_CALL(*this, AssignmentResponse(
- AssignmentSource::Result::RESULT_SERVER_INTERRUPTED,
- AssignmentEquals(Assignment())))
- .Times(1)
- .RetiresOnSaturation();
-
- EXPECT_CALL(*this, AssignmentResponse(AssignmentSource::Result::RESULT_OK,
- AssignmentEquals(assignment)))
- .Times(1)
- .RetiresOnSaturation();
-
- GetNetworkAssignmentAndWaitForResponse(
- net::HTTP_OK, net::Error::OK, BuildResponseFromAssignment(assignment),
- "UserAuthT0kenz", kEngineVersion);
+ net::HTTP_OK, net::Error::OK, ValueToString(*BuildAssignerResponse()),
+ kTestAuthToken, kEngineVersion);
}
TEST_F(AssignmentSourceTest, TestValidAfterError) {
InSequence sequence;
- Assignment assignment = BuildValidAssignment();
+ Assignment assignment = BuildSslAssignment();
EXPECT_CALL(*this, AssignmentResponse(
AssignmentSource::Result::RESULT_NETWORK_FAILURE, _))
@@ -241,11 +263,11 @@ TEST_F(AssignmentSourceTest, TestValidAfterError) {
GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK,
net::Error::ERR_INSUFFICIENT_RESOURCES,
- "", "UserAuthT0kenz", kEngineVersion);
+ "", kTestAuthToken, kEngineVersion);
GetNetworkAssignmentAndWaitForResponse(
- net::HTTP_OK, net::Error::OK, BuildResponseFromAssignment(assignment),
- "UserAuthT0kenz", kEngineVersion);
+ net::HTTP_OK, net::Error::OK, ValueToString(*BuildAssignerResponse()),
+ kTestAuthToken, kEngineVersion);
}
TEST_F(AssignmentSourceTest, TestNetworkFailure) {
@@ -253,14 +275,14 @@ TEST_F(AssignmentSourceTest, TestNetworkFailure) {
AssignmentSource::Result::RESULT_NETWORK_FAILURE, _));
GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK,
net::Error::ERR_INSUFFICIENT_RESOURCES,
- "", "UserAuthT0kenz", kEngineVersion);
+ "", kTestAuthToken, kEngineVersion);
}
TEST_F(AssignmentSourceTest, TestBadRequest) {
EXPECT_CALL(*this, AssignmentResponse(
AssignmentSource::Result::RESULT_BAD_REQUEST, _));
GetNetworkAssignmentAndWaitForResponse(net::HTTP_BAD_REQUEST, net::Error::OK,
- "", "UserAuthT0kenz", kEngineVersion);
+ "", kTestAuthToken, kEngineVersion);
}
TEST_F(AssignmentSourceTest, TestUnauthorized) {
@@ -268,21 +290,21 @@ TEST_F(AssignmentSourceTest, TestUnauthorized) {
AssignmentResponse(
AssignmentSource::Result::RESULT_EXPIRED_ACCESS_TOKEN, _));
GetNetworkAssignmentAndWaitForResponse(net::HTTP_UNAUTHORIZED, net::Error::OK,
- "", "UserAuthT0kenz", kEngineVersion);
+ "", kTestAuthToken, kEngineVersion);
}
TEST_F(AssignmentSourceTest, TestForbidden) {
EXPECT_CALL(*this, AssignmentResponse(
AssignmentSource::Result::RESULT_USER_INVALID, _));
GetNetworkAssignmentAndWaitForResponse(net::HTTP_FORBIDDEN, net::Error::OK,
- "", "UserAuthT0kenz", kEngineVersion);
+ "", kTestAuthToken, kEngineVersion);
}
TEST_F(AssignmentSourceTest, TestTooManyRequests) {
EXPECT_CALL(*this, AssignmentResponse(
AssignmentSource::Result::RESULT_OUT_OF_VMS, _));
GetNetworkAssignmentAndWaitForResponse(static_cast<net::HttpStatusCode>(429),
- net::Error::OK, "", "UserAuthT0kenz",
+ net::Error::OK, "", kTestAuthToken,
kEngineVersion);
}
@@ -290,7 +312,7 @@ TEST_F(AssignmentSourceTest, TestInternalServerError) {
EXPECT_CALL(*this, AssignmentResponse(
AssignmentSource::Result::RESULT_SERVER_ERROR, _));
GetNetworkAssignmentAndWaitForResponse(net::HTTP_INTERNAL_SERVER_ERROR,
- net::Error::OK, "", "UserAuthT0kenz",
+ net::Error::OK, "", kTestAuthToken,
kEngineVersion);
}
@@ -298,56 +320,62 @@ TEST_F(AssignmentSourceTest, TestUnexpectedNetCodeFallback) {
EXPECT_CALL(*this, AssignmentResponse(
AssignmentSource::Result::RESULT_BAD_RESPONSE, _));
GetNetworkAssignmentAndWaitForResponse(net::HTTP_NOT_IMPLEMENTED,
- net::Error::OK, "", "UserAuthT0kenz",
+ net::Error::OK, "", kTestAuthToken,
kEngineVersion);
}
TEST_F(AssignmentSourceTest, TestInvalidJsonResponse) {
- Assignment assignment = BuildValidAssignment();
+ Assignment assignment = BuildSslAssignment();
// Remove half the response.
- std::string response = BuildResponseFromAssignment(assignment);
+ std::string response = ValueToString(*BuildAssignerResponse());
response = response.substr(response.size() / 2);
EXPECT_CALL(*this, AssignmentResponse(
AssignmentSource::Result::RESULT_BAD_RESPONSE, _));
GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK, response,
- "UserAuthT0kenz", kEngineVersion);
+ kTestAuthToken, kEngineVersion);
}
TEST_F(AssignmentSourceTest, TestMissingResponsePort) {
- // Purposely do not add the 'port' field to the response.
- base::DictionaryValue dict;
- dict.SetString("clientToken", "SecretT0kenz");
- dict.SetString("host", "happywhales");
- dict.SetString("certificateFingerprint", "WhaleWhaleWhale");
- dict.SetString("certificate", "whaaaaaaaaaaaaale");
-
- std::string response;
- base::JSONWriter::Write(dict, &response);
-
+ scoped_ptr<base::DictionaryValue> response = BuildAssignerResponse();
+ response->Remove("port", nullptr);
EXPECT_CALL(*this, AssignmentResponse(
AssignmentSource::Result::RESULT_BAD_RESPONSE, _));
- GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK, response,
- "UserAuthT0kenz", kEngineVersion);
+ GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK,
+ ValueToString(*response),
+ kTestAuthToken, kEngineVersion);
}
TEST_F(AssignmentSourceTest, TestInvalidIPAddress) {
- // Purposely add an invalid IP field to the response.
- base::DictionaryValue dict;
- dict.SetString("clientToken", "SecretT0kenz");
- dict.SetString("host", "happywhales");
- dict.SetInteger("port", 500);
- dict.SetString("certificateFingerprint", "WhaleWhaleWhale");
- dict.SetString("certificate", "whaaaaaaaaaaaaale");
+ scoped_ptr<base::DictionaryValue> response = BuildAssignerResponse();
+ response->SetString("host", "happywhales.test");
- std::string response;
- base::JSONWriter::Write(dict, &response);
+ EXPECT_CALL(*this, AssignmentResponse(
+ AssignmentSource::Result::RESULT_BAD_RESPONSE, _));
+ GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK,
+ ValueToString(*response),
+ kTestAuthToken, kEngineVersion);
+}
+TEST_F(AssignmentSourceTest, TestMissingCert) {
+ scoped_ptr<base::DictionaryValue> response = BuildAssignerResponse();
+ response->Remove("certificate", nullptr);
EXPECT_CALL(*this, AssignmentResponse(
AssignmentSource::Result::RESULT_BAD_RESPONSE, _));
- GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK, response,
- "UserAuthT0kenz", kEngineVersion);
+ GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK,
+ ValueToString(*response),
+ kTestAuthToken, kEngineVersion);
+}
+
+TEST_F(AssignmentSourceTest, TestInvalidCert) {
+ scoped_ptr<base::DictionaryValue> response = BuildAssignerResponse();
+ response->SetString("certificate", "h4x0rz!");
+ EXPECT_CALL(*this, AssignmentResponse(
+ AssignmentSource::Result::RESULT_INVALID_CERT, _));
+ GetNetworkAssignmentAndWaitForResponse(net::HTTP_OK, net::Error::OK,
+ ValueToString(*response),
+ kTestAuthToken, kEngineVersion);
}
} // namespace
diff --git a/blimp/client/session/blimp_client_session.cc b/blimp/client/session/blimp_client_session.cc
index 29c0b32..7846d59 100644
--- a/blimp/client/session/blimp_client_session.cc
+++ b/blimp/client/session/blimp_client_session.cc
@@ -22,6 +22,7 @@
#include "blimp/net/client_connection_manager.h"
#include "blimp/net/common.h"
#include "blimp/net/null_blimp_message_processor.h"
+#include "blimp/net/ssl_client_transport.h"
#include "blimp/net/tcp_client_transport.h"
#include "net/base/address_list.h"
#include "net/base/ip_address.h"
@@ -66,7 +67,6 @@ class ClientNetworkComponents {
// they are used from the UI thread.
std::vector<scoped_ptr<BlimpMessageThreadPipe>> outgoing_pipes_;
std::vector<scoped_ptr<BlimpMessageProcessor>> outgoing_message_processors_;
-
DISALLOW_COPY_AND_ASSIGN(ClientNetworkComponents);
};
@@ -81,8 +81,20 @@ void ClientNetworkComponents::ConnectWithAssignment(
DCHECK(connection_manager_);
connection_manager_->set_client_token(assignment.client_token);
- connection_manager_->AddTransport(make_scoped_ptr(new TCPClientTransport(
- net::AddressList(assignment.ip_endpoint), nullptr)));
+ switch (assignment.transport_protocol) {
+ case Assignment::SSL:
+ DCHECK(assignment.cert);
+ connection_manager_->AddTransport(make_scoped_ptr(new SSLClientTransport(
+ assignment.engine_endpoint, std::move(assignment.cert), nullptr)));
+ break;
+ case Assignment::TCP:
+ connection_manager_->AddTransport(make_scoped_ptr(
+ new TCPClientTransport(assignment.engine_endpoint, nullptr)));
+ break;
+ case Assignment::UNKNOWN:
+ DLOG(FATAL) << "Uknown transport type.";
+ break;
+ }
connection_manager_->Connect();
}
@@ -118,8 +130,8 @@ BlimpClientSession::BlimpClientSession()
options.message_loop_type = base::MessageLoop::TYPE_IO;
io_thread_.StartWithOptions(options);
- assignment_source_.reset(new AssignmentSource(
- base::ThreadTaskRunnerHandle::Get(), io_thread_.task_runner()));
+ assignment_source_.reset(
+ new AssignmentSource(io_thread_.task_runner(), io_thread_.task_runner()));
// Register features' message senders and receivers.
tab_control_feature_->set_outgoing_message_processor(
diff --git a/blimp/client/session/test_selfsigned_cert.pem b/blimp/client/session/test_selfsigned_cert.pem
new file mode 100644
index 0000000..de0e79f
--- /dev/null
+++ b/blimp/client/session/test_selfsigned_cert.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBmjCCAQOgAwIBAgIBATANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwh1bml0
+dGVzdDAeFw0xMDEyMjMwMjI5NDhaFw0xMDEyMjQwMjI5NDhaMBMxETAPBgNVBAMT
+CHVuaXR0ZXN0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUrDNORwXwkey6
+1BtbawRswIkKE81+eZhlIOpMyKayUhi4qB5qaAg0Mt0Of7SwXYA/Nk0ADzcbI+jn
+bl8y1gSaHN33I/OO9bEEwBtL2c+iF0Z9tI4iQ1lU2LQ2qiW8nfdQ21HUFbcnkk31
+vE8wNzh3c332RgVzvo5nzypVkamLgQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABu5
+toCzcK6zKviZe+Uj5EVRUMwDywwCA7FadW7JmgCVt6yQ9YXgkqZelk0aodKZs+eS
+WHuyx0EKVuZzaIiI2b/PKnfGVIvAu5Svzdqc8mlwEy4cBYoVFnFOIMzN93p9uUER
+Y8o1fBKQE2LhRv3v86PYez5EI7xbUc/5ai+9LkXe
+-----END CERTIFICATE-----