1 // Copyright 2013 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 "net/tools/flip_server/http_interface.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_piece.h"
12 #include "net/tools/balsa/balsa_enums.h"
13 #include "net/tools/balsa/balsa_frame.h"
14 #include "net/tools/balsa/balsa_headers.h"
15 #include "net/tools/flip_server/flip_config.h"
16 #include "net/tools/flip_server/flip_test_utils.h"
17 #include "net/tools/flip_server/mem_cache.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
23 using ::base::StringPiece
;
25 using ::testing::InSequence
;
29 class MockSMConnection
: public SMConnection
{
31 MockSMConnection(EpollServer
* epoll_server
,
33 MemoryCache
* memory_cache
,
34 FlipAcceptor
* acceptor
,
35 std::string log_prefix
)
36 : SMConnection(epoll_server
,
42 MOCK_METHOD0(Cleanup
, void());
43 MOCK_METHOD8(InitSMConnection
,
44 void(SMConnectionPoolInterface
*,
54 class FlipHttpSMTest
: public ::testing::Test
{
56 explicit FlipHttpSMTest(FlipHandlerType type
= FLIP_HANDLER_PROXY
) {
57 SSLState
* ssl_state
= NULL
;
58 mock_another_interface_
.reset(new MockSMInterface
);
59 memory_cache_
.reset(new MemoryCache
);
60 acceptor_
.reset(new FlipAcceptor(type
,
76 epoll_server_
.reset(new EpollServer
);
77 connection_
.reset(new MockSMConnection(epoll_server_
.get(),
83 interface_
.reset(new HttpSM(connection_
.get(),
84 mock_another_interface_
.get(),
89 virtual void TearDown() override
{
90 if (acceptor_
->listen_fd_
>= 0) {
91 epoll_server_
->UnregisterFD(acceptor_
->listen_fd_
);
92 close(acceptor_
->listen_fd_
);
93 acceptor_
->listen_fd_
= -1;
95 STLDeleteElements(connection_
->output_list());
98 bool HasStream(uint32 stream_id
) {
99 return interface_
->output_ordering().ExistsInPriorityMaps(stream_id
);
103 scoped_ptr
<MockSMInterface
> mock_another_interface_
;
104 scoped_ptr
<MemoryCache
> memory_cache_
;
105 scoped_ptr
<FlipAcceptor
> acceptor_
;
106 scoped_ptr
<EpollServer
> epoll_server_
;
107 scoped_ptr
<MockSMConnection
> connection_
;
108 scoped_ptr
<HttpSM
> interface_
;
111 class FlipHttpSMProxyTest
: public FlipHttpSMTest
{
113 FlipHttpSMProxyTest() : FlipHttpSMTest(FLIP_HANDLER_PROXY
) {}
114 virtual ~FlipHttpSMProxyTest() {}
117 class FlipHttpSMHttpTest
: public FlipHttpSMTest
{
119 FlipHttpSMHttpTest() : FlipHttpSMTest(FLIP_HANDLER_HTTP_SERVER
) {}
120 virtual ~FlipHttpSMHttpTest() {}
123 class FlipHttpSMSpdyTest
: public FlipHttpSMTest
{
125 FlipHttpSMSpdyTest() : FlipHttpSMTest(FLIP_HANDLER_SPDY_SERVER
) {}
126 virtual ~FlipHttpSMSpdyTest() {}
129 TEST_F(FlipHttpSMTest
, Construct
) {
130 ASSERT_FALSE(interface_
->spdy_framer()->is_request());
133 TEST_F(FlipHttpSMTest
, AddToOutputOrder
) {
134 uint32 stream_id
= 13;
136 mci
.stream_id
= stream_id
;
139 BalsaHeaders headers
;
140 std::string filename
= "foobar";
141 memory_cache_
->InsertFile(&headers
, filename
, "");
142 mci
.file_data
= memory_cache_
->GetFileData(filename
);
145 interface_
->AddToOutputOrder(mci
);
146 ASSERT_TRUE(HasStream(stream_id
));
149 TEST_F(FlipHttpSMTest
, InitSMInterface
) {
150 scoped_ptr
<MockSMInterface
> mock(new MockSMInterface
);
153 EXPECT_CALL(*mock_another_interface_
, SendEOF(_
));
154 EXPECT_CALL(*mock_another_interface_
, ResetForNewInterface(_
));
155 EXPECT_CALL(*mock
, SendEOF(_
));
156 EXPECT_CALL(*mock
, ResetForNewInterface(_
));
159 interface_
->ResetForNewConnection();
160 interface_
->InitSMInterface(mock
.get(), 0);
161 interface_
->ResetForNewConnection();
164 TEST_F(FlipHttpSMTest
, InitSMConnection
) {
165 EXPECT_CALL(*connection_
, InitSMConnection(_
, _
, _
, _
, _
, _
, _
, _
));
167 interface_
->InitSMConnection(NULL
, NULL
, NULL
, 0, "", "", "", false);
170 TEST_F(FlipHttpSMTest
, ProcessReadInput
) {
172 "HTTP/1.1 200 OK\r\n"
173 "Content-Length: 14\r\n\r\n"
175 testing::MockFunction
<void(int)> checkpoint
; // NOLINT
178 EXPECT_CALL(*mock_another_interface_
, SendSynReply(_
, _
));
179 EXPECT_CALL(checkpoint
, Call(0));
180 EXPECT_CALL(*mock_another_interface_
, SendDataFrame(_
, _
, _
, _
, _
));
181 EXPECT_CALL(*mock_another_interface_
, SendEOF(_
));
184 ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE
,
185 interface_
->spdy_framer()->ParseState());
187 size_t read
= interface_
->ProcessReadInput(data
.data(), data
.size());
188 ASSERT_EQ(39u, read
);
190 read
+= interface_
->ProcessReadInput(&data
.data()[read
], data
.size() - read
);
191 ASSERT_EQ(data
.size(), read
);
192 ASSERT_EQ(BalsaFrameEnums::MESSAGE_FULLY_READ
,
193 interface_
->spdy_framer()->ParseState());
194 ASSERT_TRUE(interface_
->MessageFullyRead());
197 TEST_F(FlipHttpSMTest
, ProcessWriteInput
) {
198 std::string data
= "hello, world";
199 interface_
->ProcessWriteInput(data
.data(), data
.size());
201 ASSERT_EQ(1u, connection_
->output_list()->size());
202 std::list
<DataFrame
*>::const_iterator i
= connection_
->output_list()->begin();
203 DataFrame
* df
= *i
++;
204 ASSERT_EQ(data
, StringPiece(df
->data
, df
->size
));
205 ASSERT_EQ(connection_
->output_list()->end(), i
);
208 TEST_F(FlipHttpSMTest
, Reset
) {
209 std::string data
= "HTTP/1.1 200 OK\r\n\r\n";
210 testing::MockFunction
<void(int)> checkpoint
; // NOLINT
213 EXPECT_CALL(*mock_another_interface_
, SendSynReply(_
, _
));
214 EXPECT_CALL(checkpoint
, Call(0));
217 ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE
,
218 interface_
->spdy_framer()->ParseState());
220 interface_
->ProcessReadInput(data
.data(), data
.size());
222 ASSERT_FALSE(interface_
->MessageFullyRead());
223 ASSERT_EQ(BalsaFrameEnums::READING_UNTIL_CLOSE
,
224 interface_
->spdy_framer()->ParseState());
227 ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE
,
228 interface_
->spdy_framer()->ParseState());
231 TEST_F(FlipHttpSMTest
, ResetForNewConnection
) {
232 std::string data
= "HTTP/1.1 200 OK\r\n\r\n";
233 testing::MockFunction
<void(int)> checkpoint
; // NOLINT
236 EXPECT_CALL(*mock_another_interface_
, SendSynReply(_
, _
));
237 EXPECT_CALL(checkpoint
, Call(0));
238 EXPECT_CALL(*mock_another_interface_
, SendEOF(_
));
239 EXPECT_CALL(*mock_another_interface_
, ResetForNewInterface(_
));
242 ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE
,
243 interface_
->spdy_framer()->ParseState());
245 interface_
->ProcessReadInput(data
.data(), data
.size());
247 ASSERT_FALSE(interface_
->MessageFullyRead());
248 ASSERT_EQ(BalsaFrameEnums::READING_UNTIL_CLOSE
,
249 interface_
->spdy_framer()->ParseState());
251 interface_
->ResetForNewConnection();
252 ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE
,
253 interface_
->spdy_framer()->ParseState());
256 TEST_F(FlipHttpSMTest
, NewStream
) {
257 uint32 stream_id
= 4;
259 BalsaHeaders headers
;
260 std::string filename
= "foobar";
261 memory_cache_
->InsertFile(&headers
, filename
, "");
264 interface_
->NewStream(stream_id
, 1, "foobar");
265 ASSERT_TRUE(HasStream(stream_id
));
268 TEST_F(FlipHttpSMTest
, NewStreamError
) {
269 std::string syn_reply
=
270 "HTTP/1.1 404 Not Found\r\n"
271 "transfer-encoding: chunked\r\n\r\n";
272 std::string body
= "e\r\npage not found\r\n";
273 uint32 stream_id
= 4;
275 ASSERT_FALSE(HasStream(stream_id
));
276 interface_
->NewStream(stream_id
, 1, "foobar");
278 ASSERT_EQ(3u, connection_
->output_list()->size());
279 std::list
<DataFrame
*>::const_iterator i
= connection_
->output_list()->begin();
280 DataFrame
* df
= *i
++;
281 ASSERT_EQ(syn_reply
, StringPiece(df
->data
, df
->size
));
283 ASSERT_EQ(body
, StringPiece(df
->data
, df
->size
));
285 ASSERT_EQ("0\r\n\r\n", StringPiece(df
->data
, df
->size
));
286 ASSERT_FALSE(HasStream(stream_id
));
289 TEST_F(FlipHttpSMTest
, SendErrorNotFound
) {
290 std::string syn_reply
=
291 "HTTP/1.1 404 Not Found\r\n"
292 "transfer-encoding: chunked\r\n\r\n";
293 std::string body
= "e\r\npage not found\r\n";
294 uint32 stream_id
= 13;
296 mci
.stream_id
= stream_id
;
299 BalsaHeaders headers
;
300 std::string filename
= "foobar";
301 memory_cache_
->InsertFile(&headers
, filename
, "");
302 mci
.file_data
= memory_cache_
->GetFileData(filename
);
305 interface_
->AddToOutputOrder(mci
);
306 ASSERT_TRUE(HasStream(stream_id
));
307 interface_
->SendErrorNotFound(stream_id
);
309 ASSERT_EQ(3u, connection_
->output_list()->size());
310 std::list
<DataFrame
*>::const_iterator i
= connection_
->output_list()->begin();
311 DataFrame
* df
= *i
++;
312 ASSERT_EQ(syn_reply
, StringPiece(df
->data
, df
->size
));
314 ASSERT_EQ(body
, StringPiece(df
->data
, df
->size
));
316 ASSERT_EQ("0\r\n\r\n", StringPiece(df
->data
, df
->size
));
317 ASSERT_FALSE(HasStream(stream_id
));
320 TEST_F(FlipHttpSMTest
, SendSynStream
) {
321 std::string expected
=
323 "key1: value1\r\n\r\n";
324 BalsaHeaders headers
;
325 headers
.SetResponseFirstlineFromStringPieces("GET", "/path", "HTTP/1.0");
326 headers
.AppendHeader("key1", "value1");
327 interface_
->SendSynStream(18, headers
);
329 // TODO(yhirano): Is this behavior correct?
330 ASSERT_EQ(0u, connection_
->output_list()->size());
333 TEST_F(FlipHttpSMTest
, SendSynReply
) {
334 std::string expected
=
335 "HTTP/1.1 200 OK\r\n"
336 "key1: value1\r\n\r\n";
337 BalsaHeaders headers
;
338 headers
.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
339 headers
.AppendHeader("key1", "value1");
340 interface_
->SendSynReply(18, headers
);
342 ASSERT_EQ(1u, connection_
->output_list()->size());
343 DataFrame
* df
= connection_
->output_list()->front();
344 ASSERT_EQ(expected
, StringPiece(df
->data
, df
->size
));
347 TEST_F(FlipHttpSMTest
, SendDataFrame
) {
348 std::string data
= "foo bar baz";
349 interface_
->SendDataFrame(12, data
.data(), data
.size(), 0, false);
351 ASSERT_EQ(1u, connection_
->output_list()->size());
352 DataFrame
* df
= connection_
->output_list()->front();
353 ASSERT_EQ("b\r\nfoo bar baz\r\n", StringPiece(df
->data
, df
->size
));
356 TEST_F(FlipHttpSMProxyTest
, ProcessBodyData
) {
357 BalsaVisitorInterface
* visitor
= interface_
.get();
358 std::string data
= "hello, world";
361 EXPECT_CALL(*mock_another_interface_
,
362 SendDataFrame(0, data
.data(), data
.size(), 0, false));
364 visitor
->ProcessBodyData(data
.data(), data
.size());
368 // FlipHttpSMProxyTest
370 TEST_F(FlipHttpSMProxyTest
, ProcessHeaders
) {
371 BalsaVisitorInterface
* visitor
= interface_
.get();
374 EXPECT_CALL(*mock_another_interface_
, SendSynReply(0, _
));
376 BalsaHeaders headers
;
377 visitor
->ProcessHeaders(headers
);
380 TEST_F(FlipHttpSMProxyTest
, MessageDone
) {
381 BalsaVisitorInterface
* visitor
= interface_
.get();
384 EXPECT_CALL(*mock_another_interface_
, SendEOF(0));
386 visitor
->MessageDone();
389 TEST_F(FlipHttpSMProxyTest
, Cleanup
) {
390 EXPECT_CALL(*connection_
, Cleanup()).Times(0);
391 interface_
->Cleanup();
394 TEST_F(FlipHttpSMProxyTest
, SendEOF
) {
397 EXPECT_CALL(*mock_another_interface_
, ResetForNewInterface(_
));
399 interface_
->SendEOF(32);
400 ASSERT_EQ(1u, connection_
->output_list()->size());
401 DataFrame
* df
= connection_
->output_list()->front();
402 ASSERT_EQ("0\r\n\r\n", StringPiece(df
->data
, df
->size
));
406 // FlipHttpSMHttpTest
408 TEST_F(FlipHttpSMHttpTest
, ProcessHeaders
) {
409 BalsaVisitorInterface
* visitor
= interface_
.get();
411 BalsaHeaders headers
;
412 std::string filename
= "GET_/path/file";
413 memory_cache_
->InsertFile(&headers
, filename
, "");
416 BalsaHeaders headers
;
417 headers
.AppendHeader("Host", "example.com");
418 headers
.SetRequestFirstlineFromStringPieces("GET", "/path/file", "HTTP/1.0");
419 uint32 stream_id
= 133;
420 interface_
->SetStreamID(stream_id
);
421 ASSERT_FALSE(HasStream(stream_id
));
422 visitor
->ProcessHeaders(headers
);
423 ASSERT_TRUE(HasStream(stream_id
));
426 TEST_F(FlipHttpSMHttpTest
, MessageDone
) {
427 BalsaVisitorInterface
* visitor
= interface_
.get();
430 EXPECT_CALL(*mock_another_interface_
, SendEOF(0)).Times(0);
432 visitor
->MessageDone();
435 TEST_F(FlipHttpSMHttpTest
, Cleanup
) {
436 EXPECT_CALL(*connection_
, Cleanup()).Times(0);
437 interface_
->Cleanup();
440 TEST_F(FlipHttpSMHttpTest
, SendEOF
) {
443 EXPECT_CALL(*mock_another_interface_
, ResetForNewInterface(_
)).Times(0);
445 interface_
->SendEOF(32);
446 ASSERT_EQ(1u, connection_
->output_list()->size());
447 DataFrame
* df
= connection_
->output_list()->front();
448 ASSERT_EQ("0\r\n\r\n", StringPiece(df
->data
, df
->size
));
452 // FlipHttpSMSpdyTest
454 TEST_F(FlipHttpSMSpdyTest
, ProcessHeaders
) {
455 BalsaVisitorInterface
* visitor
= interface_
.get();
458 EXPECT_CALL(*mock_another_interface_
, SendSynReply(0, _
));
460 BalsaHeaders headers
;
461 visitor
->ProcessHeaders(headers
);
464 TEST_F(FlipHttpSMSpdyTest
, MessageDone
) {
465 BalsaVisitorInterface
* visitor
= interface_
.get();
468 EXPECT_CALL(*mock_another_interface_
, SendEOF(0)).Times(0);
470 visitor
->MessageDone();
473 TEST_F(FlipHttpSMSpdyTest
, Cleanup
) {
474 EXPECT_CALL(*connection_
, Cleanup()).Times(0);
475 interface_
->Cleanup();
478 TEST_F(FlipHttpSMSpdyTest
, SendEOF
) {
481 EXPECT_CALL(*mock_another_interface_
, ResetForNewInterface(_
)).Times(0);
483 interface_
->SendEOF(32);
484 ASSERT_EQ(1u, connection_
->output_list()->size());
485 DataFrame
* df
= connection_
->output_list()->front();
486 ASSERT_EQ("0\r\n\r\n", StringPiece(df
->data
, df
->size
));