1 // Copyright 2015 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.
5 #include "base/logging.h"
6 #include "base/macros.h"
7 #include "base/memory/linked_ptr.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "mojo/application/public/cpp/application_connection.h"
14 #include "mojo/application/public/cpp/application_impl.h"
15 #include "mojo/application/public/cpp/application_test_base.h"
16 #include "mojo/common/data_pipe_utils.h"
17 #include "mojo/services/network/net_address_type_converters.h"
18 #include "mojo/services/network/public/cpp/web_socket_read_queue.h"
19 #include "mojo/services/network/public/cpp/web_socket_write_queue.h"
20 #include "mojo/services/network/public/interfaces/http_connection.mojom.h"
21 #include "mojo/services/network/public/interfaces/http_message.mojom.h"
22 #include "mojo/services/network/public/interfaces/http_server.mojom.h"
23 #include "mojo/services/network/public/interfaces/net_address.mojom.h"
24 #include "mojo/services/network/public/interfaces/network_service.mojom.h"
25 #include "mojo/services/network/public/interfaces/web_socket.mojom.h"
26 #include "mojo/services/network/public/interfaces/web_socket_factory.mojom.h"
27 #include "net/base/io_buffer.h"
28 #include "net/base/net_errors.h"
29 #include "net/base/test_completion_callback.h"
30 #include "net/http/http_response_headers.h"
31 #include "net/http/http_util.h"
32 #include "net/socket/tcp_client_socket.h"
33 #include "testing/gtest/include/gtest/gtest.h"
38 const int kMaxExpectedResponseLength
= 2048;
40 NetAddressPtr
GetLocalHostWithAnyPort() {
41 NetAddressPtr
addr(NetAddress::New());
42 addr
->family
= NET_ADDRESS_FAMILY_IPV4
;
43 addr
->ipv4
= NetAddressIPv4::New();
45 addr
->ipv4
->addr
.resize(4);
46 addr
->ipv4
->addr
[0] = 127;
47 addr
->ipv4
->addr
[1] = 0;
48 addr
->ipv4
->addr
[2] = 0;
49 addr
->ipv4
->addr
[3] = 1;
54 using TestHeaders
= std::vector
<std::pair
<std::string
, std::string
>>;
60 scoped_ptr
<std::string
> body
;
66 scoped_ptr
<std::string
> body
;
69 std::string
MakeRequestMessage(const TestRequest
& data
) {
70 std::string message
= data
.method
+ " " + data
.url
+ " HTTP/1.1\r\n";
71 for (const auto& item
: data
.headers
)
72 message
+= item
.first
+ ": " + item
.second
+ "\r\n";
75 message
+= *data
.body
;
80 HttpResponsePtr
MakeResponseStruct(const TestResponse
& data
) {
81 HttpResponsePtr
response(HttpResponse::New());
82 response
->status_code
= data
.status_code
;
83 response
->headers
.resize(data
.headers
.size());
85 for (const auto& item
: data
.headers
) {
86 HttpHeaderPtr
header(HttpHeader::New());
87 header
->name
= item
.first
;
88 header
->value
= item
.second
;
89 response
->headers
[index
++] = header
.Pass();
93 uint32_t num_bytes
= static_cast<uint32_t>(data
.body
->size());
94 MojoCreateDataPipeOptions options
;
95 options
.struct_size
= sizeof(MojoCreateDataPipeOptions
);
96 options
.flags
= MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
;
97 options
.element_num_bytes
= 1;
98 options
.capacity_num_bytes
= num_bytes
;
99 DataPipe
data_pipe(options
);
100 response
->body
= data_pipe
.consumer_handle
.Pass();
102 WriteDataRaw(data_pipe
.producer_handle
.get(), data
.body
->data(),
103 &num_bytes
, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
);
104 EXPECT_EQ(MOJO_RESULT_OK
, result
);
107 return response
.Pass();
110 void CheckHeaders(const TestHeaders
& expected
,
111 const Array
<HttpHeaderPtr
>& headers
) {
112 // The server impl fiddles with Content-Length and Content-Type. So we don't
113 // do a strict check here.
114 std::map
<std::string
, std::string
> header_map
;
115 for (size_t i
= 0; i
< headers
.size(); ++i
) {
116 std::string lower_name
=
117 base::ToLowerASCII(headers
[i
]->name
.To
<std::string
>());
118 header_map
[lower_name
] = headers
[i
]->value
;
121 for (const auto& item
: expected
) {
122 std::string lower_name
= base::ToLowerASCII(item
.first
);
123 EXPECT_NE(header_map
.end(), header_map
.find(lower_name
));
124 EXPECT_EQ(item
.second
, header_map
[lower_name
]);
128 void CheckRequest(const TestRequest
& expected
, HttpRequestPtr request
) {
129 EXPECT_EQ(expected
.method
, request
->method
);
130 EXPECT_EQ(expected
.url
, request
->url
);
131 CheckHeaders(expected
.headers
, request
->headers
);
133 EXPECT_TRUE(request
->body
.is_valid());
135 common::BlockingCopyToString(request
->body
.Pass(), &body
);
136 EXPECT_EQ(*expected
.body
, body
);
138 EXPECT_FALSE(request
->body
.is_valid());
142 void CheckResponse(const TestResponse
& expected
, const std::string
& response
) {
144 net::HttpUtil::LocateEndOfHeaders(response
.c_str(), response
.size());
145 std::string assembled_headers
=
146 net::HttpUtil::AssembleRawHeaders(response
.c_str(), header_end
);
147 scoped_refptr
<net::HttpResponseHeaders
> parsed_headers(
148 new net::HttpResponseHeaders(assembled_headers
));
149 EXPECT_EQ(expected
.status_code
,
150 static_cast<uint32_t>(parsed_headers
->response_code()));
151 for (const auto& item
: expected
.headers
)
152 EXPECT_TRUE(parsed_headers
->HasHeaderValue(item
.first
, item
.second
));
155 EXPECT_NE(-1, header_end
);
156 std::string
body(response
, static_cast<size_t>(header_end
));
157 EXPECT_EQ(*expected
.body
, body
);
159 EXPECT_EQ(response
.size(), static_cast<size_t>(header_end
));
163 class TestHttpClient
{
165 TestHttpClient() : connect_result_(net::OK
) {}
167 void Connect(const net::IPEndPoint
& address
) {
168 net::AddressList
addresses(address
);
169 net::NetLog::Source source
;
170 socket_
.reset(new net::TCPClientSocket(addresses
, NULL
, source
));
172 base::RunLoop run_loop
;
173 connect_result_
= socket_
->Connect(base::Bind(&TestHttpClient::OnConnect
,
174 base::Unretained(this),
175 run_loop
.QuitClosure()));
176 if (connect_result_
== net::ERR_IO_PENDING
)
179 ASSERT_EQ(net::OK
, connect_result_
);
182 void Send(const std::string
& data
) {
183 write_buffer_
= new net::DrainableIOBuffer(new net::StringIOBuffer(data
),
188 // Note: This method determines the end of the response only by Content-Length
189 // and connection termination. Besides, it doesn't truncate at the end of the
190 // response, so |message| may return more data (e.g., part of the next
192 void ReadResponse(std::string
* message
) {
193 if (!Read(message
, 1))
195 while (!IsCompleteResponse(*message
)) {
197 if (!Read(&chunk
, 1))
199 message
->append(chunk
);
205 void OnConnect(const base::Closure
& quit_loop
, int result
) {
206 connect_result_
= result
;
211 int result
= socket_
->Write(
212 write_buffer_
.get(), write_buffer_
->BytesRemaining(),
213 base::Bind(&TestHttpClient::OnWrite
, base::Unretained(this)));
214 if (result
!= net::ERR_IO_PENDING
)
218 void OnWrite(int result
) {
219 ASSERT_GT(result
, 0);
220 write_buffer_
->DidConsume(result
);
221 if (write_buffer_
->BytesRemaining())
225 bool Read(std::string
* message
, int expected_bytes
) {
226 int total_bytes_received
= 0;
228 while (total_bytes_received
< expected_bytes
) {
229 net::TestCompletionCallback callback
;
230 ReadInternal(callback
.callback());
231 int bytes_received
= callback
.WaitForResult();
232 if (bytes_received
<= 0)
235 total_bytes_received
+= bytes_received
;
236 message
->append(read_buffer_
->data(), bytes_received
);
241 void ReadInternal(const net::CompletionCallback
& callback
) {
242 read_buffer_
= new net::IOBufferWithSize(kMaxExpectedResponseLength
);
244 socket_
->Read(read_buffer_
.get(), kMaxExpectedResponseLength
, callback
);
245 if (result
!= net::ERR_IO_PENDING
)
246 callback
.Run(result
);
249 bool IsCompleteResponse(const std::string
& response
) {
250 // Check end of headers first.
252 net::HttpUtil::LocateEndOfHeaders(response
.data(), response
.size());
253 if (end_of_headers
< 0)
256 // Return true if response has data equal to or more than content length.
257 int64 body_size
= static_cast<int64
>(response
.size()) - end_of_headers
;
258 DCHECK_LE(0, body_size
);
259 scoped_refptr
<net::HttpResponseHeaders
> headers(
260 new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
261 response
.data(), end_of_headers
)));
262 return body_size
>= headers
->GetContentLength();
265 scoped_refptr
<net::IOBufferWithSize
> read_buffer_
;
266 scoped_refptr
<net::DrainableIOBuffer
> write_buffer_
;
267 scoped_ptr
<net::TCPClientSocket
> socket_
;
270 DISALLOW_COPY_AND_ASSIGN(TestHttpClient
);
273 class WebSocketClientImpl
: public WebSocketClient
{
275 explicit WebSocketClientImpl()
276 : binding_(this, &client_ptr_
),
277 wait_for_message_count_(0),
278 run_loop_(nullptr) {}
279 ~WebSocketClientImpl() override
{}
281 // Establishes a connection from the client side.
282 void Connect(WebSocketPtr web_socket
, const std::string
& url
) {
283 web_socket_
= web_socket
.Pass();
286 send_stream_
= data_pipe
.producer_handle
.Pass();
287 write_send_stream_
.reset(new WebSocketWriteQueue(send_stream_
.get()));
289 web_socket_
->Connect(url
, Array
<String
>(0), "http://example.com",
290 data_pipe
.consumer_handle
.Pass(), client_ptr_
.Pass());
293 // Establishes a connection from the server side.
294 void AcceptConnectRequest(
295 const HttpConnectionDelegate::OnReceivedWebSocketRequestCallback
&
297 InterfaceRequest
<WebSocket
> web_socket_request
= GetProxy(&web_socket_
);
300 send_stream_
= data_pipe
.producer_handle
.Pass();
301 write_send_stream_
.reset(new WebSocketWriteQueue(send_stream_
.get()));
303 callback
.Run(web_socket_request
.Pass(), data_pipe
.consumer_handle
.Pass(),
307 void WaitForConnectCompletion() {
310 if (receive_stream_
.is_valid())
313 base::RunLoop run_loop
;
314 run_loop_
= &run_loop
;
319 void Send(const std::string
& message
) {
320 DCHECK(!message
.empty());
322 uint32_t size
= static_cast<uint32_t>(message
.size());
323 write_send_stream_
->Write(
325 base::Bind(&WebSocketClientImpl::OnFinishedWritingSendStream
,
326 base::Unretained(this), size
));
329 void WaitForMessage(size_t count
) {
332 if (received_messages_
.size() >= count
)
334 wait_for_message_count_
= count
;
335 base::RunLoop run_loop
;
336 run_loop_
= &run_loop
;
341 std::vector
<std::string
>& received_messages() { return received_messages_
; }
344 // WebSocketClient implementation.
345 void DidConnect(const String
& selected_subprotocol
,
346 const String
& extensions
,
347 ScopedDataPipeConsumerHandle receive_stream
) override
{
348 receive_stream_
= receive_stream
.Pass();
349 read_receive_stream_
.reset(new WebSocketReadQueue(receive_stream_
.get()));
351 web_socket_
->FlowControl(2048);
356 void DidReceiveData(bool fin
,
357 WebSocket::MessageType type
,
358 uint32_t num_bytes
) override
{
359 DCHECK(num_bytes
> 0);
361 read_receive_stream_
->Read(
363 base::Bind(&WebSocketClientImpl::OnFinishedReadingReceiveStream
,
364 base::Unretained(this), num_bytes
));
367 void DidReceiveFlowControl(int64_t quota
) override
{}
369 void DidFail(const String
& message
) override
{}
371 void DidClose(bool was_clean
, uint16_t code
, const String
& reason
) override
{}
373 void OnFinishedWritingSendStream(uint32_t num_bytes
, const char* buffer
) {
376 web_socket_
->Send(true, WebSocket::MESSAGE_TYPE_TEXT
, num_bytes
);
379 void OnFinishedReadingReceiveStream(uint32_t num_bytes
, const char* data
) {
382 received_messages_
.push_back(std::string(data
, num_bytes
));
383 if (run_loop_
&& received_messages_
.size() >= wait_for_message_count_
) {
384 wait_for_message_count_
= 0;
389 WebSocketClientPtr client_ptr_
;
390 Binding
<WebSocketClient
> binding_
;
391 WebSocketPtr web_socket_
;
393 ScopedDataPipeProducerHandle send_stream_
;
394 scoped_ptr
<WebSocketWriteQueue
> write_send_stream_
;
396 ScopedDataPipeConsumerHandle receive_stream_
;
397 scoped_ptr
<WebSocketReadQueue
> read_receive_stream_
;
399 std::vector
<std::string
> received_messages_
;
400 size_t wait_for_message_count_
;
402 // Pointing to a stack-allocated RunLoop instance.
403 base::RunLoop
* run_loop_
;
405 DISALLOW_COPY_AND_ASSIGN(WebSocketClientImpl
);
408 class HttpConnectionDelegateImpl
: public HttpConnectionDelegate
{
410 struct PendingRequest
{
411 HttpRequestPtr request
;
412 OnReceivedRequestCallback callback
;
415 HttpConnectionDelegateImpl(HttpConnectionPtr connection
,
416 InterfaceRequest
<HttpConnectionDelegate
> request
)
417 : connection_(connection
.Pass()),
418 binding_(this, request
.Pass()),
419 wait_for_request_count_(0),
420 run_loop_(nullptr) {}
421 ~HttpConnectionDelegateImpl() override
{}
423 // HttpConnectionDelegate implementation:
424 void OnReceivedRequest(HttpRequestPtr request
,
425 const OnReceivedRequestCallback
& callback
) override
{
426 linked_ptr
<PendingRequest
> pending_request(new PendingRequest
);
427 pending_request
->request
= request
.Pass();
428 pending_request
->callback
= callback
;
429 pending_requests_
.push_back(pending_request
);
430 if (run_loop_
&& pending_requests_
.size() >= wait_for_request_count_
) {
431 wait_for_request_count_
= 0;
436 void OnReceivedWebSocketRequest(
437 HttpRequestPtr request
,
438 const OnReceivedWebSocketRequestCallback
& callback
) override
{
439 web_socket_
.reset(new WebSocketClientImpl());
441 web_socket_
->AcceptConnectRequest(callback
);
447 void SendResponse(HttpResponsePtr response
) {
448 ASSERT_FALSE(pending_requests_
.empty());
449 linked_ptr
<PendingRequest
> request
= pending_requests_
[0];
450 pending_requests_
.erase(pending_requests_
.begin());
451 request
->callback
.Run(response
.Pass());
454 void WaitForRequest(size_t count
) {
457 if (pending_requests_
.size() >= count
)
460 wait_for_request_count_
= count
;
461 base::RunLoop run_loop
;
462 run_loop_
= &run_loop
;
467 void WaitForWebSocketRequest() {
473 base::RunLoop run_loop
;
474 run_loop_
= &run_loop
;
479 std::vector
<linked_ptr
<PendingRequest
>>& pending_requests() {
480 return pending_requests_
;
483 WebSocketClientImpl
* web_socket() { return web_socket_
.get(); }
486 HttpConnectionPtr connection_
;
487 Binding
<HttpConnectionDelegate
> binding_
;
488 std::vector
<linked_ptr
<PendingRequest
>> pending_requests_
;
489 size_t wait_for_request_count_
;
490 scoped_ptr
<WebSocketClientImpl
> web_socket_
;
492 // Pointing to a stack-allocated RunLoop instance.
493 base::RunLoop
* run_loop_
;
495 DISALLOW_COPY_AND_ASSIGN(HttpConnectionDelegateImpl
);
498 class HttpServerDelegateImpl
: public HttpServerDelegate
{
500 explicit HttpServerDelegateImpl(HttpServerDelegatePtr
* delegate_ptr
)
501 : binding_(this, delegate_ptr
),
502 wait_for_connection_count_(0),
503 run_loop_(nullptr) {}
504 ~HttpServerDelegateImpl() override
{}
506 // HttpServerDelegate implementation.
507 void OnConnected(HttpConnectionPtr connection
,
508 InterfaceRequest
<HttpConnectionDelegate
> delegate
) override
{
509 connections_
.push_back(make_linked_ptr(
510 new HttpConnectionDelegateImpl(connection
.Pass(), delegate
.Pass())));
511 if (run_loop_
&& connections_
.size() >= wait_for_connection_count_
) {
512 wait_for_connection_count_
= 0;
517 void WaitForConnection(size_t count
) {
520 if (connections_
.size() >= count
)
523 wait_for_connection_count_
= count
;
524 base::RunLoop run_loop
;
525 run_loop_
= &run_loop
;
530 std::vector
<linked_ptr
<HttpConnectionDelegateImpl
>>& connections() {
535 Binding
<HttpServerDelegate
> binding_
;
536 std::vector
<linked_ptr
<HttpConnectionDelegateImpl
>> connections_
;
537 size_t wait_for_connection_count_
;
538 // Pointing to a stack-allocated RunLoop instance.
539 base::RunLoop
* run_loop_
;
541 DISALLOW_COPY_AND_ASSIGN(HttpServerDelegateImpl
);
544 class HttpServerAppTest
: public test::ApplicationTestBase
{
546 HttpServerAppTest() : message_loop_(base::MessageLoop::TYPE_IO
) {}
547 ~HttpServerAppTest() override
{}
550 bool ShouldCreateDefaultRunLoop() override
{ return false; }
552 void SetUp() override
{
553 ApplicationTestBase::SetUp();
555 mojo::URLRequestPtr
request(mojo::URLRequest::New());
556 request
->url
= mojo::String::From("mojo:network_service");
557 scoped_ptr
<ApplicationConnection
> connection
=
558 application_impl()->ConnectToApplication(request
.Pass());
559 connection
->ConnectToService(&network_service_
);
560 connection
->ConnectToService(&web_socket_factory_
);
563 void CreateHttpServer(HttpServerDelegatePtr delegate
,
564 NetAddressPtr
* out_bound_to
) {
565 network_service_
->CreateHttpServer(
566 GetLocalHostWithAnyPort(), delegate
.Pass(),
567 [out_bound_to
](NetworkErrorPtr result
, NetAddressPtr bound_to
) {
568 ASSERT_EQ(net::OK
, result
->code
);
569 EXPECT_NE(0u, bound_to
->ipv4
->port
);
570 *out_bound_to
= bound_to
.Pass();
572 network_service_
.WaitForIncomingResponse();
575 NetworkServicePtr network_service_
;
576 WebSocketFactoryPtr web_socket_factory_
;
579 base::MessageLoop message_loop_
;
581 DISALLOW_COPY_AND_ASSIGN(HttpServerAppTest
);
586 TEST_F(HttpServerAppTest
, BasicHttpRequestResponse
) {
587 NetAddressPtr bound_to
;
588 HttpServerDelegatePtr server_delegate_ptr
;
589 HttpServerDelegateImpl
server_delegate_impl(&server_delegate_ptr
);
590 CreateHttpServer(server_delegate_ptr
.Pass(), &bound_to
);
592 TestHttpClient client
;
593 client
.Connect(bound_to
.To
<net::IPEndPoint
>());
595 server_delegate_impl
.WaitForConnection(1);
596 HttpConnectionDelegateImpl
& connection
=
597 *server_delegate_impl
.connections()[0];
599 TestRequest request_data
= {"HEAD", "/test", {{"Hello", "World"}}, nullptr};
600 client
.Send(MakeRequestMessage(request_data
));
602 connection
.WaitForRequest(1);
604 CheckRequest(request_data
, connection
.pending_requests()[0]->request
.Pass());
606 TestResponse response_data
= {200, {{"Content-Length", "4"}}, nullptr};
607 connection
.SendResponse(MakeResponseStruct(response_data
));
608 // This causes the underlying TCP connection to be closed. The client can
609 // determine the end of the response based on that.
610 server_delegate_impl
.connections().clear();
612 std::string response_message
;
613 client
.ReadResponse(&response_message
);
615 CheckResponse(response_data
, response_message
);
618 TEST_F(HttpServerAppTest
, HttpRequestResponseWithBody
) {
619 NetAddressPtr bound_to
;
620 HttpServerDelegatePtr server_delegate_ptr
;
621 HttpServerDelegateImpl
server_delegate_impl(&server_delegate_ptr
);
622 CreateHttpServer(server_delegate_ptr
.Pass(), &bound_to
);
624 TestHttpClient client
;
625 client
.Connect(bound_to
.To
<net::IPEndPoint
>());
627 server_delegate_impl
.WaitForConnection(1);
628 HttpConnectionDelegateImpl
& connection
=
629 *server_delegate_impl
.connections()[0];
631 TestRequest request_data
= {
635 {"Content-Length", "23"},
636 {"Content-Type", "text/plain"}},
637 make_scoped_ptr(new std::string("This is a test request!"))};
638 client
.Send(MakeRequestMessage(request_data
));
640 connection
.WaitForRequest(1);
642 CheckRequest(request_data
, connection
.pending_requests()[0]->request
.Pass());
644 TestResponse response_data
= {
646 {{"Content-Length", "26"}},
647 make_scoped_ptr(new std::string("This is a test response..."))};
648 connection
.SendResponse(MakeResponseStruct(response_data
));
650 std::string response_message
;
651 client
.ReadResponse(&response_message
);
653 CheckResponse(response_data
, response_message
);
656 TEST_F(HttpServerAppTest
, WebSocket
) {
657 NetAddressPtr bound_to
;
658 HttpServerDelegatePtr server_delegate_ptr
;
659 HttpServerDelegateImpl
server_delegate_impl(&server_delegate_ptr
);
660 CreateHttpServer(server_delegate_ptr
.Pass(), &bound_to
);
662 WebSocketPtr web_socket_ptr
;
663 web_socket_factory_
->CreateWebSocket(GetProxy(&web_socket_ptr
));
664 WebSocketClientImpl socket_0
;
666 web_socket_ptr
.Pass(),
667 base::StringPrintf("ws://127.0.0.1:%d/hello", bound_to
->ipv4
->port
));
669 server_delegate_impl
.WaitForConnection(1);
670 HttpConnectionDelegateImpl
& connection
=
671 *server_delegate_impl
.connections()[0];
673 connection
.WaitForWebSocketRequest();
674 WebSocketClientImpl
& socket_1
= *connection
.web_socket();
676 socket_1
.WaitForConnectCompletion();
677 socket_0
.WaitForConnectCompletion();
679 socket_0
.Send("Hello");
680 socket_0
.Send("world!");
682 socket_1
.WaitForMessage(2);
683 EXPECT_EQ("Hello", socket_1
.received_messages()[0]);
684 EXPECT_EQ("world!", socket_1
.received_messages()[1]);
686 socket_1
.Send("How do");
687 socket_1
.Send("you do?");
689 socket_0
.WaitForMessage(2);
690 EXPECT_EQ("How do", socket_0
.received_messages()[0]);
691 EXPECT_EQ("you do?", socket_0
.received_messages()[1]);