1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <stdint.h>
6 
7 #include <string>
8 #include <utility>
9 #include <vector>
10 
11 #include "base/bind.h"
12 #include "base/run_loop.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/test/bind_test_util.h"
15 #include "base/test/task_environment.h"
16 #include "build/build_config.h"
17 #include "mojo/public/cpp/bindings/pending_remote.h"
18 #include "mojo/public/cpp/bindings/remote.h"
19 #include "mojo/public/cpp/system/data_pipe_utils.h"
20 #include "mojo/public/cpp/system/simple_watcher.h"
21 #include "mojo/public/cpp/system/wait.h"
22 #include "net/base/address_list.h"
23 #include "net/base/ip_address.h"
24 #include "net/base/ip_endpoint.h"
25 #include "net/base/net_errors.h"
26 #include "net/test/embedded_test_server/embedded_test_server.h"
27 #include "net/test/embedded_test_server/http_request.h"
28 #include "net/test/embedded_test_server/http_response.h"
29 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
30 #include "net/url_request/url_request_test_util.h"
31 #include "services/network/mojo_socket_test_util.h"
32 #include "services/network/public/mojom/tcp_socket.mojom.h"
33 #include "services/network/socket_factory.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35 
36 namespace network {
37 namespace {
38 
39 class TCPBoundSocketTest : public testing::Test {
40  public:
TCPBoundSocketTest()41   TCPBoundSocketTest()
42       : task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
43         factory_(nullptr /* net_log */, &url_request_context_) {}
~TCPBoundSocketTest()44   ~TCPBoundSocketTest() override {}
45 
factory()46   SocketFactory* factory() { return &factory_; }
47 
BindSocket(const net::IPEndPoint & ip_endpoint_in,mojo::Remote<mojom::TCPBoundSocket> * bound_socket,net::IPEndPoint * ip_endpoint_out)48   int BindSocket(const net::IPEndPoint& ip_endpoint_in,
49                  mojo::Remote<mojom::TCPBoundSocket>* bound_socket,
50                  net::IPEndPoint* ip_endpoint_out) {
51     base::RunLoop run_loop;
52     int bind_result = net::ERR_IO_PENDING;
53     factory()->CreateTCPBoundSocket(
54         ip_endpoint_in, TRAFFIC_ANNOTATION_FOR_TESTS,
55         bound_socket->BindNewPipeAndPassReceiver(),
56         base::BindLambdaForTesting(
57             [&](int net_error,
58                 const base::Optional<net::IPEndPoint>& local_addr) {
59               bind_result = net_error;
60               if (net_error == net::OK) {
61                 *ip_endpoint_out = *local_addr;
62               } else {
63                 EXPECT_FALSE(local_addr);
64               }
65               run_loop.Quit();
66             }));
67     run_loop.Run();
68 
69     // On error, |bound_socket| should be closed.
70     if (bind_result != net::OK && bound_socket->is_connected()) {
71       base::RunLoop close_pipe_run_loop;
72       bound_socket->set_disconnect_handler(close_pipe_run_loop.QuitClosure());
73       close_pipe_run_loop.Run();
74     }
75     return bind_result;
76   }
77 
Listen(mojo::Remote<mojom::TCPBoundSocket> bound_socket,mojo::Remote<mojom::TCPServerSocket> * server_socket)78   int Listen(mojo::Remote<mojom::TCPBoundSocket> bound_socket,
79              mojo::Remote<mojom::TCPServerSocket>* server_socket) {
80     base::RunLoop bound_socket_destroyed_run_loop;
81     bound_socket.set_disconnect_handler(
82         bound_socket_destroyed_run_loop.QuitClosure());
83 
84     base::RunLoop run_loop;
85     int listen_result = net::ERR_IO_PENDING;
86     bound_socket->Listen(1 /* backlog */,
87                          server_socket->BindNewPipeAndPassReceiver(),
88                          base::BindLambdaForTesting([&](int net_error) {
89                            listen_result = net_error;
90                            run_loop.Quit();
91                          }));
92     run_loop.Run();
93 
94     // Whether Bind() fails or succeeds, |bound_socket| is destroyed.
95     bound_socket_destroyed_run_loop.Run();
96 
97     // On error, |server_socket| should be closed.
98     if (listen_result != net::OK && server_socket->is_connected()) {
99       base::RunLoop close_pipe_run_loop;
100       server_socket->set_disconnect_handler(close_pipe_run_loop.QuitClosure());
101       close_pipe_run_loop.Run();
102     }
103 
104     return listen_result;
105   }
106 
Connect(mojo::Remote<mojom::TCPBoundSocket> bound_socket,const net::IPEndPoint & expected_local_addr,const net::IPEndPoint & connect_to_addr,mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options,mojo::Remote<mojom::TCPConnectedSocket> * connected_socket,mojo::PendingRemote<mojom::SocketObserver> socket_observer,mojo::ScopedDataPipeConsumerHandle * client_socket_receive_handle,mojo::ScopedDataPipeProducerHandle * client_socket_send_handle)107   int Connect(mojo::Remote<mojom::TCPBoundSocket> bound_socket,
108               const net::IPEndPoint& expected_local_addr,
109               const net::IPEndPoint& connect_to_addr,
110               mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options,
111               mojo::Remote<mojom::TCPConnectedSocket>* connected_socket,
112               mojo::PendingRemote<mojom::SocketObserver> socket_observer,
113               mojo::ScopedDataPipeConsumerHandle* client_socket_receive_handle,
114               mojo::ScopedDataPipeProducerHandle* client_socket_send_handle) {
115     base::RunLoop bound_socket_destroyed_run_loop;
116     bound_socket.set_disconnect_handler(
117         bound_socket_destroyed_run_loop.QuitClosure());
118 
119     int connect_result = net::ERR_IO_PENDING;
120     base::RunLoop run_loop;
121     bound_socket->Connect(
122         net::AddressList(connect_to_addr),
123         std::move(tcp_connected_socket_options),
124         connected_socket->BindNewPipeAndPassReceiver(),
125         std::move(socket_observer),
126         base::BindLambdaForTesting(
127             [&](int net_error,
128                 const base::Optional<net::IPEndPoint>& local_addr,
129                 const base::Optional<net::IPEndPoint>& remote_addr,
130                 mojo::ScopedDataPipeConsumerHandle receive_stream,
131                 mojo::ScopedDataPipeProducerHandle send_stream) {
132               connect_result = net_error;
133               if (net_error == net::OK) {
134                 EXPECT_EQ(expected_local_addr, *local_addr);
135                 EXPECT_EQ(connect_to_addr, *remote_addr);
136                 *client_socket_receive_handle = std::move(receive_stream);
137                 *client_socket_send_handle = std::move(send_stream);
138               } else {
139                 EXPECT_FALSE(local_addr);
140                 EXPECT_FALSE(remote_addr);
141                 EXPECT_FALSE(receive_stream.is_valid());
142                 EXPECT_FALSE(send_stream.is_valid());
143               }
144               run_loop.Quit();
145             }));
146     run_loop.Run();
147 
148     // Whether Bind() fails or succeeds, |bound_socket| is destroyed.
149     bound_socket_destroyed_run_loop.Run();
150 
151     // On error, |connected_socket| should be closed.
152     if (connect_result != net::OK && connected_socket->is_connected()) {
153       base::RunLoop close_pipe_run_loop;
154       connected_socket->set_disconnect_handler(
155           close_pipe_run_loop.QuitClosure());
156       close_pipe_run_loop.Run();
157     }
158 
159     return connect_result;
160   }
161 
162   // Attempts to read exactly |expected_bytes| from |receive_handle|, or reads
163   // until the pipe is closed if |expected_bytes| is 0.
ReadData(mojo::DataPipeConsumerHandle receive_handle,uint32_t expected_bytes=0)164   std::string ReadData(mojo::DataPipeConsumerHandle receive_handle,
165                        uint32_t expected_bytes = 0) {
166     std::string read_data;
167     while (expected_bytes == 0 || read_data.size() < expected_bytes) {
168       const void* buffer;
169       uint32_t num_bytes = expected_bytes - read_data.size();
170       MojoResult result = receive_handle.BeginReadData(
171           &buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
172       if (result == MOJO_RESULT_SHOULD_WAIT) {
173         task_environment_.RunUntilIdle();
174         continue;
175       }
176       if (result != MOJO_RESULT_OK) {
177         if (expected_bytes != 0)
178           ADD_FAILURE() << "Read failed";
179         return read_data;
180       }
181       read_data.append(static_cast<const char*>(buffer), num_bytes);
182       receive_handle.EndReadData(num_bytes);
183     }
184 
185     return read_data;
186   }
187 
LocalHostWithAnyPort()188   static net::IPEndPoint LocalHostWithAnyPort() {
189     return net::IPEndPoint(net::IPAddress::IPv4Localhost(), 0 /* port */);
190   }
191 
task_environment()192   base::test::TaskEnvironment* task_environment() { return &task_environment_; }
193 
194  private:
195   base::test::TaskEnvironment task_environment_;
196   net::TestURLRequestContext url_request_context_;
197   SocketFactory factory_;
198 
199   DISALLOW_COPY_AND_ASSIGN(TCPBoundSocketTest);
200 };
201 
202 // Try to bind a socket to an address already being listened on, which should
203 // fail.
TEST_F(TCPBoundSocketTest,BindError)204 TEST_F(TCPBoundSocketTest, BindError) {
205   // Set up a listening socket.
206   mojo::Remote<mojom::TCPBoundSocket> bound_socket1;
207   net::IPEndPoint bound_address1;
208   ASSERT_EQ(net::OK, BindSocket(LocalHostWithAnyPort(), &bound_socket1,
209                                 &bound_address1));
210   mojo::Remote<mojom::TCPServerSocket> server_socket;
211   ASSERT_EQ(net::OK, Listen(std::move(bound_socket1), &server_socket));
212 
213   // Try to bind another socket to the listening socket's address.
214   mojo::Remote<mojom::TCPBoundSocket> bound_socket2;
215   net::IPEndPoint bound_address2;
216   int result = BindSocket(bound_address1, &bound_socket2, &bound_address2);
217   // Depending on platform, can get different errors. Some platforms can return
218   // either error.
219   EXPECT_TRUE(result == net::ERR_ADDRESS_IN_USE ||
220               result == net::ERR_INVALID_ARGUMENT);
221 }
222 
223 // Test the case of a connect error. To cause a connect error, bind a socket,
224 // but don't listen on it, and then try connecting to it using another bound
225 // socket.
226 //
227 // Don't run on Apple platforms because this pattern ends in a connect timeout
228 // on OSX (after 25+ seconds) instead of connection refused.
229 #if !defined(OS_MACOSX) && !defined(OS_IOS)
TEST_F(TCPBoundSocketTest,ConnectError)230 TEST_F(TCPBoundSocketTest, ConnectError) {
231   mojo::Remote<mojom::TCPBoundSocket> bound_socket1;
232   net::IPEndPoint bound_address1;
233   ASSERT_EQ(net::OK, BindSocket(LocalHostWithAnyPort(), &bound_socket1,
234                                 &bound_address1));
235 
236   // Trying to bind to an address currently being used for listening should
237   // fail.
238   mojo::Remote<mojom::TCPBoundSocket> bound_socket2;
239   net::IPEndPoint bound_address2;
240   ASSERT_EQ(net::OK, BindSocket(LocalHostWithAnyPort(), &bound_socket2,
241                                 &bound_address2));
242   mojo::Remote<mojom::TCPConnectedSocket> connected_socket;
243   mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
244   mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
245   EXPECT_EQ(net::ERR_CONNECTION_REFUSED,
246             Connect(std::move(bound_socket2), bound_address2, bound_address1,
247                     nullptr /* tcp_connected_socket_options */,
248                     &connected_socket, mojo::NullRemote(),
249                     &client_socket_receive_handle, &client_socket_send_handle));
250 }
251 #endif  // !defined(OS_MACOSX) && !defined(OS_IOS)
252 
253 // Test listen failure.
254 
255 // All platforms except Windows use SO_REUSEADDR on server sockets by default,
256 // which allows binding multiple sockets to the same port at once, as long as
257 // nothing is listening on it yet.
258 //
259 // Apple platforms don't allow binding multiple TCP sockets to the same port
260 // even with SO_REUSEADDR enabled.
261 #if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_IOS)
TEST_F(TCPBoundSocketTest,ListenError)262 TEST_F(TCPBoundSocketTest, ListenError) {
263   // Bind a socket.
264   mojo::Remote<mojom::TCPBoundSocket> bound_socket1;
265   net::IPEndPoint bound_address1;
266   ASSERT_EQ(net::OK, BindSocket(LocalHostWithAnyPort(), &bound_socket1,
267                                 &bound_address1));
268 
269   // Bind another socket to the same address, which should succeed, due to
270   // SO_REUSEADDR.
271   mojo::Remote<mojom::TCPBoundSocket> bound_socket2;
272   net::IPEndPoint bound_address2;
273   ASSERT_EQ(net::OK,
274             BindSocket(bound_address1, &bound_socket2, &bound_address2));
275 
276   // Listen on the first socket, which should also succeed.
277   mojo::Remote<mojom::TCPServerSocket> server_socket1;
278   ASSERT_EQ(net::OK, Listen(std::move(bound_socket1), &server_socket1));
279 
280   // Listen on the second socket should fail.
281   mojo::Remote<mojom::TCPServerSocket> server_socket2;
282   int result = Listen(std::move(bound_socket2), &server_socket2);
283   // Depending on platform, can get different errors. Some platforms can return
284   // either error.
285   EXPECT_TRUE(result == net::ERR_ADDRESS_IN_USE ||
286               result == net::ERR_INVALID_ARGUMENT);
287 }
288 #endif  // !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_IOS)
289 
290 // Test the case bind succeeds, and transfer some data.
TEST_F(TCPBoundSocketTest,ReadWrite)291 TEST_F(TCPBoundSocketTest, ReadWrite) {
292   // Set up a listening socket.
293   mojo::Remote<mojom::TCPBoundSocket> bound_socket1;
294   net::IPEndPoint server_address;
295   ASSERT_EQ(net::OK, BindSocket(LocalHostWithAnyPort(), &bound_socket1,
296                                 &server_address));
297   mojo::Remote<mojom::TCPServerSocket> server_socket;
298   ASSERT_EQ(net::OK, Listen(std::move(bound_socket1), &server_socket));
299 
300   // Connect to the socket with another socket.
301   mojo::Remote<mojom::TCPBoundSocket> bound_socket2;
302   net::IPEndPoint client_address;
303   ASSERT_EQ(net::OK, BindSocket(LocalHostWithAnyPort(), &bound_socket2,
304                                 &client_address));
305   mojo::Remote<mojom::TCPConnectedSocket> client_socket;
306   TestSocketObserver socket_observer;
307   mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
308   mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
309   EXPECT_EQ(net::OK,
310             Connect(std::move(bound_socket2), client_address, server_address,
311                     nullptr /* tcp_connected_socket_options */, &client_socket,
312                     socket_observer.GetObserverRemote(),
313                     &client_socket_receive_handle, &client_socket_send_handle));
314 
315   base::RunLoop run_loop;
316   mojo::Remote<mojom::TCPConnectedSocket> accept_socket;
317   mojo::ScopedDataPipeConsumerHandle accept_socket_receive_handle;
318   mojo::ScopedDataPipeProducerHandle accept_socket_send_handle;
319   server_socket->Accept(
320       mojo::NullRemote() /* ovserver */,
321       base::BindLambdaForTesting(
322           [&](int net_error, const base::Optional<net::IPEndPoint>& remote_addr,
323               mojo::PendingRemote<mojom::TCPConnectedSocket> connected_socket,
324               mojo::ScopedDataPipeConsumerHandle receive_stream,
325               mojo::ScopedDataPipeProducerHandle send_stream) {
326             EXPECT_EQ(net_error, net::OK);
327             EXPECT_EQ(*remote_addr, client_address);
328             accept_socket.Bind(std::move(connected_socket));
329             accept_socket_receive_handle = std::move(receive_stream);
330             accept_socket_send_handle = std::move(send_stream);
331             run_loop.Quit();
332           }));
333   run_loop.Run();
334 
335   const std::string kData = "Jumbo Shrimp";
336   ASSERT_TRUE(mojo::BlockingCopyFromString(kData, client_socket_send_handle));
337   EXPECT_EQ(kData, ReadData(accept_socket_receive_handle.get(), kData.size()));
338 
339   ASSERT_TRUE(mojo::BlockingCopyFromString(kData, accept_socket_send_handle));
340   EXPECT_EQ(kData, ReadData(client_socket_receive_handle.get(), kData.size()));
341 
342   // Close the accept socket.
343   accept_socket.reset();
344 
345   // Wait for read error on the client socket.
346   EXPECT_EQ(net::OK, socket_observer.WaitForReadError());
347 
348   // Write data to the client socket until there's an error.
349   while (true) {
350     void* buffer = nullptr;
351     uint32_t buffer_num_bytes = 0;
352     MojoResult result = client_socket_send_handle->BeginWriteData(
353         &buffer, &buffer_num_bytes, MOJO_WRITE_DATA_FLAG_NONE);
354     if (result == MOJO_RESULT_SHOULD_WAIT) {
355       task_environment()->RunUntilIdle();
356       continue;
357     }
358     if (result != MOJO_RESULT_OK)
359       break;
360     memset(buffer, 0, buffer_num_bytes);
361     client_socket_send_handle->EndWriteData(buffer_num_bytes);
362   }
363   // Wait for write error on the client socket. Don't check exact error, out of
364   // paranoia.
365   EXPECT_LT(socket_observer.WaitForWriteError(), 0);
366 }
367 
368 // Establish a connection while passing in some options. This test doesn't check
369 // that the options are actually set, since there's no API for that.
TEST_F(TCPBoundSocketTest,ConnectWithOptions)370 TEST_F(TCPBoundSocketTest, ConnectWithOptions) {
371   // Set up a listening socket.
372   mojo::Remote<mojom::TCPBoundSocket> bound_socket1;
373   net::IPEndPoint server_address;
374   ASSERT_EQ(net::OK, BindSocket(LocalHostWithAnyPort(), &bound_socket1,
375                                 &server_address));
376   mojo::Remote<mojom::TCPServerSocket> server_socket;
377   ASSERT_EQ(net::OK, Listen(std::move(bound_socket1), &server_socket));
378 
379   // Connect to the socket with another socket.
380   mojo::Remote<mojom::TCPBoundSocket> bound_socket2;
381   net::IPEndPoint client_address;
382   ASSERT_EQ(net::OK, BindSocket(LocalHostWithAnyPort(), &bound_socket2,
383                                 &client_address));
384   mojo::Remote<mojom::TCPConnectedSocket> client_socket;
385   TestSocketObserver socket_observer;
386   mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
387   mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
388   mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options =
389       mojom::TCPConnectedSocketOptions::New();
390   tcp_connected_socket_options->send_buffer_size = 32 * 1024;
391   tcp_connected_socket_options->receive_buffer_size = 64 * 1024;
392   tcp_connected_socket_options->no_delay = false;
393 
394   EXPECT_EQ(net::OK,
395             Connect(std::move(bound_socket2), client_address, server_address,
396                     std::move(tcp_connected_socket_options), &client_socket,
397                     socket_observer.GetObserverRemote(),
398                     &client_socket_receive_handle, &client_socket_send_handle));
399 
400   base::RunLoop run_loop;
401   mojo::Remote<mojom::TCPConnectedSocket> accept_socket;
402   mojo::ScopedDataPipeConsumerHandle accept_socket_receive_handle;
403   mojo::ScopedDataPipeProducerHandle accept_socket_send_handle;
404   server_socket->Accept(
405       mojo::NullRemote() /* ovserver */,
406       base::BindLambdaForTesting(
407           [&](int net_error, const base::Optional<net::IPEndPoint>& remote_addr,
408               mojo::PendingRemote<mojom::TCPConnectedSocket> connected_socket,
409               mojo::ScopedDataPipeConsumerHandle receive_stream,
410               mojo::ScopedDataPipeProducerHandle send_stream) {
411             EXPECT_EQ(net_error, net::OK);
412             EXPECT_EQ(*remote_addr, client_address);
413             accept_socket.Bind(std::move(connected_socket));
414             accept_socket_receive_handle = std::move(receive_stream);
415             accept_socket_send_handle = std::move(send_stream);
416             run_loop.Quit();
417           }));
418   run_loop.Run();
419 
420   const std::string kData = "Jumbo Shrimp";
421   ASSERT_TRUE(mojo::BlockingCopyFromString(kData, client_socket_send_handle));
422   EXPECT_EQ(kData, ReadData(accept_socket_receive_handle.get(), kData.size()));
423 
424   ASSERT_TRUE(mojo::BlockingCopyFromString(kData, accept_socket_send_handle));
425   EXPECT_EQ(kData, ReadData(client_socket_receive_handle.get(), kData.size()));
426 }
427 
428 // Test that a TCPBoundSocket can be upgraded to TLS once connected.
TEST_F(TCPBoundSocketTest,UpgradeToTLS)429 TEST_F(TCPBoundSocketTest, UpgradeToTLS) {
430   // Simplest way to set up an TLS server is to use the embedded test server.
431   net::test_server::EmbeddedTestServer test_server(
432       net::test_server::EmbeddedTestServer::TYPE_HTTPS);
433   test_server.RegisterRequestHandler(base::BindRepeating(
434       [](const net::test_server::HttpRequest& request)
435           -> std::unique_ptr<net::test_server::HttpResponse> {
436         std::unique_ptr<net::test_server::BasicHttpResponse> basic_response =
437             std::make_unique<net::test_server::BasicHttpResponse>();
438         basic_response->set_content(request.relative_url);
439         return basic_response;
440       }));
441   ASSERT_TRUE(test_server.Start());
442 
443   mojo::Remote<mojom::TCPBoundSocket> bound_socket;
444   net::IPEndPoint client_address;
445   ASSERT_EQ(net::OK,
446             BindSocket(LocalHostWithAnyPort(), &bound_socket, &client_address));
447   mojo::Remote<mojom::TCPConnectedSocket> client_socket;
448   TestSocketObserver socket_observer;
449   mojo::ScopedDataPipeConsumerHandle client_socket_receive_handle;
450   mojo::ScopedDataPipeProducerHandle client_socket_send_handle;
451 
452   EXPECT_EQ(net::OK,
453             Connect(std::move(bound_socket), client_address,
454                     net::IPEndPoint(net::IPAddress::IPv4Localhost(),
455                                     test_server.host_port_pair().port()),
456                     nullptr /* tcp_connected_socket_options */, &client_socket,
457                     socket_observer.GetObserverRemote(),
458                     &client_socket_receive_handle, &client_socket_send_handle));
459 
460   // Need to closed these pipes for UpgradeToTLS to complete.
461   client_socket_receive_handle.reset();
462   client_socket_send_handle.reset();
463 
464   base::RunLoop run_loop;
465   mojo::Remote<mojom::TLSClientSocket> tls_client_socket;
466   client_socket->UpgradeToTLS(
467       test_server.host_port_pair(), nullptr /* options */,
468       net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
469       tls_client_socket.BindNewPipeAndPassReceiver(),
470       mojo::NullRemote() /* observer */,
471       base::BindLambdaForTesting(
472           [&](int net_error,
473               mojo::ScopedDataPipeConsumerHandle receive_pipe_handle,
474               mojo::ScopedDataPipeProducerHandle send_pipe_handle,
475               const base::Optional<net::SSLInfo>& ssl_info) {
476             EXPECT_EQ(net::OK, net_error);
477             client_socket_receive_handle = std::move(receive_pipe_handle);
478             client_socket_send_handle = std::move(send_pipe_handle);
479             run_loop.Quit();
480           }));
481   run_loop.Run();
482 
483   const char kPath[] = "/foo";
484 
485   // Send an HTTP request.
486   std::string request = base::StringPrintf("GET %s HTTP/1.0\r\n\r\n", kPath);
487   EXPECT_TRUE(mojo::BlockingCopyFromString(request, client_socket_send_handle));
488 
489   // Read the response, and make sure it looks reasonable.
490   std::string response = ReadData(client_socket_receive_handle.get());
491   EXPECT_EQ("HTTP/", response.substr(0, 5));
492   // The response body should be the path, so make sure the response ends with
493   // the path.
494   EXPECT_EQ(kPath, response.substr(response.length() - strlen(kPath)));
495 }
496 
497 }  // namespace
498 }  // namespace network
499