OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include <stddef.h> | |
6 #include <stdint.h> | |
7 | |
8 #include <utility> | |
9 | |
10 #include "base/logging.h" | |
11 #include "base/macros.h" | |
12 #include "base/memory/linked_ptr.h" | |
13 #include "base/memory/ref_counted.h" | |
14 #include "base/memory/scoped_ptr.h" | |
15 #include "base/run_loop.h" | |
16 #include "base/strings/string_util.h" | |
17 #include "base/strings/stringprintf.h" | |
18 #include "mojo/common/data_pipe_utils.h" | |
19 #include "mojo/services/network/net_address_type_converters.h" | |
20 #include "mojo/services/network/public/cpp/web_socket_read_queue.h" | |
21 #include "mojo/services/network/public/cpp/web_socket_write_queue.h" | |
22 #include "mojo/services/network/public/interfaces/http_connection.mojom.h" | |
23 #include "mojo/services/network/public/interfaces/http_message.mojom.h" | |
24 #include "mojo/services/network/public/interfaces/http_server.mojom.h" | |
25 #include "mojo/services/network/public/interfaces/net_address.mojom.h" | |
26 #include "mojo/services/network/public/interfaces/network_service.mojom.h" | |
27 #include "mojo/services/network/public/interfaces/web_socket.mojom.h" | |
28 #include "mojo/services/network/public/interfaces/web_socket_factory.mojom.h" | |
29 #include "mojo/shell/public/cpp/shell_test.h" | |
30 #include "net/base/io_buffer.h" | |
31 #include "net/base/net_errors.h" | |
32 #include "net/base/test_completion_callback.h" | |
33 #include "net/http/http_response_headers.h" | |
34 #include "net/http/http_util.h" | |
35 #include "net/socket/tcp_client_socket.h" | |
36 #include "testing/gtest/include/gtest/gtest.h" | |
37 | |
38 namespace mojo { | |
39 namespace { | |
40 | |
41 const int kMaxExpectedResponseLength = 2048; | |
42 | |
43 NetAddressPtr GetLocalHostWithAnyPort() { | |
44 NetAddressPtr addr(NetAddress::New()); | |
45 addr->family = NetAddressFamily::IPV4; | |
46 addr->ipv4 = NetAddressIPv4::New(); | |
47 addr->ipv4->port = 0; | |
48 addr->ipv4->addr.resize(4); | |
49 addr->ipv4->addr[0] = 127; | |
50 addr->ipv4->addr[1] = 0; | |
51 addr->ipv4->addr[2] = 0; | |
52 addr->ipv4->addr[3] = 1; | |
53 | |
54 return addr; | |
55 } | |
56 | |
57 using TestHeaders = std::vector<std::pair<std::string, std::string>>; | |
58 | |
59 struct TestRequest { | |
60 std::string method; | |
61 std::string url; | |
62 TestHeaders headers; | |
63 scoped_ptr<std::string> body; | |
64 }; | |
65 | |
66 struct TestResponse { | |
67 uint32_t status_code; | |
68 TestHeaders headers; | |
69 scoped_ptr<std::string> body; | |
70 }; | |
71 | |
72 std::string MakeRequestMessage(const TestRequest& data) { | |
73 std::string message = data.method + " " + data.url + " HTTP/1.1\r\n"; | |
74 for (const auto& item : data.headers) | |
75 message += item.first + ": " + item.second + "\r\n"; | |
76 message += "\r\n"; | |
77 if (data.body) | |
78 message += *data.body; | |
79 | |
80 return message; | |
81 } | |
82 | |
83 HttpResponsePtr MakeResponseStruct(const TestResponse& data) { | |
84 HttpResponsePtr response(HttpResponse::New()); | |
85 response->status_code = data.status_code; | |
86 response->headers.resize(data.headers.size()); | |
87 size_t index = 0; | |
88 for (const auto& item : data.headers) { | |
89 HttpHeaderPtr header(HttpHeader::New()); | |
90 header->name = item.first; | |
91 header->value = item.second; | |
92 response->headers[index++] = std::move(header); | |
93 } | |
94 | |
95 if (data.body) { | |
96 uint32_t num_bytes = static_cast<uint32_t>(data.body->size()); | |
97 MojoCreateDataPipeOptions options; | |
98 options.struct_size = sizeof(MojoCreateDataPipeOptions); | |
99 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; | |
100 options.element_num_bytes = 1; | |
101 options.capacity_num_bytes = num_bytes; | |
102 DataPipe data_pipe(options); | |
103 response->body = std::move(data_pipe.consumer_handle); | |
104 MojoResult result = | |
105 WriteDataRaw(data_pipe.producer_handle.get(), data.body->data(), | |
106 &num_bytes, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); | |
107 EXPECT_EQ(MOJO_RESULT_OK, result); | |
108 } | |
109 | |
110 return response; | |
111 } | |
112 | |
113 void CheckHeaders(const TestHeaders& expected, | |
114 const Array<HttpHeaderPtr>& headers) { | |
115 // The server impl fiddles with Content-Length and Content-Type. So we don't | |
116 // do a strict check here. | |
117 std::map<std::string, std::string> header_map; | |
118 for (size_t i = 0; i < headers.size(); ++i) { | |
119 std::string lower_name = | |
120 base::ToLowerASCII(headers[i]->name.To<std::string>()); | |
121 header_map[lower_name] = headers[i]->value; | |
122 } | |
123 | |
124 for (const auto& item : expected) { | |
125 std::string lower_name = base::ToLowerASCII(item.first); | |
126 EXPECT_NE(header_map.end(), header_map.find(lower_name)); | |
127 EXPECT_EQ(item.second, header_map[lower_name]); | |
128 } | |
129 } | |
130 | |
131 void CheckRequest(const TestRequest& expected, HttpRequestPtr request) { | |
132 EXPECT_EQ(expected.method, request->method); | |
133 EXPECT_EQ(expected.url, request->url); | |
134 CheckHeaders(expected.headers, request->headers); | |
135 if (expected.body) { | |
136 EXPECT_TRUE(request->body.is_valid()); | |
137 std::string body; | |
138 common::BlockingCopyToString(std::move(request->body), &body); | |
139 EXPECT_EQ(*expected.body, body); | |
140 } else { | |
141 EXPECT_FALSE(request->body.is_valid()); | |
142 } | |
143 } | |
144 | |
145 void CheckResponse(const TestResponse& expected, const std::string& response) { | |
146 int header_end = | |
147 net::HttpUtil::LocateEndOfHeaders(response.c_str(), response.size()); | |
148 std::string assembled_headers = | |
149 net::HttpUtil::AssembleRawHeaders(response.c_str(), header_end); | |
150 scoped_refptr<net::HttpResponseHeaders> parsed_headers( | |
151 new net::HttpResponseHeaders(assembled_headers)); | |
152 EXPECT_EQ(expected.status_code, | |
153 static_cast<uint32_t>(parsed_headers->response_code())); | |
154 for (const auto& item : expected.headers) | |
155 EXPECT_TRUE(parsed_headers->HasHeaderValue(item.first, item.second)); | |
156 | |
157 if (expected.body) { | |
158 EXPECT_NE(-1, header_end); | |
159 std::string body(response, static_cast<size_t>(header_end)); | |
160 EXPECT_EQ(*expected.body, body); | |
161 } else { | |
162 EXPECT_EQ(response.size(), static_cast<size_t>(header_end)); | |
163 } | |
164 } | |
165 | |
166 class TestHttpClient { | |
167 public: | |
168 TestHttpClient() : connect_result_(net::OK) {} | |
169 | |
170 void Connect(const net::IPEndPoint& address) { | |
171 net::AddressList addresses(address); | |
172 net::NetLog::Source source; | |
173 socket_.reset(new net::TCPClientSocket(addresses, NULL, source)); | |
174 | |
175 base::RunLoop run_loop; | |
176 connect_result_ = socket_->Connect(base::Bind(&TestHttpClient::OnConnect, | |
177 base::Unretained(this), | |
178 run_loop.QuitClosure())); | |
179 if (connect_result_ == net::ERR_IO_PENDING) | |
180 run_loop.Run(); | |
181 | |
182 ASSERT_EQ(net::OK, connect_result_); | |
183 } | |
184 | |
185 void Send(const std::string& data) { | |
186 write_buffer_ = new net::DrainableIOBuffer(new net::StringIOBuffer(data), | |
187 data.length()); | |
188 Write(); | |
189 } | |
190 | |
191 // Note: This method determines the end of the response only by Content-Length | |
192 // and connection termination. Besides, it doesn't truncate at the end of the | |
193 // response, so |message| may return more data (e.g., part of the next | |
194 // response). | |
195 void ReadResponse(std::string* message) { | |
196 if (!Read(message, 1)) | |
197 return; | |
198 while (!IsCompleteResponse(*message)) { | |
199 std::string chunk; | |
200 if (!Read(&chunk, 1)) | |
201 return; | |
202 message->append(chunk); | |
203 } | |
204 return; | |
205 } | |
206 | |
207 private: | |
208 void OnConnect(const base::Closure& quit_loop, int result) { | |
209 connect_result_ = result; | |
210 quit_loop.Run(); | |
211 } | |
212 | |
213 void Write() { | |
214 int result = socket_->Write( | |
215 write_buffer_.get(), write_buffer_->BytesRemaining(), | |
216 base::Bind(&TestHttpClient::OnWrite, base::Unretained(this))); | |
217 if (result != net::ERR_IO_PENDING) | |
218 OnWrite(result); | |
219 } | |
220 | |
221 void OnWrite(int result) { | |
222 ASSERT_GT(result, 0); | |
223 write_buffer_->DidConsume(result); | |
224 if (write_buffer_->BytesRemaining()) | |
225 Write(); | |
226 } | |
227 | |
228 bool Read(std::string* message, int expected_bytes) { | |
229 int total_bytes_received = 0; | |
230 message->clear(); | |
231 while (total_bytes_received < expected_bytes) { | |
232 net::TestCompletionCallback callback; | |
233 ReadInternal(callback.callback()); | |
234 int bytes_received = callback.WaitForResult(); | |
235 if (bytes_received <= 0) | |
236 return false; | |
237 | |
238 total_bytes_received += bytes_received; | |
239 message->append(read_buffer_->data(), bytes_received); | |
240 } | |
241 return true; | |
242 } | |
243 | |
244 void ReadInternal(const net::CompletionCallback& callback) { | |
245 read_buffer_ = new net::IOBufferWithSize(kMaxExpectedResponseLength); | |
246 int result = | |
247 socket_->Read(read_buffer_.get(), kMaxExpectedResponseLength, callback); | |
248 if (result != net::ERR_IO_PENDING) | |
249 callback.Run(result); | |
250 } | |
251 | |
252 bool IsCompleteResponse(const std::string& response) { | |
253 // Check end of headers first. | |
254 int end_of_headers = | |
255 net::HttpUtil::LocateEndOfHeaders(response.data(), response.size()); | |
256 if (end_of_headers < 0) | |
257 return false; | |
258 | |
259 // Return true if response has data equal to or more than content length. | |
260 int64_t body_size = static_cast<int64_t>(response.size()) - end_of_headers; | |
261 DCHECK_LE(0, body_size); | |
262 scoped_refptr<net::HttpResponseHeaders> headers( | |
263 new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( | |
264 response.data(), end_of_headers))); | |
265 return body_size >= headers->GetContentLength(); | |
266 } | |
267 | |
268 scoped_refptr<net::IOBufferWithSize> read_buffer_; | |
269 scoped_refptr<net::DrainableIOBuffer> write_buffer_; | |
270 scoped_ptr<net::TCPClientSocket> socket_; | |
271 int connect_result_; | |
272 | |
273 DISALLOW_COPY_AND_ASSIGN(TestHttpClient); | |
274 }; | |
275 | |
276 class WebSocketClientImpl : public WebSocketClient { | |
277 public: | |
278 explicit WebSocketClientImpl() | |
279 : binding_(this, &client_ptr_), | |
280 wait_for_message_count_(0), | |
281 run_loop_(nullptr) {} | |
282 ~WebSocketClientImpl() override {} | |
283 | |
284 // Establishes a connection from the client side. | |
285 void Connect(WebSocketPtr web_socket, const std::string& url) { | |
286 web_socket_ = std::move(web_socket); | |
287 | |
288 DataPipe data_pipe; | |
289 send_stream_ = std::move(data_pipe.producer_handle); | |
290 write_send_stream_.reset(new WebSocketWriteQueue(send_stream_.get())); | |
291 | |
292 web_socket_->Connect(url, Array<String>(), "http://example.com", | |
293 std::move(data_pipe.consumer_handle), | |
294 std::move(client_ptr_)); | |
295 } | |
296 | |
297 // Establishes a connection from the server side. | |
298 void AcceptConnectRequest( | |
299 const HttpConnectionDelegate::OnReceivedWebSocketRequestCallback& | |
300 callback) { | |
301 InterfaceRequest<WebSocket> web_socket_request = GetProxy(&web_socket_); | |
302 | |
303 DataPipe data_pipe; | |
304 send_stream_ = std::move(data_pipe.producer_handle); | |
305 write_send_stream_.reset(new WebSocketWriteQueue(send_stream_.get())); | |
306 | |
307 callback.Run(std::move(web_socket_request), | |
308 std::move(data_pipe.consumer_handle), std::move(client_ptr_)); | |
309 } | |
310 | |
311 void WaitForConnectCompletion() { | |
312 DCHECK(!run_loop_); | |
313 | |
314 if (receive_stream_.is_valid()) | |
315 return; | |
316 | |
317 base::RunLoop run_loop; | |
318 run_loop_ = &run_loop; | |
319 run_loop.Run(); | |
320 run_loop_ = nullptr; | |
321 } | |
322 | |
323 void Send(const std::string& message) { | |
324 DCHECK(!message.empty()); | |
325 | |
326 uint32_t size = static_cast<uint32_t>(message.size()); | |
327 write_send_stream_->Write( | |
328 &message[0], size, | |
329 base::Bind(&WebSocketClientImpl::OnFinishedWritingSendStream, | |
330 base::Unretained(this), size)); | |
331 } | |
332 | |
333 void WaitForMessage(size_t count) { | |
334 DCHECK(!run_loop_); | |
335 | |
336 if (received_messages_.size() >= count) | |
337 return; | |
338 wait_for_message_count_ = count; | |
339 base::RunLoop run_loop; | |
340 run_loop_ = &run_loop; | |
341 run_loop.Run(); | |
342 run_loop_ = nullptr; | |
343 } | |
344 | |
345 std::vector<std::string>& received_messages() { return received_messages_; } | |
346 | |
347 private: | |
348 // WebSocketClient implementation. | |
349 void DidConnect(const String& selected_subprotocol, | |
350 const String& extensions, | |
351 ScopedDataPipeConsumerHandle receive_stream) override { | |
352 receive_stream_ = std::move(receive_stream); | |
353 read_receive_stream_.reset(new WebSocketReadQueue(receive_stream_.get())); | |
354 | |
355 web_socket_->FlowControl(2048); | |
356 if (run_loop_) | |
357 run_loop_->Quit(); | |
358 } | |
359 | |
360 void DidReceiveData(bool fin, | |
361 WebSocket::MessageType type, | |
362 uint32_t num_bytes) override { | |
363 DCHECK(num_bytes > 0); | |
364 | |
365 read_receive_stream_->Read( | |
366 num_bytes, | |
367 base::Bind(&WebSocketClientImpl::OnFinishedReadingReceiveStream, | |
368 base::Unretained(this), num_bytes)); | |
369 } | |
370 | |
371 void DidReceiveFlowControl(int64_t quota) override {} | |
372 | |
373 void DidFail(const String& message) override {} | |
374 | |
375 void DidClose(bool was_clean, uint16_t code, const String& reason) override {} | |
376 | |
377 void OnFinishedWritingSendStream(uint32_t num_bytes, const char* buffer) { | |
378 EXPECT_TRUE(buffer); | |
379 | |
380 web_socket_->Send(true, WebSocket::MessageType::TEXT, num_bytes); | |
381 } | |
382 | |
383 void OnFinishedReadingReceiveStream(uint32_t num_bytes, const char* data) { | |
384 EXPECT_TRUE(data); | |
385 | |
386 received_messages_.push_back(std::string(data, num_bytes)); | |
387 if (run_loop_ && received_messages_.size() >= wait_for_message_count_) { | |
388 wait_for_message_count_ = 0; | |
389 run_loop_->Quit(); | |
390 } | |
391 } | |
392 | |
393 WebSocketClientPtr client_ptr_; | |
394 Binding<WebSocketClient> binding_; | |
395 WebSocketPtr web_socket_; | |
396 | |
397 ScopedDataPipeProducerHandle send_stream_; | |
398 scoped_ptr<WebSocketWriteQueue> write_send_stream_; | |
399 | |
400 ScopedDataPipeConsumerHandle receive_stream_; | |
401 scoped_ptr<WebSocketReadQueue> read_receive_stream_; | |
402 | |
403 std::vector<std::string> received_messages_; | |
404 size_t wait_for_message_count_; | |
405 | |
406 // Pointing to a stack-allocated RunLoop instance. | |
407 base::RunLoop* run_loop_; | |
408 | |
409 DISALLOW_COPY_AND_ASSIGN(WebSocketClientImpl); | |
410 }; | |
411 | |
412 class HttpConnectionDelegateImpl : public HttpConnectionDelegate { | |
413 public: | |
414 struct PendingRequest { | |
415 HttpRequestPtr request; | |
416 OnReceivedRequestCallback callback; | |
417 }; | |
418 | |
419 HttpConnectionDelegateImpl(HttpConnectionPtr connection, | |
420 InterfaceRequest<HttpConnectionDelegate> request) | |
421 : connection_(std::move(connection)), | |
422 binding_(this, std::move(request)), | |
423 wait_for_request_count_(0), | |
424 run_loop_(nullptr) {} | |
425 ~HttpConnectionDelegateImpl() override {} | |
426 | |
427 // HttpConnectionDelegate implementation: | |
428 void OnReceivedRequest(HttpRequestPtr request, | |
429 const OnReceivedRequestCallback& callback) override { | |
430 linked_ptr<PendingRequest> pending_request(new PendingRequest); | |
431 pending_request->request = std::move(request); | |
432 pending_request->callback = callback; | |
433 pending_requests_.push_back(pending_request); | |
434 if (run_loop_ && pending_requests_.size() >= wait_for_request_count_) { | |
435 wait_for_request_count_ = 0; | |
436 run_loop_->Quit(); | |
437 } | |
438 } | |
439 | |
440 void OnReceivedWebSocketRequest( | |
441 HttpRequestPtr request, | |
442 const OnReceivedWebSocketRequestCallback& callback) override { | |
443 web_socket_.reset(new WebSocketClientImpl()); | |
444 | |
445 web_socket_->AcceptConnectRequest(callback); | |
446 | |
447 if (run_loop_) | |
448 run_loop_->Quit(); | |
449 } | |
450 | |
451 void SendResponse(HttpResponsePtr response) { | |
452 ASSERT_FALSE(pending_requests_.empty()); | |
453 linked_ptr<PendingRequest> request = pending_requests_[0]; | |
454 pending_requests_.erase(pending_requests_.begin()); | |
455 request->callback.Run(std::move(response)); | |
456 } | |
457 | |
458 void WaitForRequest(size_t count) { | |
459 DCHECK(!run_loop_); | |
460 | |
461 if (pending_requests_.size() >= count) | |
462 return; | |
463 | |
464 wait_for_request_count_ = count; | |
465 base::RunLoop run_loop; | |
466 run_loop_ = &run_loop; | |
467 run_loop.Run(); | |
468 run_loop_ = nullptr; | |
469 } | |
470 | |
471 void WaitForWebSocketRequest() { | |
472 DCHECK(!run_loop_); | |
473 | |
474 if (web_socket_) | |
475 return; | |
476 | |
477 base::RunLoop run_loop; | |
478 run_loop_ = &run_loop; | |
479 run_loop.Run(); | |
480 run_loop_ = nullptr; | |
481 } | |
482 | |
483 std::vector<linked_ptr<PendingRequest>>& pending_requests() { | |
484 return pending_requests_; | |
485 } | |
486 | |
487 WebSocketClientImpl* web_socket() { return web_socket_.get(); } | |
488 | |
489 private: | |
490 HttpConnectionPtr connection_; | |
491 Binding<HttpConnectionDelegate> binding_; | |
492 std::vector<linked_ptr<PendingRequest>> pending_requests_; | |
493 size_t wait_for_request_count_; | |
494 scoped_ptr<WebSocketClientImpl> web_socket_; | |
495 | |
496 // Pointing to a stack-allocated RunLoop instance. | |
497 base::RunLoop* run_loop_; | |
498 | |
499 DISALLOW_COPY_AND_ASSIGN(HttpConnectionDelegateImpl); | |
500 }; | |
501 | |
502 class HttpServerDelegateImpl : public HttpServerDelegate { | |
503 public: | |
504 explicit HttpServerDelegateImpl(HttpServerDelegatePtr* delegate_ptr) | |
505 : binding_(this, delegate_ptr), | |
506 wait_for_connection_count_(0), | |
507 run_loop_(nullptr) {} | |
508 ~HttpServerDelegateImpl() override {} | |
509 | |
510 // HttpServerDelegate implementation. | |
511 void OnConnected(HttpConnectionPtr connection, | |
512 InterfaceRequest<HttpConnectionDelegate> delegate) override { | |
513 connections_.push_back(make_linked_ptr(new HttpConnectionDelegateImpl( | |
514 std::move(connection), std::move(delegate)))); | |
515 if (run_loop_ && connections_.size() >= wait_for_connection_count_) { | |
516 wait_for_connection_count_ = 0; | |
517 run_loop_->Quit(); | |
518 } | |
519 } | |
520 | |
521 void WaitForConnection(size_t count) { | |
522 DCHECK(!run_loop_); | |
523 | |
524 if (connections_.size() >= count) | |
525 return; | |
526 | |
527 wait_for_connection_count_ = count; | |
528 base::RunLoop run_loop; | |
529 run_loop_ = &run_loop; | |
530 run_loop.Run(); | |
531 run_loop_ = nullptr; | |
532 } | |
533 | |
534 std::vector<linked_ptr<HttpConnectionDelegateImpl>>& connections() { | |
535 return connections_; | |
536 } | |
537 | |
538 private: | |
539 Binding<HttpServerDelegate> binding_; | |
540 std::vector<linked_ptr<HttpConnectionDelegateImpl>> connections_; | |
541 size_t wait_for_connection_count_; | |
542 // Pointing to a stack-allocated RunLoop instance. | |
543 base::RunLoop* run_loop_; | |
544 | |
545 DISALLOW_COPY_AND_ASSIGN(HttpServerDelegateImpl); | |
546 }; | |
547 | |
548 class HttpServerTest : public test::ShellTest { | |
549 public: | |
550 HttpServerTest() | |
551 : ShellTest("exe:network_service_unittests") {} | |
552 ~HttpServerTest() override {} | |
553 | |
554 protected: | |
555 void SetUp() override { | |
556 ShellTest::SetUp(); | |
557 | |
558 scoped_ptr<Connection> connection = | |
559 connector()->Connect("mojo:network_service"); | |
560 connection->GetInterface(&network_service_); | |
561 connection->GetInterface(&web_socket_factory_); | |
562 } | |
563 | |
564 scoped_ptr<base::MessageLoop> CreateMessageLoop() override { | |
565 return make_scoped_ptr(new base::MessageLoop(base::MessageLoop::TYPE_IO)); | |
566 } | |
567 | |
568 void CreateHttpServer(HttpServerDelegatePtr delegate, | |
569 NetAddressPtr* out_bound_to) { | |
570 base::RunLoop loop; | |
571 network_service_->CreateHttpServer( | |
572 GetLocalHostWithAnyPort(), std::move(delegate), | |
573 [out_bound_to, &loop](NetworkErrorPtr result, NetAddressPtr bound_to) { | |
574 ASSERT_EQ(net::OK, result->code); | |
575 EXPECT_NE(0u, bound_to->ipv4->port); | |
576 *out_bound_to = std::move(bound_to); | |
577 loop.Quit(); | |
578 }); | |
579 loop.Run(); | |
580 } | |
581 | |
582 NetworkServicePtr network_service_; | |
583 WebSocketFactoryPtr web_socket_factory_; | |
584 | |
585 private: | |
586 DISALLOW_COPY_AND_ASSIGN(HttpServerTest); | |
587 }; | |
588 | |
589 } // namespace | |
590 | |
591 TEST_F(HttpServerTest, BasicHttpRequestResponse) { | |
592 NetAddressPtr bound_to; | |
593 HttpServerDelegatePtr server_delegate_ptr; | |
594 HttpServerDelegateImpl server_delegate_impl(&server_delegate_ptr); | |
595 CreateHttpServer(std::move(server_delegate_ptr), &bound_to); | |
596 | |
597 TestHttpClient client; | |
598 client.Connect(bound_to.To<net::IPEndPoint>()); | |
599 | |
600 server_delegate_impl.WaitForConnection(1); | |
601 HttpConnectionDelegateImpl& connection = | |
602 *server_delegate_impl.connections()[0]; | |
603 | |
604 TestRequest request_data = {"HEAD", "/test", {{"Hello", "World"}}, nullptr}; | |
605 client.Send(MakeRequestMessage(request_data)); | |
606 | |
607 connection.WaitForRequest(1); | |
608 | |
609 CheckRequest(request_data, | |
610 std::move(connection.pending_requests()[0]->request)); | |
611 | |
612 TestResponse response_data = {200, {{"Content-Length", "4"}}, nullptr}; | |
613 connection.SendResponse(MakeResponseStruct(response_data)); | |
614 // This causes the underlying TCP connection to be closed. The client can | |
615 // determine the end of the response based on that. | |
616 server_delegate_impl.connections().clear(); | |
617 | |
618 std::string response_message; | |
619 client.ReadResponse(&response_message); | |
620 | |
621 CheckResponse(response_data, response_message); | |
622 } | |
623 | |
624 TEST_F(HttpServerTest, HttpRequestResponseWithBody) { | |
625 NetAddressPtr bound_to; | |
626 HttpServerDelegatePtr server_delegate_ptr; | |
627 HttpServerDelegateImpl server_delegate_impl(&server_delegate_ptr); | |
628 CreateHttpServer(std::move(server_delegate_ptr), &bound_to); | |
629 | |
630 TestHttpClient client; | |
631 client.Connect(bound_to.To<net::IPEndPoint>()); | |
632 | |
633 server_delegate_impl.WaitForConnection(1); | |
634 HttpConnectionDelegateImpl& connection = | |
635 *server_delegate_impl.connections()[0]; | |
636 | |
637 TestRequest request_data = { | |
638 "Post", | |
639 "/test", | |
640 {{"Hello", "World"}, | |
641 {"Content-Length", "23"}, | |
642 {"Content-Type", "text/plain"}}, | |
643 make_scoped_ptr(new std::string("This is a test request!"))}; | |
644 client.Send(MakeRequestMessage(request_data)); | |
645 | |
646 connection.WaitForRequest(1); | |
647 | |
648 CheckRequest(request_data, | |
649 std::move(connection.pending_requests()[0]->request)); | |
650 | |
651 TestResponse response_data = { | |
652 200, | |
653 {{"Content-Length", "26"}}, | |
654 make_scoped_ptr(new std::string("This is a test response..."))}; | |
655 connection.SendResponse(MakeResponseStruct(response_data)); | |
656 | |
657 std::string response_message; | |
658 client.ReadResponse(&response_message); | |
659 | |
660 CheckResponse(response_data, response_message); | |
661 } | |
662 | |
663 TEST_F(HttpServerTest, WebSocket) { | |
664 NetAddressPtr bound_to; | |
665 HttpServerDelegatePtr server_delegate_ptr; | |
666 HttpServerDelegateImpl server_delegate_impl(&server_delegate_ptr); | |
667 CreateHttpServer(std::move(server_delegate_ptr), &bound_to); | |
668 | |
669 WebSocketPtr web_socket_ptr; | |
670 web_socket_factory_->CreateWebSocket(GetProxy(&web_socket_ptr)); | |
671 WebSocketClientImpl socket_0; | |
672 socket_0.Connect( | |
673 std::move(web_socket_ptr), | |
674 base::StringPrintf("ws://127.0.0.1:%d/hello", bound_to->ipv4->port)); | |
675 | |
676 server_delegate_impl.WaitForConnection(1); | |
677 HttpConnectionDelegateImpl& connection = | |
678 *server_delegate_impl.connections()[0]; | |
679 | |
680 connection.WaitForWebSocketRequest(); | |
681 WebSocketClientImpl& socket_1 = *connection.web_socket(); | |
682 | |
683 socket_1.WaitForConnectCompletion(); | |
684 socket_0.WaitForConnectCompletion(); | |
685 | |
686 socket_0.Send("Hello"); | |
687 socket_0.Send("world!"); | |
688 | |
689 socket_1.WaitForMessage(2); | |
690 EXPECT_EQ("Hello", socket_1.received_messages()[0]); | |
691 EXPECT_EQ("world!", socket_1.received_messages()[1]); | |
692 | |
693 socket_1.Send("How do"); | |
694 socket_1.Send("you do?"); | |
695 | |
696 socket_0.WaitForMessage(2); | |
697 EXPECT_EQ("How do", socket_0.received_messages()[0]); | |
698 EXPECT_EQ("you do?", socket_0.received_messages()[1]); | |
699 } | |
700 | |
701 } // namespace mojo | |
OLD | NEW |