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 "net/base/io_buffer.h"
27 #include "net/base/net_errors.h"
28 #include "net/base/test_completion_callback.h"
29 #include "net/http/http_response_headers.h"
30 #include "net/http/http_util.h"
31 #include "net/socket/tcp_client_socket.h"
32 #include "testing/gtest/include/gtest/gtest.h"
37 const int kMaxExpectedResponseLength
= 2048;
39 NetAddressPtr
GetLocalHostWithAnyPort() {
40 NetAddressPtr
addr(NetAddress::New());
41 addr
->family
= NET_ADDRESS_FAMILY_IPV4
;
42 addr
->ipv4
= NetAddressIPv4::New();
44 addr
->ipv4
->addr
.resize(4);
45 addr
->ipv4
->addr
[0] = 127;
46 addr
->ipv4
->addr
[1] = 0;
47 addr
->ipv4
->addr
[2] = 0;
48 addr
->ipv4
->addr
[3] = 1;
53 using TestHeaders
= std::vector
<std::pair
<std::string
, std::string
>>;
59 scoped_ptr
<std::string
> body
;
65 scoped_ptr
<std::string
> body
;
68 std::string
MakeRequestMessage(const TestRequest
& data
) {
69 std::string message
= data
.method
+ " " + data
.url
+ " HTTP/1.1\r\n";
70 for (const auto& item
: data
.headers
)
71 message
+= item
.first
+ ": " + item
.second
+ "\r\n";
74 message
+= *data
.body
;
79 HttpResponsePtr
MakeResponseStruct(const TestResponse
& data
) {
80 HttpResponsePtr
response(HttpResponse::New());
81 response
->status_code
= data
.status_code
;
82 response
->headers
.resize(data
.headers
.size());
84 for (const auto& item
: data
.headers
) {
85 HttpHeaderPtr
header(HttpHeader::New());
86 header
->name
= item
.first
;
87 header
->value
= item
.second
;
88 response
->headers
[index
++] = header
.Pass();
92 uint32_t num_bytes
= static_cast<uint32_t>(data
.body
->size());
93 MojoCreateDataPipeOptions options
;
94 options
.struct_size
= sizeof(MojoCreateDataPipeOptions
);
95 options
.flags
= MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
;
96 options
.element_num_bytes
= 1;
97 options
.capacity_num_bytes
= num_bytes
;
98 DataPipe
data_pipe(options
);
99 response
->body
= data_pipe
.consumer_handle
.Pass();
101 WriteDataRaw(data_pipe
.producer_handle
.get(), data
.body
->data(),
102 &num_bytes
, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
);
103 EXPECT_EQ(MOJO_RESULT_OK
, result
);
106 return response
.Pass();
109 void CheckHeaders(const TestHeaders
& expected
,
110 const Array
<HttpHeaderPtr
>& headers
) {
111 // The server impl fiddles with Content-Length and Content-Type. So we don't
112 // do a strict check here.
113 std::map
<std::string
, std::string
> header_map
;
114 for (size_t i
= 0; i
< headers
.size(); ++i
) {
115 std::string lower_name
=
116 base::StringToLowerASCII(headers
[i
]->name
.To
<std::string
>());
117 header_map
[lower_name
] = headers
[i
]->value
;
120 for (const auto& item
: expected
) {
121 std::string lower_name
= base::StringToLowerASCII(item
.first
);
122 EXPECT_NE(header_map
.end(), header_map
.find(lower_name
));
123 EXPECT_EQ(item
.second
, header_map
[lower_name
]);
127 void CheckRequest(const TestRequest
& expected
, HttpRequestPtr request
) {
128 EXPECT_EQ(expected
.method
, request
->method
);
129 EXPECT_EQ(expected
.url
, request
->url
);
130 CheckHeaders(expected
.headers
, request
->headers
);
132 EXPECT_TRUE(request
->body
.is_valid());
134 common::BlockingCopyToString(request
->body
.Pass(), &body
);
135 EXPECT_EQ(*expected
.body
, body
);
137 EXPECT_FALSE(request
->body
.is_valid());
141 void CheckResponse(const TestResponse
& expected
, const std::string
& response
) {
143 net::HttpUtil::LocateEndOfHeaders(response
.c_str(), response
.size());
144 std::string assembled_headers
=
145 net::HttpUtil::AssembleRawHeaders(response
.c_str(), header_end
);
146 scoped_refptr
<net::HttpResponseHeaders
> parsed_headers(
147 new net::HttpResponseHeaders(assembled_headers
));
148 EXPECT_EQ(expected
.status_code
,
149 static_cast<uint32_t>(parsed_headers
->response_code()));
150 for (const auto& item
: expected
.headers
)
151 EXPECT_TRUE(parsed_headers
->HasHeaderValue(item
.first
, item
.second
));
154 EXPECT_NE(-1, header_end
);
155 std::string
body(response
, static_cast<size_t>(header_end
));
156 EXPECT_EQ(*expected
.body
, body
);
158 EXPECT_EQ(response
.size(), static_cast<size_t>(header_end
));
162 class TestHttpClient
{
164 TestHttpClient() : connect_result_(net::OK
) {}
166 void Connect(const net::IPEndPoint
& address
) {
167 net::AddressList
addresses(address
);
168 net::NetLog::Source source
;
169 socket_
.reset(new net::TCPClientSocket(addresses
, NULL
, source
));
171 base::RunLoop run_loop
;
172 connect_result_
= socket_
->Connect(base::Bind(&TestHttpClient::OnConnect
,
173 base::Unretained(this),
174 run_loop
.QuitClosure()));
175 if (connect_result_
== net::ERR_IO_PENDING
)
178 ASSERT_EQ(net::OK
, connect_result_
);
181 void Send(const std::string
& data
) {
182 write_buffer_
= new net::DrainableIOBuffer(new net::StringIOBuffer(data
),
187 // Note: This method determines the end of the response only by Content-Length
188 // and connection termination. Besides, it doesn't truncate at the end of the
189 // response, so |message| may return more data (e.g., part of the next
191 void ReadResponse(std::string
* message
) {
192 if (!Read(message
, 1))
194 while (!IsCompleteResponse(*message
)) {
196 if (!Read(&chunk
, 1))
198 message
->append(chunk
);
204 void OnConnect(const base::Closure
& quit_loop
, int result
) {
205 connect_result_
= result
;
210 int result
= socket_
->Write(
211 write_buffer_
.get(), write_buffer_
->BytesRemaining(),
212 base::Bind(&TestHttpClient::OnWrite
, base::Unretained(this)));
213 if (result
!= net::ERR_IO_PENDING
)
217 void OnWrite(int result
) {
218 ASSERT_GT(result
, 0);
219 write_buffer_
->DidConsume(result
);
220 if (write_buffer_
->BytesRemaining())
224 bool Read(std::string
* message
, int expected_bytes
) {
225 int total_bytes_received
= 0;
227 while (total_bytes_received
< expected_bytes
) {
228 net::TestCompletionCallback callback
;
229 ReadInternal(callback
.callback());
230 int bytes_received
= callback
.WaitForResult();
231 if (bytes_received
<= 0)
234 total_bytes_received
+= bytes_received
;
235 message
->append(read_buffer_
->data(), bytes_received
);
240 void ReadInternal(const net::CompletionCallback
& callback
) {
241 read_buffer_
= new net::IOBufferWithSize(kMaxExpectedResponseLength
);
243 socket_
->Read(read_buffer_
.get(), kMaxExpectedResponseLength
, callback
);
244 if (result
!= net::ERR_IO_PENDING
)
245 callback
.Run(result
);
248 bool IsCompleteResponse(const std::string
& response
) {
249 // Check end of headers first.
251 net::HttpUtil::LocateEndOfHeaders(response
.data(), response
.size());
252 if (end_of_headers
< 0)
255 // Return true if response has data equal to or more than content length.
256 int64 body_size
= static_cast<int64
>(response
.size()) - end_of_headers
;
257 DCHECK_LE(0, body_size
);
258 scoped_refptr
<net::HttpResponseHeaders
> headers(
259 new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
260 response
.data(), end_of_headers
)));
261 return body_size
>= headers
->GetContentLength();
264 scoped_refptr
<net::IOBufferWithSize
> read_buffer_
;
265 scoped_refptr
<net::DrainableIOBuffer
> write_buffer_
;
266 scoped_ptr
<net::TCPClientSocket
> socket_
;
269 DISALLOW_COPY_AND_ASSIGN(TestHttpClient
);
272 class WebSocketClientImpl
: public WebSocketClient
{
274 explicit WebSocketClientImpl()
275 : binding_(this, &client_ptr_
),
276 wait_for_message_count_(0),
277 run_loop_(nullptr) {}
278 ~WebSocketClientImpl() override
{}
280 // Establishes a connection from the client side.
281 void Connect(WebSocketPtr web_socket
, const std::string
& url
) {
282 web_socket_
= web_socket
.Pass();
285 send_stream_
= data_pipe
.producer_handle
.Pass();
286 write_send_stream_
.reset(new WebSocketWriteQueue(send_stream_
.get()));
288 web_socket_
->Connect(url
, Array
<String
>(0), "http://example.com",
289 data_pipe
.consumer_handle
.Pass(), client_ptr_
.Pass());
292 // Establishes a connection from the server side.
293 void AcceptConnectRequest(
294 const HttpConnectionDelegate::OnReceivedWebSocketRequestCallback
&
296 InterfaceRequest
<WebSocket
> web_socket_request
= GetProxy(&web_socket_
);
299 send_stream_
= data_pipe
.producer_handle
.Pass();
300 write_send_stream_
.reset(new WebSocketWriteQueue(send_stream_
.get()));
302 callback
.Run(web_socket_request
.Pass(), data_pipe
.consumer_handle
.Pass(),
306 void WaitForConnectCompletion() {
309 if (receive_stream_
.is_valid())
312 base::RunLoop run_loop
;
313 run_loop_
= &run_loop
;
318 void Send(const std::string
& message
) {
319 DCHECK(!message
.empty());
321 uint32_t size
= static_cast<uint32_t>(message
.size());
322 write_send_stream_
->Write(
324 base::Bind(&WebSocketClientImpl::OnFinishedWritingSendStream
,
325 base::Unretained(this), size
));
328 void WaitForMessage(size_t count
) {
331 if (received_messages_
.size() >= count
)
333 wait_for_message_count_
= count
;
334 base::RunLoop run_loop
;
335 run_loop_
= &run_loop
;
340 std::vector
<std::string
>& received_messages() { return received_messages_
; }
343 // WebSocketClient implementation.
344 void DidConnect(const String
& selected_subprotocol
,
345 const String
& extensions
,
346 ScopedDataPipeConsumerHandle receive_stream
) override
{
347 receive_stream_
= receive_stream
.Pass();
348 read_receive_stream_
.reset(new WebSocketReadQueue(receive_stream_
.get()));
350 web_socket_
->FlowControl(2048);
355 void DidReceiveData(bool fin
,
356 WebSocket::MessageType type
,
357 uint32_t num_bytes
) override
{
358 DCHECK(num_bytes
> 0);
360 read_receive_stream_
->Read(
362 base::Bind(&WebSocketClientImpl::OnFinishedReadingReceiveStream
,
363 base::Unretained(this), num_bytes
));
366 void DidReceiveFlowControl(int64_t quota
) override
{}
368 void DidFail(const String
& message
) override
{}
370 void DidClose(bool was_clean
, uint16_t code
, const String
& reason
) override
{}
372 void OnFinishedWritingSendStream(uint32_t num_bytes
, const char* buffer
) {
375 web_socket_
->Send(true, WebSocket::MESSAGE_TYPE_TEXT
, num_bytes
);
378 void OnFinishedReadingReceiveStream(uint32_t num_bytes
, const char* data
) {
381 received_messages_
.push_back(std::string(data
, num_bytes
));
382 if (run_loop_
&& received_messages_
.size() >= wait_for_message_count_
) {
383 wait_for_message_count_
= 0;
388 WebSocketClientPtr client_ptr_
;
389 Binding
<WebSocketClient
> binding_
;
390 WebSocketPtr web_socket_
;
392 ScopedDataPipeProducerHandle send_stream_
;
393 scoped_ptr
<WebSocketWriteQueue
> write_send_stream_
;
395 ScopedDataPipeConsumerHandle receive_stream_
;
396 scoped_ptr
<WebSocketReadQueue
> read_receive_stream_
;
398 std::vector
<std::string
> received_messages_
;
399 size_t wait_for_message_count_
;
401 // Pointing to a stack-allocated RunLoop instance.
402 base::RunLoop
* run_loop_
;
404 DISALLOW_COPY_AND_ASSIGN(WebSocketClientImpl
);
407 class HttpConnectionDelegateImpl
: public HttpConnectionDelegate
{
409 struct PendingRequest
{
410 HttpRequestPtr request
;
411 OnReceivedRequestCallback callback
;
414 HttpConnectionDelegateImpl(HttpConnectionPtr connection
,
415 InterfaceRequest
<HttpConnectionDelegate
> request
)
416 : connection_(connection
.Pass()),
417 binding_(this, request
.Pass()),
418 wait_for_request_count_(0),
419 run_loop_(nullptr) {}
420 ~HttpConnectionDelegateImpl() override
{}
422 // HttpConnectionDelegate implementation:
423 void OnReceivedRequest(HttpRequestPtr request
,
424 const OnReceivedRequestCallback
& callback
) override
{
425 linked_ptr
<PendingRequest
> pending_request(new PendingRequest
);
426 pending_request
->request
= request
.Pass();
427 pending_request
->callback
= callback
;
428 pending_requests_
.push_back(pending_request
);
429 if (run_loop_
&& pending_requests_
.size() >= wait_for_request_count_
) {
430 wait_for_request_count_
= 0;
435 void OnReceivedWebSocketRequest(
436 HttpRequestPtr request
,
437 const OnReceivedWebSocketRequestCallback
& callback
) override
{
438 web_socket_
.reset(new WebSocketClientImpl());
440 web_socket_
->AcceptConnectRequest(callback
);
446 void SendResponse(HttpResponsePtr response
) {
447 ASSERT_FALSE(pending_requests_
.empty());
448 linked_ptr
<PendingRequest
> request
= pending_requests_
[0];
449 pending_requests_
.erase(pending_requests_
.begin());
450 request
->callback
.Run(response
.Pass());
453 void WaitForRequest(size_t count
) {
456 if (pending_requests_
.size() >= count
)
459 wait_for_request_count_
= count
;
460 base::RunLoop run_loop
;
461 run_loop_
= &run_loop
;
466 void WaitForWebSocketRequest() {
472 base::RunLoop run_loop
;
473 run_loop_
= &run_loop
;
478 std::vector
<linked_ptr
<PendingRequest
>>& pending_requests() {
479 return pending_requests_
;
482 WebSocketClientImpl
* web_socket() { return web_socket_
.get(); }
485 HttpConnectionPtr connection_
;
486 Binding
<HttpConnectionDelegate
> binding_
;
487 std::vector
<linked_ptr
<PendingRequest
>> pending_requests_
;
488 size_t wait_for_request_count_
;
489 scoped_ptr
<WebSocketClientImpl
> web_socket_
;
491 // Pointing to a stack-allocated RunLoop instance.
492 base::RunLoop
* run_loop_
;
494 DISALLOW_COPY_AND_ASSIGN(HttpConnectionDelegateImpl
);
497 class HttpServerDelegateImpl
: public HttpServerDelegate
{
499 explicit HttpServerDelegateImpl(HttpServerDelegatePtr
* delegate_ptr
)
500 : binding_(this, delegate_ptr
),
501 wait_for_connection_count_(0),
502 run_loop_(nullptr) {}
503 ~HttpServerDelegateImpl() override
{}
505 // HttpServerDelegate implementation.
506 void OnConnected(HttpConnectionPtr connection
,
507 InterfaceRequest
<HttpConnectionDelegate
> delegate
) override
{
508 connections_
.push_back(make_linked_ptr(
509 new HttpConnectionDelegateImpl(connection
.Pass(), delegate
.Pass())));
510 if (run_loop_
&& connections_
.size() >= wait_for_connection_count_
) {
511 wait_for_connection_count_
= 0;
516 void WaitForConnection(size_t count
) {
519 if (connections_
.size() >= count
)
522 wait_for_connection_count_
= count
;
523 base::RunLoop run_loop
;
524 run_loop_
= &run_loop
;
529 std::vector
<linked_ptr
<HttpConnectionDelegateImpl
>>& connections() {
534 Binding
<HttpServerDelegate
> binding_
;
535 std::vector
<linked_ptr
<HttpConnectionDelegateImpl
>> connections_
;
536 size_t wait_for_connection_count_
;
537 // Pointing to a stack-allocated RunLoop instance.
538 base::RunLoop
* run_loop_
;
540 DISALLOW_COPY_AND_ASSIGN(HttpServerDelegateImpl
);
543 class HttpServerAppTest
: public test::ApplicationTestBase
{
545 HttpServerAppTest() : message_loop_(base::MessageLoop::TYPE_IO
) {}
546 ~HttpServerAppTest() override
{}
549 bool ShouldCreateDefaultRunLoop() override
{ return false; }
551 void SetUp() override
{
552 ApplicationTestBase::SetUp();
554 mojo::URLRequestPtr
request(mojo::URLRequest::New());
555 request
->url
= mojo::String::From("mojo:network_service");
556 ApplicationConnection
* connection
=
557 application_impl()->ConnectToApplication(request
.Pass());
558 connection
->ConnectToService(&network_service_
);
561 void CreateHttpServer(HttpServerDelegatePtr delegate
,
562 NetAddressPtr
* out_bound_to
) {
563 network_service_
->CreateHttpServer(
564 GetLocalHostWithAnyPort(), delegate
.Pass(),
565 [out_bound_to
](NetworkErrorPtr result
, NetAddressPtr bound_to
) {
566 ASSERT_EQ(net::OK
, result
->code
);
567 EXPECT_NE(0u, bound_to
->ipv4
->port
);
568 *out_bound_to
= bound_to
.Pass();
570 network_service_
.WaitForIncomingResponse();
573 NetworkServicePtr network_service_
;
576 base::MessageLoop message_loop_
;
578 DISALLOW_COPY_AND_ASSIGN(HttpServerAppTest
);
583 TEST_F(HttpServerAppTest
, BasicHttpRequestResponse
) {
584 NetAddressPtr bound_to
;
585 HttpServerDelegatePtr server_delegate_ptr
;
586 HttpServerDelegateImpl
server_delegate_impl(&server_delegate_ptr
);
587 CreateHttpServer(server_delegate_ptr
.Pass(), &bound_to
);
589 TestHttpClient client
;
590 client
.Connect(bound_to
.To
<net::IPEndPoint
>());
592 server_delegate_impl
.WaitForConnection(1);
593 HttpConnectionDelegateImpl
& connection
=
594 *server_delegate_impl
.connections()[0];
596 TestRequest request_data
= {"HEAD", "/test", {{"Hello", "World"}}, nullptr};
597 client
.Send(MakeRequestMessage(request_data
));
599 connection
.WaitForRequest(1);
601 CheckRequest(request_data
, connection
.pending_requests()[0]->request
.Pass());
603 TestResponse response_data
= {200, {{"Content-Length", "4"}}, nullptr};
604 connection
.SendResponse(MakeResponseStruct(response_data
));
605 // This causes the underlying TCP connection to be closed. The client can
606 // determine the end of the response based on that.
607 server_delegate_impl
.connections().clear();
609 std::string response_message
;
610 client
.ReadResponse(&response_message
);
612 CheckResponse(response_data
, response_message
);
615 TEST_F(HttpServerAppTest
, HttpRequestResponseWithBody
) {
616 NetAddressPtr bound_to
;
617 HttpServerDelegatePtr server_delegate_ptr
;
618 HttpServerDelegateImpl
server_delegate_impl(&server_delegate_ptr
);
619 CreateHttpServer(server_delegate_ptr
.Pass(), &bound_to
);
621 TestHttpClient client
;
622 client
.Connect(bound_to
.To
<net::IPEndPoint
>());
624 server_delegate_impl
.WaitForConnection(1);
625 HttpConnectionDelegateImpl
& connection
=
626 *server_delegate_impl
.connections()[0];
628 TestRequest request_data
= {
632 {"Content-Length", "23"},
633 {"Content-Type", "text/plain"}},
634 make_scoped_ptr(new std::string("This is a test request!"))};
635 client
.Send(MakeRequestMessage(request_data
));
637 connection
.WaitForRequest(1);
639 CheckRequest(request_data
, connection
.pending_requests()[0]->request
.Pass());
641 TestResponse response_data
= {
643 {{"Content-Length", "26"}},
644 make_scoped_ptr(new std::string("This is a test response..."))};
645 connection
.SendResponse(MakeResponseStruct(response_data
));
647 std::string response_message
;
648 client
.ReadResponse(&response_message
);
650 CheckResponse(response_data
, response_message
);
653 TEST_F(HttpServerAppTest
, WebSocket
) {
654 NetAddressPtr bound_to
;
655 HttpServerDelegatePtr server_delegate_ptr
;
656 HttpServerDelegateImpl
server_delegate_impl(&server_delegate_ptr
);
657 CreateHttpServer(server_delegate_ptr
.Pass(), &bound_to
);
659 WebSocketPtr web_socket_ptr
;
660 network_service_
->CreateWebSocket(GetProxy(&web_socket_ptr
));
661 WebSocketClientImpl socket_0
;
663 web_socket_ptr
.Pass(),
664 base::StringPrintf("ws://127.0.0.1:%d/hello", bound_to
->ipv4
->port
));
666 server_delegate_impl
.WaitForConnection(1);
667 HttpConnectionDelegateImpl
& connection
=
668 *server_delegate_impl
.connections()[0];
670 connection
.WaitForWebSocketRequest();
671 WebSocketClientImpl
& socket_1
= *connection
.web_socket();
673 socket_1
.WaitForConnectCompletion();
674 socket_0
.WaitForConnectCompletion();
676 socket_0
.Send("Hello");
677 socket_0
.Send("world!");
679 socket_1
.WaitForMessage(2);
680 EXPECT_EQ("Hello", socket_1
.received_messages()[0]);
681 EXPECT_EQ("world!", socket_1
.received_messages()[1]);
683 socket_1
.Send("How do");
684 socket_1
.Send("you do?");
686 socket_0
.WaitForMessage(2);
687 EXPECT_EQ("How do", socket_0
.received_messages()[0]);
688 EXPECT_EQ("you do?", socket_0
.received_messages()[1]);