Commit 5ccbb9f7 authored by Yutaka Hirano's avatar Yutaka Hirano Committed by Commit Bot

Implement network::QuicTransport

Implement the handshake part.

Bug: 1011392
Change-Id: I6d652df766e26250e10dbe0bfc88bbe38b3fbe8d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1981238
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#727354}
parent 5403ad72
...@@ -120,6 +120,8 @@ jumbo_component("network_service") { ...@@ -120,6 +120,8 @@ jumbo_component("network_service") {
"proxy_resolving_socket_mojo.h", "proxy_resolving_socket_mojo.h",
"proxy_service_mojo.cc", "proxy_service_mojo.cc",
"proxy_service_mojo.h", "proxy_service_mojo.h",
"quic_transport.cc",
"quic_transport.h",
"resolve_host_request.cc", "resolve_host_request.cc",
"resolve_host_request.h", "resolve_host_request.h",
"resource_scheduler/resource_scheduler.cc", "resource_scheduler/resource_scheduler.cc",
...@@ -322,6 +324,7 @@ source_set("tests") { ...@@ -322,6 +324,7 @@ source_set("tests") {
"proxy_config_service_mojo_unittest.cc", "proxy_config_service_mojo_unittest.cc",
"proxy_resolving_client_socket_unittest.cc", "proxy_resolving_client_socket_unittest.cc",
"proxy_resolving_socket_mojo_unittest.cc", "proxy_resolving_socket_mojo_unittest.cc",
"quic_transport_unittest.cc",
"resource_scheduler/resource_scheduler_params_manager_unittest.cc", "resource_scheduler/resource_scheduler_params_manager_unittest.cc",
"resource_scheduler/resource_scheduler_unittest.cc", "resource_scheduler/resource_scheduler_unittest.cc",
"restricted_cookie_manager_unittest.cc", "restricted_cookie_manager_unittest.cc",
...@@ -387,6 +390,8 @@ source_set("tests") { ...@@ -387,6 +390,8 @@ source_set("tests") {
"//mojo/public/cpp/system", "//mojo/public/cpp/system",
"//net", "//net",
"//net:extras", "//net:extras",
"//net:quic_test_tools",
"//net:simple_quic_tools",
"//net:test_support", "//net:test_support",
"//net/http:transport_security_state_unittest_data_default", "//net/http:transport_security_state_unittest_data_default",
"//services/network/public/cpp", "//services/network/public/cpp",
......
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
#include "services/network/public/cpp/cert_verifier/cert_net_fetcher_url_loader.h" #include "services/network/public/cpp/cert_verifier/cert_net_fetcher_url_loader.h"
#include "services/network/public/cpp/features.h" #include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/network_switches.h" #include "services/network/public/cpp/network_switches.h"
#include "services/network/quic_transport.h"
#include "services/network/resolve_host_request.h" #include "services/network/resolve_host_request.h"
#include "services/network/resource_scheduler/resource_scheduler_client.h" #include "services/network/resource_scheduler/resource_scheduler_client.h"
#include "services/network/restricted_cookie_manager.h" #include "services/network/restricted_cookie_manager.h"
...@@ -590,6 +591,13 @@ void NetworkContext::DestroyURLLoaderFactory( ...@@ -590,6 +591,13 @@ void NetworkContext::DestroyURLLoaderFactory(
} }
} }
void NetworkContext::Remove(QuicTransport* transport) {
auto it = quic_transports_.find(transport);
if (it != quic_transports_.end()) {
quic_transports_.erase(it);
}
}
void NetworkContext::LoaderCreated(uint32_t process_id) { void NetworkContext::LoaderCreated(uint32_t process_id) {
loader_count_per_process_[process_id] += 1; loader_count_per_process_[process_id] += 1;
} }
......
...@@ -99,6 +99,7 @@ class P2PSocketManager; ...@@ -99,6 +99,7 @@ class P2PSocketManager;
class ProxyLookupRequest; class ProxyLookupRequest;
class ResourceScheduler; class ResourceScheduler;
class ResourceSchedulerClient; class ResourceSchedulerClient;
class QuicTransport;
class WebSocketFactory; class WebSocketFactory;
namespace cors { namespace cors {
...@@ -404,6 +405,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext ...@@ -404,6 +405,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
// no open pipes. // no open pipes.
void DestroyURLLoaderFactory(cors::CorsURLLoaderFactory* url_loader_factory); void DestroyURLLoaderFactory(cors::CorsURLLoaderFactory* url_loader_factory);
// Removes |transport| and destroys it.
void Remove(QuicTransport* transport);
// The following methods are used to track the number of requests per process // The following methods are used to track the number of requests per process
// and ensure it doesn't go over a reasonable limit. // and ensure it doesn't go over a reasonable limit.
void LoaderCreated(uint32_t process_id); void LoaderCreated(uint32_t process_id);
...@@ -463,6 +467,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext ...@@ -463,6 +467,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
const net::HttpAuthPreferences* GetHttpAuthPreferences() const; const net::HttpAuthPreferences* GetHttpAuthPreferences() const;
size_t num_open_quic_transports() const { return quic_transports_.size(); }
private: private:
URLRequestContextOwner MakeURLRequestContext( URLRequestContextOwner MakeURLRequestContext(
mojo::PendingReceiver<mojom::URLLoaderFactory>* mojo::PendingReceiver<mojom::URLLoaderFactory>*
...@@ -566,6 +572,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext ...@@ -566,6 +572,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
base::UniquePtrComparator> base::UniquePtrComparator>
url_loader_factories_; url_loader_factories_;
std::set<std::unique_ptr<QuicTransport>, base::UniquePtrComparator>
quic_transports_;
// A count of outstanding requests per initiating process. // A count of outstanding requests per initiating process.
std::map<uint32_t, uint32_t> loader_count_per_process_; std::map<uint32_t, uint32_t> loader_count_per_process_;
......
// Copyright 2019 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.
#include "services/network/quic_transport.h"
#include "services/network/network_context.h"
#include "services/network/public/mojom/quic_transport.mojom.h"
namespace network {
QuicTransport::QuicTransport(
const GURL& url,
const url::Origin& origin,
const net::NetworkIsolationKey& key,
NetworkContext* context,
mojo::PendingRemote<mojom::QuicTransportHandshakeClient> handshake_client)
: transport_(std::make_unique<net::QuicTransportClient>(
url,
origin,
this,
key,
context->url_request_context())),
context_(context),
receiver_(this),
handshake_client_(std::move(handshake_client)) {
handshake_client_.set_disconnect_handler(
base::BindOnce(&QuicTransport::Dispose, base::Unretained(this)));
transport_->Connect();
}
QuicTransport::~QuicTransport() = default;
void QuicTransport::OnConnected() {
DCHECK(handshake_client_);
handshake_client_->OnConnectionEstablished(
receiver_.BindNewPipeAndPassRemote(),
client_.BindNewPipeAndPassReceiver());
handshake_client_.reset();
client_.set_disconnect_handler(
base::BindOnce(&QuicTransport::Dispose, base::Unretained(this)));
}
void QuicTransport::OnConnectionFailed() {
DCHECK(handshake_client_);
handshake_client_->OnHandshakeFailed();
Dispose();
// |this| is deleted.
}
void QuicTransport::OnClosed() {
DCHECK(!handshake_client_);
Dispose();
// |this| is deleted.
}
void QuicTransport::OnError() {
DCHECK(!handshake_client_);
Dispose();
// |this| is deleted.
}
void QuicTransport::OnIncomingBidirectionalStreamAvailable() {}
void QuicTransport::OnIncomingUnidirectionalStreamAvailable() {}
void QuicTransport::Dispose() {
context_->Remove(this);
// |this| is deleted.
}
} // namespace network
// Copyright 2019 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.
#ifndef SERVICES_NETWORK_QUIC_TRANSPORT_H_
#define SERVICES_NETWORK_QUIC_TRANSPORT_H_
#include <memory>
#include "base/macros.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/quic/quic_transport_client.h"
#include "services/network/public/mojom/quic_transport.mojom.h"
class GURL;
namespace url {
class Origin;
} // namespace url
namespace net {
class NetworkIsolationKey;
} // namespace net
namespace network {
class NetworkContext;
// The implementation for QuicTransport
// (https://wicg.github.io/web-transport/#quic-transport) in the NetworkService.
// Implements mojom::QuicTransport with the net/ implementation.
class COMPONENT_EXPORT(NETWORK_SERVICE) QuicTransport final
: public mojom::QuicTransport,
public net::QuicTransportClient::Visitor {
public:
QuicTransport(const GURL& url,
const url::Origin& origin,
const net::NetworkIsolationKey& key,
NetworkContext* context,
mojo::PendingRemote<mojom::QuicTransportHandshakeClient>
handshake_client);
~QuicTransport() override;
// net::QuicTransportClient::Visitor implementation:
void OnConnected() override;
void OnConnectionFailed() override;
void OnClosed() override;
void OnError() override;
void OnIncomingBidirectionalStreamAvailable() override;
void OnIncomingUnidirectionalStreamAvailable() override;
void Dispose();
private:
const std::unique_ptr<net::QuicTransportClient> transport_;
NetworkContext* const context_; // outlives |this|.
mojo::Receiver<mojom::QuicTransport> receiver_;
mojo::Remote<mojom::QuicTransportHandshakeClient> handshake_client_;
mojo::Remote<mojom::QuicTransportClient> client_;
};
} // namespace network
#endif // SERVICES_NETWORK_QUIC_TRANSPORT_H_
// Copyright 2019 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.
#include "services/network/quic_transport.h"
#include "base/test/task_environment.h"
#include "net/cert/mock_cert_verifier.h"
#include "net/dns/mock_host_resolver.h"
#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
#include "net/tools/quic/quic_transport_simple_server.h"
#include "net/url_request/url_request_context.h"
#include "services/network/network_context.h"
#include "services/network/network_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace network {
namespace {
class TestHandshakeClient final : public mojom::QuicTransportHandshakeClient {
public:
TestHandshakeClient(mojo::PendingReceiver<mojom::QuicTransportHandshakeClient>
pending_receiver,
base::OnceClosure callback)
: receiver_(this, std::move(pending_receiver)),
callback_(std::move(callback)) {
receiver_.set_disconnect_handler(base::BindOnce(
&TestHandshakeClient::OnMojoConnectionError, base::Unretained(this)));
}
~TestHandshakeClient() override = default;
void OnConnectionEstablished(
mojo::PendingRemote<mojom::QuicTransport> transport,
mojo::PendingReceiver<mojom::QuicTransportClient> client_receiver)
override {
transport_ = std::move(transport);
client_receiver_ = std::move(client_receiver);
has_seen_connection_establishment_ = true;
receiver_.reset();
std::move(callback_).Run();
}
void OnHandshakeFailed() override {
has_seen_handshake_failure_ = true;
receiver_.reset();
std::move(callback_).Run();
}
void OnMojoConnectionError() {
has_seen_handshake_failure_ = true;
std::move(callback_).Run();
}
mojo::PendingRemote<mojom::QuicTransport> PassTransport() {
return std::move(transport_);
}
mojo::PendingReceiver<mojom::QuicTransportClient> PassClientReceiver() {
return std::move(client_receiver_);
}
bool has_seen_connection_establishment() const {
return has_seen_connection_establishment_;
}
bool has_seen_handshake_failure() const {
return has_seen_handshake_failure_;
}
bool has_seen_mojo_connection_error() const {
return has_seen_mojo_connection_error_;
}
private:
mojo::Receiver<mojom::QuicTransportHandshakeClient> receiver_;
mojo::PendingRemote<mojom::QuicTransport> transport_;
mojo::PendingReceiver<mojom::QuicTransportClient> client_receiver_;
base::OnceClosure callback_;
bool has_seen_connection_establishment_ = false;
bool has_seen_handshake_failure_ = false;
bool has_seen_mojo_connection_error_ = false;
};
class QuicTransportTest : public testing::Test {
public:
QuicTransportTest()
: origin_(url::Origin::Create(GURL("https://example.org/"))),
task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
network_service_(NetworkService::CreateForTesting()),
network_context_remote_(mojo::NullRemote()),
network_context_(network_service_.get(),
network_context_remote_.BindNewPipeAndPassReceiver(),
mojom::NetworkContextParams::New()),
server_(/* port= */ 0,
{origin_},
quic::test::crypto_test_utils::ProofSourceForTesting()) {
EXPECT_EQ(EXIT_SUCCESS, server_.Start());
cert_verifier_.set_default_result(net::OK);
host_resolver_.rules()->AddRule("test.example.com", "127.0.0.1");
network_context_.url_request_context()->set_cert_verifier(&cert_verifier_);
network_context_.url_request_context()->set_host_resolver(&host_resolver_);
auto* quic_context = network_context_.url_request_context()->quic_context();
quic_context->params()->supported_versions.push_back(
quic::ParsedQuicVersion{quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_99});
quic_context->params()->origins_to_force_quic_on.insert(
net::HostPortPair("test.example.com", 0));
}
~QuicTransportTest() override = default;
std::unique_ptr<QuicTransport> CreateQuicTransport(
const GURL& url,
const url::Origin& origin,
const net::NetworkIsolationKey& key,
mojo::PendingRemote<mojom::QuicTransportHandshakeClient>
handshake_client) {
return std::make_unique<QuicTransport>(url, origin, key, &network_context_,
std::move(handshake_client));
}
std::unique_ptr<QuicTransport> CreateQuicTransport(
const GURL& url,
const url::Origin& origin,
mojo::PendingRemote<mojom::QuicTransportHandshakeClient>
handshake_client) {
return CreateQuicTransport(url, origin, net::NetworkIsolationKey(),
std::move(handshake_client));
}
GURL GetURL(base::StringPiece suffix) {
return GURL(quiche::QuicheStrCat("quic-transport://test.example.com:",
server_.server_address().port(), suffix));
}
const url::Origin& origin() const { return origin_; }
const NetworkContext& network_context() const { return network_context_; }
private:
const url::Origin origin_;
base::test::TaskEnvironment task_environment_;
std::unique_ptr<NetworkService> network_service_;
mojo::Remote<mojom::NetworkContext> network_context_remote_;
net::MockCertVerifier cert_verifier_;
net::MockHostResolver host_resolver_;
NetworkContext network_context_;
net::QuicTransportSimpleServer server_;
};
TEST_F(QuicTransportTest, ConnectSuccessfully) {
base::RunLoop run_loop_for_handshake;
mojo::PendingRemote<mojom::QuicTransportHandshakeClient> handshake_client;
TestHandshakeClient test_handshake_client(
handshake_client.InitWithNewPipeAndPassReceiver(),
run_loop_for_handshake.QuitClosure());
auto transport = CreateQuicTransport(GetURL("/discard"), origin(),
std::move(handshake_client));
run_loop_for_handshake.Run();
EXPECT_TRUE(test_handshake_client.has_seen_connection_establishment());
EXPECT_FALSE(test_handshake_client.has_seen_handshake_failure());
EXPECT_FALSE(test_handshake_client.has_seen_mojo_connection_error());
}
TEST_F(QuicTransportTest, ConnectWithError) {
base::RunLoop run_loop_for_handshake;
mojo::PendingRemote<mojom::QuicTransportHandshakeClient> handshake_client;
TestHandshakeClient test_handshake_client(
handshake_client.InitWithNewPipeAndPassReceiver(),
run_loop_for_handshake.QuitClosure());
// This should fail due to the wrong origin
auto transport = CreateQuicTransport(
GetURL("/discard"), url::Origin::Create(GURL("https://evil.com")),
std::move(handshake_client));
run_loop_for_handshake.Run();
// TODO(vasilvv): This should fail, but now succeeds due to a bug in net/.
EXPECT_TRUE(test_handshake_client.has_seen_connection_establishment());
EXPECT_FALSE(test_handshake_client.has_seen_handshake_failure());
EXPECT_FALSE(test_handshake_client.has_seen_mojo_connection_error());
}
} // namespace
} // namespace network
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