Home | History | Annotate | Download | only in flip_server
      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.
      4 
      5 #include "net/tools/flip_server/http_interface.h"
      6 
      7 #include <list>
      8 
      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"
     20 
     21 namespace net {
     22 
     23 using ::base::StringPiece;
     24 using ::testing::_;
     25 using ::testing::InSequence;
     26 
     27 namespace {
     28 
     29 class MockSMConnection : public SMConnection {
     30  public:
     31   MockSMConnection(EpollServer* epoll_server,
     32                    SSLState* ssl_state,
     33                    MemoryCache* memory_cache,
     34                    FlipAcceptor* acceptor,
     35                    std::string log_prefix)
     36       : SMConnection(epoll_server,
     37                      ssl_state,
     38                      memory_cache,
     39                      acceptor,
     40                      log_prefix) {}
     41 
     42   MOCK_METHOD0(Cleanup, void());
     43   MOCK_METHOD8(InitSMConnection,
     44                void(SMConnectionPoolInterface*,
     45                     SMInterface*,
     46                     EpollServer*,
     47                     int,
     48                     std::string,
     49                     std::string,
     50                     std::string,
     51                     bool));
     52 };
     53 
     54 class FlipHttpSMTest : public ::testing::Test {
     55  public:
     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,
     61                                      "127.0.0.1",
     62                                      "8941",
     63                                      "ssl_cert_filename",
     64                                      "ssl_key_filename",
     65                                      "127.0.0.1",
     66                                      "8942",
     67                                      "127.0.0.1",
     68                                      "8943",
     69                                      1,
     70                                      0,
     71                                      true,
     72                                      1,
     73                                      false,
     74                                      true,
     75                                      NULL));
     76     epoll_server_.reset(new EpollServer);
     77     connection_.reset(new MockSMConnection(epoll_server_.get(),
     78                                            ssl_state,
     79                                            memory_cache_.get(),
     80                                            acceptor_.get(),
     81                                            "log_prefix"));
     82 
     83     interface_.reset(new HttpSM(connection_.get(),
     84                                 mock_another_interface_.get(),
     85                                 memory_cache_.get(),
     86                                 acceptor_.get()));
     87   }
     88 
     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;
     94     }
     95     STLDeleteElements(connection_->output_list());
     96   }
     97 
     98   bool HasStream(uint32 stream_id) {
     99     return interface_->output_ordering().ExistsInPriorityMaps(stream_id);
    100   }
    101 
    102  protected:
    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_;
    109 };
    110 
    111 class FlipHttpSMProxyTest : public FlipHttpSMTest {
    112  public:
    113   FlipHttpSMProxyTest() : FlipHttpSMTest(FLIP_HANDLER_PROXY) {}
    114   virtual ~FlipHttpSMProxyTest() {}
    115 };
    116 
    117 class FlipHttpSMHttpTest : public FlipHttpSMTest {
    118  public:
    119   FlipHttpSMHttpTest() : FlipHttpSMTest(FLIP_HANDLER_HTTP_SERVER) {}
    120   virtual ~FlipHttpSMHttpTest() {}
    121 };
    122 
    123 class FlipHttpSMSpdyTest : public FlipHttpSMTest {
    124  public:
    125   FlipHttpSMSpdyTest() : FlipHttpSMTest(FLIP_HANDLER_SPDY_SERVER) {}
    126   virtual ~FlipHttpSMSpdyTest() {}
    127 };
    128 
    129 TEST_F(FlipHttpSMTest, Construct) {
    130   ASSERT_FALSE(interface_->spdy_framer()->is_request());
    131 }
    132 
    133 TEST_F(FlipHttpSMTest, AddToOutputOrder) {
    134   uint32 stream_id = 13;
    135   MemCacheIter mci;
    136   mci.stream_id = stream_id;
    137 
    138   {
    139     BalsaHeaders headers;
    140     std::string filename = "foobar";
    141     memory_cache_->InsertFile(&headers, filename, "");
    142     mci.file_data = memory_cache_->GetFileData(filename);
    143   }
    144 
    145   interface_->AddToOutputOrder(mci);
    146   ASSERT_TRUE(HasStream(stream_id));
    147 }
    148 
    149 TEST_F(FlipHttpSMTest, InitSMInterface) {
    150   scoped_ptr<MockSMInterface> mock(new MockSMInterface);
    151   {
    152     InSequence s;
    153     EXPECT_CALL(*mock_another_interface_, SendEOF(_));
    154     EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_));
    155     EXPECT_CALL(*mock, SendEOF(_));
    156     EXPECT_CALL(*mock, ResetForNewInterface(_));
    157   }
    158 
    159   interface_->ResetForNewConnection();
    160   interface_->InitSMInterface(mock.get(), 0);
    161   interface_->ResetForNewConnection();
    162 }
    163 
    164 TEST_F(FlipHttpSMTest, InitSMConnection) {
    165   EXPECT_CALL(*connection_, InitSMConnection(_, _, _, _, _, _, _, _));
    166 
    167   interface_->InitSMConnection(NULL, NULL, NULL, 0, "", "", "", false);
    168 }
    169 
    170 TEST_F(FlipHttpSMTest, ProcessReadInput) {
    171   std::string data =
    172       "HTTP/1.1 200 OK\r\n"
    173       "Content-Length: 14\r\n\r\n"
    174       "hello, world\r\n";
    175   testing::MockFunction<void(int)> checkpoint;  // NOLINT
    176   {
    177     InSequence s;
    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(_));
    182   }
    183 
    184   ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
    185             interface_->spdy_framer()->ParseState());
    186 
    187   size_t read = interface_->ProcessReadInput(data.data(), data.size());
    188   ASSERT_EQ(39u, read);
    189   checkpoint.Call(0);
    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());
    195 }
    196 
    197 TEST_F(FlipHttpSMTest, ProcessWriteInput) {
    198   std::string data = "hello, world";
    199   interface_->ProcessWriteInput(data.data(), data.size());
    200 
    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);
    206 }
    207 
    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
    211   {
    212     InSequence s;
    213     EXPECT_CALL(*mock_another_interface_, SendSynReply(_, _));
    214     EXPECT_CALL(checkpoint, Call(0));
    215   }
    216 
    217   ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
    218             interface_->spdy_framer()->ParseState());
    219 
    220   interface_->ProcessReadInput(data.data(), data.size());
    221   checkpoint.Call(0);
    222   ASSERT_FALSE(interface_->MessageFullyRead());
    223   ASSERT_EQ(BalsaFrameEnums::READING_UNTIL_CLOSE,
    224             interface_->spdy_framer()->ParseState());
    225 
    226   interface_->Reset();
    227   ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
    228             interface_->spdy_framer()->ParseState());
    229 }
    230 
    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
    234   {
    235     InSequence s;
    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(_));
    240   }
    241 
    242   ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
    243             interface_->spdy_framer()->ParseState());
    244 
    245   interface_->ProcessReadInput(data.data(), data.size());
    246   checkpoint.Call(0);
    247   ASSERT_FALSE(interface_->MessageFullyRead());
    248   ASSERT_EQ(BalsaFrameEnums::READING_UNTIL_CLOSE,
    249             interface_->spdy_framer()->ParseState());
    250 
    251   interface_->ResetForNewConnection();
    252   ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
    253             interface_->spdy_framer()->ParseState());
    254 }
    255 
    256 TEST_F(FlipHttpSMTest, NewStream) {
    257   uint32 stream_id = 4;
    258   {
    259     BalsaHeaders headers;
    260     std::string filename = "foobar";
    261     memory_cache_->InsertFile(&headers, filename, "");
    262   }
    263 
    264   interface_->NewStream(stream_id, 1, "foobar");
    265   ASSERT_TRUE(HasStream(stream_id));
    266 }
    267 
    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;
    274 
    275   ASSERT_FALSE(HasStream(stream_id));
    276   interface_->NewStream(stream_id, 1, "foobar");
    277 
    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));
    282   df = *i++;
    283   ASSERT_EQ(body, StringPiece(df->data, df->size));
    284   df = *i++;
    285   ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
    286   ASSERT_FALSE(HasStream(stream_id));
    287 }
    288 
    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;
    295   MemCacheIter mci;
    296   mci.stream_id = stream_id;
    297 
    298   {
    299     BalsaHeaders headers;
    300     std::string filename = "foobar";
    301     memory_cache_->InsertFile(&headers, filename, "");
    302     mci.file_data = memory_cache_->GetFileData(filename);
    303   }
    304 
    305   interface_->AddToOutputOrder(mci);
    306   ASSERT_TRUE(HasStream(stream_id));
    307   interface_->SendErrorNotFound(stream_id);
    308 
    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));
    313   df = *i++;
    314   ASSERT_EQ(body, StringPiece(df->data, df->size));
    315   df = *i++;
    316   ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
    317   ASSERT_FALSE(HasStream(stream_id));
    318 }
    319 
    320 TEST_F(FlipHttpSMTest, SendSynStream) {
    321   std::string expected =
    322       "GET / HTTP/1.0\r\n"
    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);
    328 
    329   // TODO(yhirano): Is this behavior correct?
    330   ASSERT_EQ(0u, connection_->output_list()->size());
    331 }
    332 
    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);
    341 
    342   ASSERT_EQ(1u, connection_->output_list()->size());
    343   DataFrame* df = connection_->output_list()->front();
    344   ASSERT_EQ(expected, StringPiece(df->data, df->size));
    345 }
    346 
    347 TEST_F(FlipHttpSMTest, SendDataFrame) {
    348   std::string data = "foo bar baz";
    349   interface_->SendDataFrame(12, data.data(), data.size(), 0, false);
    350 
    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));
    354 }
    355 
    356 TEST_F(FlipHttpSMProxyTest, ProcessBodyData) {
    357   BalsaVisitorInterface* visitor = interface_.get();
    358   std::string data = "hello, world";
    359   {
    360     InSequence s;
    361     EXPECT_CALL(*mock_another_interface_,
    362                 SendDataFrame(0, data.data(), data.size(), 0, false));
    363   }
    364   visitor->ProcessBodyData(data.data(), data.size());
    365 }
    366 
    367 // --
    368 // FlipHttpSMProxyTest
    369 
    370 TEST_F(FlipHttpSMProxyTest, ProcessHeaders) {
    371   BalsaVisitorInterface* visitor = interface_.get();
    372   {
    373     InSequence s;
    374     EXPECT_CALL(*mock_another_interface_, SendSynReply(0, _));
    375   }
    376   BalsaHeaders headers;
    377   visitor->ProcessHeaders(headers);
    378 }
    379 
    380 TEST_F(FlipHttpSMProxyTest, MessageDone) {
    381   BalsaVisitorInterface* visitor = interface_.get();
    382   {
    383     InSequence s;
    384     EXPECT_CALL(*mock_another_interface_, SendEOF(0));
    385   }
    386   visitor->MessageDone();
    387 }
    388 
    389 TEST_F(FlipHttpSMProxyTest, Cleanup) {
    390   EXPECT_CALL(*connection_, Cleanup()).Times(0);
    391   interface_->Cleanup();
    392 }
    393 
    394 TEST_F(FlipHttpSMProxyTest, SendEOF) {
    395   {
    396     InSequence s;
    397     EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_));
    398   }
    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));
    403 }
    404 
    405 // --
    406 // FlipHttpSMHttpTest
    407 
    408 TEST_F(FlipHttpSMHttpTest, ProcessHeaders) {
    409   BalsaVisitorInterface* visitor = interface_.get();
    410   {
    411     BalsaHeaders headers;
    412     std::string filename = "GET_/path/file";
    413     memory_cache_->InsertFile(&headers, filename, "");
    414   }
    415 
    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));
    424 }
    425 
    426 TEST_F(FlipHttpSMHttpTest, MessageDone) {
    427   BalsaVisitorInterface* visitor = interface_.get();
    428   {
    429     InSequence s;
    430     EXPECT_CALL(*mock_another_interface_, SendEOF(0)).Times(0);
    431   }
    432   visitor->MessageDone();
    433 }
    434 
    435 TEST_F(FlipHttpSMHttpTest, Cleanup) {
    436   EXPECT_CALL(*connection_, Cleanup()).Times(0);
    437   interface_->Cleanup();
    438 }
    439 
    440 TEST_F(FlipHttpSMHttpTest, SendEOF) {
    441   {
    442     InSequence s;
    443     EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_)).Times(0);
    444   }
    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));
    449 }
    450 
    451 // --
    452 // FlipHttpSMSpdyTest
    453 
    454 TEST_F(FlipHttpSMSpdyTest, ProcessHeaders) {
    455   BalsaVisitorInterface* visitor = interface_.get();
    456   {
    457     InSequence s;
    458     EXPECT_CALL(*mock_another_interface_, SendSynReply(0, _));
    459   }
    460   BalsaHeaders headers;
    461   visitor->ProcessHeaders(headers);
    462 }
    463 
    464 TEST_F(FlipHttpSMSpdyTest, MessageDone) {
    465   BalsaVisitorInterface* visitor = interface_.get();
    466   {
    467     InSequence s;
    468     EXPECT_CALL(*mock_another_interface_, SendEOF(0)).Times(0);
    469   }
    470   visitor->MessageDone();
    471 }
    472 
    473 TEST_F(FlipHttpSMSpdyTest, Cleanup) {
    474   EXPECT_CALL(*connection_, Cleanup()).Times(0);
    475   interface_->Cleanup();
    476 }
    477 
    478 TEST_F(FlipHttpSMSpdyTest, SendEOF) {
    479   {
    480     InSequence s;
    481     EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_)).Times(0);
    482   }
    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));
    487 }
    488 
    489 }  // namespace
    490 
    491 }  // namespace net
    492