123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- // Copyright 2018 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 <string>
- #include <utility>
- #include <vector>
- #include "base/containers/span.h"
- #include "base/run_loop.h"
- #include "base/strings/stringprintf.h"
- #include "base/test/bind.h"
- #include "base/test/task_environment.h"
- #include "components/webrtc/fake_ssl_client_socket.h"
- #include "mojo/public/cpp/bindings/pending_receiver.h"
- #include "mojo/public/cpp/bindings/pending_remote.h"
- #include "mojo/public/cpp/bindings/receiver.h"
- #include "mojo/public/cpp/bindings/remote.h"
- #include "mojo/public/cpp/system/data_pipe_utils.h"
- #include "net/base/net_errors.h"
- #include "net/base/network_isolation_key.h"
- #include "net/base/test_completion_callback.h"
- #include "net/dns/mock_host_resolver.h"
- #include "net/proxy_resolution/configured_proxy_resolution_service.h"
- #include "net/socket/socket_test_util.h"
- #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
- #include "net/url_request/url_request_context_builder.h"
- #include "net/url_request/url_request_test_util.h"
- #include "services/network/mojo_socket_test_util.h"
- #include "services/network/proxy_resolving_socket_factory_mojo.h"
- #include "services/network/proxy_resolving_socket_mojo.h"
- #include "services/network/socket_factory.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace network {
- class ProxyResolvingSocketTestBase {
- public:
- ProxyResolvingSocketTestBase(bool use_tls)
- : use_tls_(use_tls),
- fake_tls_handshake_(false),
- task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
- ProxyResolvingSocketTestBase(const ProxyResolvingSocketTestBase&) = delete;
- ProxyResolvingSocketTestBase& operator=(const ProxyResolvingSocketTestBase&) =
- delete;
- ~ProxyResolvingSocketTestBase() {}
- void Init(const std::string& pac_result) {
- // Init() can be called multiple times in a test. Reset the members for each
- // invocation. `context_` must outlive `factory_impl_`, which uses the
- // URLRequestContext.
- factory_receiver_ = nullptr;
- factory_impl_ = nullptr;
- factory_remote_.reset();
- context_ = nullptr;
- mock_client_socket_factory_ =
- std::make_unique<net::MockClientSocketFactory>();
- mock_client_socket_factory_->set_enable_read_if_ready(true);
- auto context_builder = net::CreateTestURLRequestContextBuilder();
- context_builder->set_proxy_resolution_service(
- net::ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- pac_result, TRAFFIC_ANNOTATION_FOR_TESTS));
- context_builder->set_client_socket_factory_for_testing(
- mock_client_socket_factory_.get());
- context_ = context_builder->Build();
- factory_impl_ =
- std::make_unique<ProxyResolvingSocketFactoryMojo>(context_.get());
- factory_receiver_ =
- std::make_unique<mojo::Receiver<mojom::ProxyResolvingSocketFactory>>(
- factory_impl_.get(), factory_remote_.BindNewPipeAndPassReceiver());
- }
- // Reads |num_bytes| from |handle| or reads until an error occurs. Returns the
- // bytes read as a string.
- std::string Read(mojo::ScopedDataPipeConsumerHandle* handle,
- size_t num_bytes) {
- std::string received_contents;
- while (received_contents.size() < num_bytes) {
- base::RunLoop().RunUntilIdle();
- std::vector<char> buffer(num_bytes);
- uint32_t read_size =
- static_cast<uint32_t>(num_bytes - received_contents.size());
- MojoResult result = handle->get().ReadData(buffer.data(), &read_size,
- MOJO_READ_DATA_FLAG_NONE);
- if (result == MOJO_RESULT_SHOULD_WAIT)
- continue;
- if (result != MOJO_RESULT_OK)
- return received_contents;
- received_contents.append(buffer.data(), read_size);
- }
- return received_contents;
- }
- int CreateSocketSync(
- mojo::PendingReceiver<mojom::ProxyResolvingSocket> receiver,
- mojo::PendingRemote<mojom::SocketObserver> socket_observer,
- net::IPEndPoint* peer_addr_out,
- const GURL& url,
- mojo::ScopedDataPipeConsumerHandle* receive_pipe_handle_out,
- mojo::ScopedDataPipeProducerHandle* send_pipe_handle_out) {
- base::RunLoop run_loop;
- int net_error = net::ERR_FAILED;
- network::mojom::ProxyResolvingSocketOptionsPtr options =
- network::mojom::ProxyResolvingSocketOptions::New();
- options->use_tls = use_tls_;
- options->fake_tls_handshake = fake_tls_handshake_;
- factory_remote_->CreateProxyResolvingSocket(
- url, net::NetworkIsolationKey(), std::move(options),
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
- std::move(receiver), std::move(socket_observer),
- base::BindLambdaForTesting(
- [&](int result, const absl::optional<net::IPEndPoint>& local_addr,
- const absl::optional<net::IPEndPoint>& peer_addr,
- mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
- mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
- net_error = result;
- if (net_error == net::OK)
- EXPECT_NE(0, local_addr.value().port());
- if (peer_addr_out && peer_addr)
- *peer_addr_out = peer_addr.value();
- *receive_pipe_handle_out = std::move(receive_pipe_handle);
- *send_pipe_handle_out = std::move(send_pipe_handle);
- run_loop.Quit();
- }));
- run_loop.Run();
- return net_error;
- }
- net::MockClientSocketFactory* mock_client_socket_factory() {
- return mock_client_socket_factory_.get();
- }
- bool use_tls() const { return use_tls_; }
- void set_fake_tls_handshake(bool val) { fake_tls_handshake_ = val; }
- mojom::ProxyResolvingSocketFactory* factory() {
- return factory_remote_.get();
- }
- private:
- const bool use_tls_;
- bool fake_tls_handshake_;
- base::test::TaskEnvironment task_environment_;
- std::unique_ptr<net::MockClientSocketFactory> mock_client_socket_factory_;
- std::unique_ptr<net::URLRequestContext> context_;
- mojo::Remote<mojom::ProxyResolvingSocketFactory> factory_remote_;
- std::unique_ptr<mojo::Receiver<mojom::ProxyResolvingSocketFactory>>
- factory_receiver_;
- std::unique_ptr<ProxyResolvingSocketFactoryMojo> factory_impl_;
- };
- class ProxyResolvingSocketTest : public ProxyResolvingSocketTestBase,
- public testing::TestWithParam<bool> {
- public:
- ProxyResolvingSocketTest() : ProxyResolvingSocketTestBase(GetParam()) {}
- ProxyResolvingSocketTest(const ProxyResolvingSocketTest&) = delete;
- ProxyResolvingSocketTest& operator=(const ProxyResolvingSocketTest&) = delete;
- ~ProxyResolvingSocketTest() override {}
- };
- INSTANTIATE_TEST_SUITE_P(All,
- ProxyResolvingSocketTest,
- ::testing::Bool());
- // Tests that the connection is established to the proxy.
- TEST_P(ProxyResolvingSocketTest, ConnectToProxy) {
- const GURL kDestination("https://example.com:443");
- const int kProxyPort = 8009;
- const int kDirectPort = 443;
- for (bool is_direct : {true, false}) {
- net::MockClientSocketFactory socket_factory;
- std::unique_ptr<net::URLRequestContext> context;
- if (is_direct) {
- Init("DIRECT");
- } else {
- Init(base::StringPrintf("PROXY myproxy.com:%d", kProxyPort));
- }
- // Note that this read is not consumed when |!is_direct|.
- net::MockRead reads[] = {net::MockRead("HTTP/1.1 200 Success\r\n\r\n"),
- net::MockRead(net::ASYNC, net::OK)};
- // Note that this write is not consumed when |is_direct|.
- net::MockWrite writes[] = {
- net::MockWrite("CONNECT example.com:443 HTTP/1.1\r\n"
- "Host: example.com:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n")};
- net::SSLSocketDataProvider ssl_socket(net::ASYNC, net::OK);
- mock_client_socket_factory()->AddSSLSocketDataProvider(&ssl_socket);
- net::StaticSocketDataProvider socket_data(reads, writes);
- net::IPEndPoint remote_addr(net::IPAddress(127, 0, 0, 1),
- is_direct ? kDirectPort : kProxyPort);
- socket_data.set_connect_data(
- net::MockConnect(net::ASYNC, net::OK, remote_addr));
- mock_client_socket_factory()->AddSocketDataProvider(&socket_data);
- mojo::PendingRemote<mojom::ProxyResolvingSocket> socket;
- mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
- mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
- net::IPEndPoint actual_remote_addr;
- EXPECT_EQ(net::OK, CreateSocketSync(socket.InitWithNewPipeAndPassReceiver(),
- mojo::NullRemote() /* socket_observer*/,
- &actual_remote_addr, kDestination,
- &client_socket_receive_handle,
- &client_socket_send_handle));
- // Consume all read data.
- base::RunLoop().RunUntilIdle();
- if (!is_direct) {
- EXPECT_EQ(net::IPEndPoint(), actual_remote_addr);
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- } else {
- EXPECT_EQ(remote_addr.ToString(), actual_remote_addr.ToString());
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_FALSE(socket_data.AllWriteDataConsumed());
- }
- EXPECT_EQ(use_tls(), ssl_socket.ConnectDataConsumed());
- }
- }
- TEST_P(ProxyResolvingSocketTest, ConnectError) {
- const struct TestData {
- // Whether the error is encountered synchronously as opposed to
- // asynchronously.
- bool is_error_sync;
- // Whether it is using a direct connection as opposed to a proxy connection.
- bool is_direct;
- } kTestCases[] = {
- {true, true}, {true, false}, {false, true}, {false, false},
- };
- const GURL kDestination("https://example.com:443");
- for (auto test : kTestCases) {
- std::unique_ptr<net::URLRequestContext> context;
- if (test.is_direct) {
- Init("DIRECT");
- } else {
- Init("PROXY myproxy.com:89");
- }
- net::StaticSocketDataProvider socket_data;
- socket_data.set_connect_data(net::MockConnect(
- test.is_error_sync ? net::SYNCHRONOUS : net::ASYNC, net::ERR_FAILED));
- mock_client_socket_factory()->AddSocketDataProvider(&socket_data);
- mojo::PendingRemote<mojom::ProxyResolvingSocket> socket;
- mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
- mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
- int status = CreateSocketSync(socket.InitWithNewPipeAndPassReceiver(),
- mojo::NullRemote() /* socket_observer*/,
- nullptr /* peer_addr_out */, kDestination,
- &client_socket_receive_handle,
- &client_socket_send_handle);
- if (test.is_direct) {
- EXPECT_EQ(net::ERR_FAILED, status);
- } else {
- EXPECT_EQ(net::ERR_PROXY_CONNECTION_FAILED, status);
- }
- EXPECT_TRUE(socket_data.AllReadDataConsumed());
- EXPECT_TRUE(socket_data.AllWriteDataConsumed());
- }
- }
- // Tests writing to and reading from a mojom::ProxyResolvingSocket.
- TEST_P(ProxyResolvingSocketTest, BasicReadWrite) {
- Init("DIRECT");
- mojo::PendingRemote<mojom::ProxyResolvingSocket> socket;
- const char kTestMsg[] = "abcdefghij";
- const size_t kMsgSize = strlen(kTestMsg);
- const int kNumIterations = 3;
- std::vector<net::MockRead> reads;
- std::vector<net::MockWrite> writes;
- int sequence_number = 0;
- for (int j = 0; j < kNumIterations; ++j) {
- for (size_t i = 0; i < kMsgSize; ++i) {
- reads.push_back(
- net::MockRead(net::ASYNC, &kTestMsg[i], 1, sequence_number++));
- }
- if (j == kNumIterations - 1) {
- reads.push_back(net::MockRead(net::ASYNC, net::OK, sequence_number++));
- }
- for (size_t i = 0; i < kMsgSize; ++i) {
- writes.push_back(
- net::MockWrite(net::ASYNC, &kTestMsg[i], 1, sequence_number++));
- }
- }
- net::StaticSocketDataProvider data_provider(reads, writes);
- data_provider.set_connect_data(net::MockConnect(net::SYNCHRONOUS, net::OK));
- mock_client_socket_factory()->AddSocketDataProvider(&data_provider);
- net::SSLSocketDataProvider ssl_data(net::ASYNC, net::OK);
- mock_client_socket_factory()->AddSSLSocketDataProvider(&ssl_data);
- mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
- mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
- const GURL kDestination("http://example.com");
- EXPECT_EQ(net::OK, CreateSocketSync(socket.InitWithNewPipeAndPassReceiver(),
- mojo::NullRemote() /* socket_observer */,
- nullptr /* peer_addr_out */, kDestination,
- &client_socket_receive_handle,
- &client_socket_send_handle));
- // Loop kNumIterations times to test that writes can follow reads, and reads
- // can follow writes.
- for (int j = 0; j < kNumIterations; ++j) {
- // Reading kMsgSize should coalesce the 1-byte mock reads.
- EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, kMsgSize));
- // Write multiple times.
- for (size_t i = 0; i < kMsgSize; ++i) {
- uint32_t num_bytes = 1;
- EXPECT_EQ(MOJO_RESULT_OK,
- client_socket_send_handle->WriteData(
- &kTestMsg[i], &num_bytes, MOJO_WRITE_DATA_FLAG_NONE));
- // Flush the 1 byte write.
- base::RunLoop().RunUntilIdle();
- }
- }
- EXPECT_TRUE(data_provider.AllReadDataConsumed());
- EXPECT_TRUE(data_provider.AllWriteDataConsumed());
- EXPECT_EQ(use_tls(), ssl_data.ConnectDataConsumed());
- }
- // Tests that exercise logic related to mojo.
- class ProxyResolvingSocketMojoTest : public ProxyResolvingSocketTestBase,
- public testing::Test {
- public:
- ProxyResolvingSocketMojoTest() : ProxyResolvingSocketTestBase(false) {}
- ProxyResolvingSocketMojoTest(const ProxyResolvingSocketMojoTest&) = delete;
- ProxyResolvingSocketMojoTest& operator=(const ProxyResolvingSocketMojoTest&) =
- delete;
- ~ProxyResolvingSocketMojoTest() override {}
- };
- TEST_F(ProxyResolvingSocketMojoTest, ConnectWithFakeTLSHandshake) {
- const GURL kDestination("https://example.com:443");
- const char kTestMsg[] = "abcdefghij";
- const size_t kMsgSize = strlen(kTestMsg);
- Init("DIRECT");
- set_fake_tls_handshake(true);
- base::StringPiece client_hello =
- webrtc::FakeSSLClientSocket::GetSslClientHello();
- base::StringPiece server_hello =
- webrtc::FakeSSLClientSocket::GetSslServerHello();
- std::vector<net::MockRead> reads = {
- net::MockRead(net::ASYNC, server_hello.data(), server_hello.length(), 1),
- net::MockRead(net::ASYNC, 2, kTestMsg),
- net::MockRead(net::ASYNC, net::OK, 3)};
- std::vector<net::MockWrite> writes = {net::MockWrite(
- net::ASYNC, client_hello.data(), client_hello.length(), 0)};
- net::StaticSocketDataProvider data_provider(reads, writes);
- data_provider.set_connect_data(net::MockConnect(net::ASYNC, net::OK));
- mock_client_socket_factory()->AddSocketDataProvider(&data_provider);
- mojo::PendingRemote<mojom::ProxyResolvingSocket> socket;
- mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
- mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
- net::IPEndPoint actual_remote_addr;
- EXPECT_EQ(net::OK, CreateSocketSync(socket.InitWithNewPipeAndPassReceiver(),
- mojo::NullRemote() /* socket_observer*/,
- &actual_remote_addr, kDestination,
- &client_socket_receive_handle,
- &client_socket_send_handle));
- EXPECT_EQ(kTestMsg, Read(&client_socket_receive_handle, kMsgSize));
- EXPECT_TRUE(data_provider.AllReadDataConsumed());
- EXPECT_TRUE(data_provider.AllWriteDataConsumed());
- }
- // Tests that when ProxyResolvingSocket remote is destroyed but not the
- // ProxyResolvingSocketFactory, the connect callback is not dropped.
- // Regression test for https://crbug.com/862608.
- TEST_F(ProxyResolvingSocketMojoTest, SocketDestroyedBeforeConnectCompletes) {
- Init("DIRECT");
- std::vector<net::MockRead> reads;
- std::vector<net::MockWrite> writes;
- net::StaticSocketDataProvider data_provider(reads, writes);
- data_provider.set_connect_data(net::MockConnect(net::ASYNC, net::OK));
- mock_client_socket_factory()->AddSocketDataProvider(&data_provider);
- const GURL kDestination("http://example.com");
- mojo::PendingRemote<mojom::ProxyResolvingSocket> socket;
- base::RunLoop run_loop;
- int net_error = net::OK;
- factory()->CreateProxyResolvingSocket(
- kDestination, net::NetworkIsolationKey(), nullptr,
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
- socket.InitWithNewPipeAndPassReceiver(),
- mojo::NullRemote() /* observer */,
- base::BindLambdaForTesting(
- [&](int result, const absl::optional<net::IPEndPoint>& local_addr,
- const absl::optional<net::IPEndPoint>& peer_addr,
- mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
- mojo::ScopedDataPipeProducerHandle send_pipe_handle) {
- net_error = result;
- }));
- socket.reset();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(net::ERR_ABORTED, net_error);
- }
- TEST_F(ProxyResolvingSocketMojoTest, SocketObserver) {
- Init("DIRECT");
- const char kMsg[] = "message!";
- const char kMsgLen = strlen(kMsg);
- std::vector<net::MockRead> reads = {
- net::MockRead(kMsg),
- net::MockRead(net::ASYNC, net::ERR_CONNECTION_ABORTED)};
- std::vector<net::MockWrite> writes = {
- net::MockWrite(net::ASYNC, net::ERR_TIMED_OUT)};
- net::StaticSocketDataProvider data_provider(reads, writes);
- data_provider.set_connect_data(net::MockConnect(net::ASYNC, net::OK));
- mock_client_socket_factory()->AddSocketDataProvider(&data_provider);
- const GURL kDestination("http://example.com");
- mojo::PendingRemote<mojom::ProxyResolvingSocket> socket;
- mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
- mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
- TestSocketObserver test_observer;
- int status = CreateSocketSync(
- socket.InitWithNewPipeAndPassReceiver(),
- test_observer.GetObserverRemote(), nullptr /* peer_addr_out */,
- kDestination, &client_socket_receive_handle, &client_socket_send_handle);
- EXPECT_EQ(net::OK, status);
- EXPECT_EQ(kMsg, Read(&client_socket_receive_handle, kMsgLen));
- EXPECT_EQ(net::ERR_CONNECTION_ABORTED, test_observer.WaitForReadError());
- EXPECT_TRUE(mojo::BlockingCopyFromString(kMsg, client_socket_send_handle));
- EXPECT_EQ(net::ERR_TIMED_OUT, test_observer.WaitForWriteError());
- EXPECT_TRUE(data_provider.AllReadDataConsumed());
- EXPECT_TRUE(data_provider.AllWriteDataConsumed());
- }
- } // namespace network
|