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/spdy_interface.h"
      6 
      7 #include <list>
      8 
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/strings/string_piece.h"
     11 #include "net/spdy/buffered_spdy_framer.h"
     12 #include "net/tools/balsa/balsa_enums.h"
     13 #include "net/tools/balsa/balsa_headers.h"
     14 #include "net/tools/flip_server/flip_config.h"
     15 #include "net/tools/flip_server/flip_test_utils.h"
     16 #include "net/tools/flip_server/mem_cache.h"
     17 #include "testing/gmock/include/gmock/gmock.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 
     20 namespace net {
     21 
     22 using ::base::StringPiece;
     23 using ::testing::_;
     24 using ::testing::InSequence;
     25 using ::testing::InvokeWithoutArgs;
     26 using ::testing::Return;
     27 using ::testing::SaveArg;
     28 using ::testing::Values;
     29 
     30 namespace {
     31 
     32 struct StringSaver {
     33  public:
     34   StringSaver() : data(NULL), size(0) {}
     35   void Save() { string = std::string(data, size); }
     36 
     37   const char* data;
     38   size_t size;
     39   std::string string;
     40 };
     41 
     42 class SpdyFramerVisitor : public BufferedSpdyFramerVisitorInterface {
     43  public:
     44   virtual ~SpdyFramerVisitor() {}
     45   MOCK_METHOD1(OnError, void(SpdyFramer::SpdyError));
     46   MOCK_METHOD2(OnStreamError, void(SpdyStreamId, const std::string&));
     47   MOCK_METHOD7(OnSynStream,
     48                void(SpdyStreamId,
     49                     SpdyStreamId,
     50                     SpdyPriority,
     51                     uint8,
     52                     bool,
     53                     bool,
     54                     const SpdyHeaderBlock&));
     55   MOCK_METHOD3(OnSynStream, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
     56   MOCK_METHOD3(OnSynReply, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
     57   MOCK_METHOD3(OnHeaders, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
     58   MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId, size_t, bool));
     59   MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId,
     60                                        const char*,
     61                                        size_t,
     62                                        bool));
     63   MOCK_METHOD1(OnSettings, void(bool clear_persisted));
     64   MOCK_METHOD3(OnSetting, void(SpdySettingsIds, uint8, uint32));
     65   MOCK_METHOD1(OnPing, void(uint32 unique_id));
     66   MOCK_METHOD2(OnRstStream, void(SpdyStreamId, SpdyRstStreamStatus));
     67   MOCK_METHOD2(OnGoAway, void(SpdyStreamId, SpdyGoAwayStatus));
     68   MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId, uint32));
     69   MOCK_METHOD2(OnPushPromise, void(SpdyStreamId, SpdyStreamId));
     70 };
     71 
     72 class FakeSMConnection : public SMConnection {
     73  public:
     74   FakeSMConnection(EpollServer* epoll_server,
     75                    SSLState* ssl_state,
     76                    MemoryCache* memory_cache,
     77                    FlipAcceptor* acceptor,
     78                    std::string log_prefix)
     79       : SMConnection(epoll_server,
     80                      ssl_state,
     81                      memory_cache,
     82                      acceptor,
     83                      log_prefix) {}
     84 
     85   MOCK_METHOD0(Cleanup, void());
     86   MOCK_METHOD8(InitSMConnection,
     87                void(SMConnectionPoolInterface*,
     88                     SMInterface*,
     89                     EpollServer*,
     90                     int,
     91                     std::string,
     92                     std::string,
     93                     std::string,
     94                     bool));
     95 };
     96 
     97 // This class is almost SpdySM, except one function.
     98 // This class is the test target of tests in this file.
     99 class TestSpdySM : public SpdySM {
    100  public:
    101   virtual ~TestSpdySM() {}
    102   TestSpdySM(SMConnection* connection,
    103              SMInterface* sm_http_interface,
    104              EpollServer* epoll_server,
    105              MemoryCache* memory_cache,
    106              FlipAcceptor* acceptor,
    107              SpdyMajorVersion version)
    108       : SpdySM(connection,
    109                sm_http_interface,
    110                epoll_server,
    111                memory_cache,
    112                acceptor,
    113                version) {}
    114 
    115   MOCK_METHOD2(FindOrMakeNewSMConnectionInterface,
    116                SMInterface*(const std::string&, const std::string&));
    117 };
    118 
    119 class SpdySMTestBase : public ::testing::TestWithParam<SpdyMajorVersion> {
    120  public:
    121   explicit SpdySMTestBase(FlipHandlerType type) {
    122     SSLState* ssl_state = NULL;
    123     mock_another_interface_.reset(new MockSMInterface);
    124     memory_cache_.reset(new MemoryCache);
    125     acceptor_.reset(new FlipAcceptor(type,
    126                                      "127.0.0.1",
    127                                      "8941",
    128                                      "ssl_cert_filename",
    129                                      "ssl_key_filename",
    130                                      "127.0.0.1",
    131                                      "8942",
    132                                      "127.0.0.1",
    133                                      "8943",
    134                                      1,
    135                                      0,
    136                                      true,
    137                                      1,
    138                                      false,
    139                                      true,
    140                                      NULL));
    141     epoll_server_.reset(new EpollServer);
    142     connection_.reset(new FakeSMConnection(epoll_server_.get(),
    143                                            ssl_state,
    144                                            memory_cache_.get(),
    145                                            acceptor_.get(),
    146                                            "log_prefix"));
    147 
    148     interface_.reset(new TestSpdySM(connection_.get(),
    149                                     mock_another_interface_.get(),
    150                                     epoll_server_.get(),
    151                                     memory_cache_.get(),
    152                                     acceptor_.get(),
    153                                     GetParam()));
    154 
    155     spdy_framer_.reset(new BufferedSpdyFramer(GetParam(), true));
    156     spdy_framer_visitor_.reset(new SpdyFramerVisitor);
    157     spdy_framer_->set_visitor(spdy_framer_visitor_.get());
    158   }
    159 
    160   virtual ~SpdySMTestBase() {
    161     if (acceptor_->listen_fd_ >= 0) {
    162       epoll_server_->UnregisterFD(acceptor_->listen_fd_);
    163       close(acceptor_->listen_fd_);
    164       acceptor_->listen_fd_ = -1;
    165     }
    166     OutputList& output_list = *connection_->output_list();
    167     for (OutputList::const_iterator i = output_list.begin();
    168          i != output_list.end();
    169          ++i) {
    170       delete *i;
    171     }
    172     output_list.clear();
    173   }
    174 
    175   bool HasStream(uint32 stream_id) {
    176     return interface_->output_ordering().ExistsInPriorityMaps(stream_id);
    177   }
    178 
    179  protected:
    180   scoped_ptr<MockSMInterface> mock_another_interface_;
    181   scoped_ptr<MemoryCache> memory_cache_;
    182   scoped_ptr<FlipAcceptor> acceptor_;
    183   scoped_ptr<EpollServer> epoll_server_;
    184   scoped_ptr<FakeSMConnection> connection_;
    185   scoped_ptr<TestSpdySM> interface_;
    186   scoped_ptr<BufferedSpdyFramer> spdy_framer_;
    187   scoped_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
    188 };
    189 
    190 class SpdySMProxyTest : public SpdySMTestBase {
    191  public:
    192   SpdySMProxyTest() : SpdySMTestBase(FLIP_HANDLER_PROXY) {}
    193   virtual ~SpdySMProxyTest() {}
    194 };
    195 
    196 class SpdySMServerTest : public SpdySMTestBase {
    197  public:
    198   SpdySMServerTest() : SpdySMTestBase(FLIP_HANDLER_SPDY_SERVER) {}
    199   virtual ~SpdySMServerTest() {}
    200 };
    201 
    202 INSTANTIATE_TEST_CASE_P(SpdySMProxyTest,
    203                         SpdySMProxyTest,
    204                         Values(SPDY2, SPDY3, SPDY4));
    205 INSTANTIATE_TEST_CASE_P(SpdySMServerTest, SpdySMServerTest, Values(SPDY2));
    206 
    207 TEST_P(SpdySMProxyTest, InitSMConnection) {
    208   {
    209     InSequence s;
    210     EXPECT_CALL(*connection_, InitSMConnection(_, _, _, _, _, _, _, _));
    211   }
    212   interface_->InitSMConnection(
    213       NULL, NULL, epoll_server_.get(), -1, "", "", "", false);
    214 }
    215 
    216 TEST_P(SpdySMProxyTest, OnSynStream_SPDY2) {
    217   if (GetParam() != SPDY2) {
    218     // This test case is for SPDY2.
    219     return;
    220   }
    221   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
    222   scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
    223   uint32 stream_id = 92;
    224   uint32 associated_id = 43;
    225   std::string expected = "GET /path HTTP/1.0\r\n"
    226       "Host: 127.0.0.1\r\n"
    227       "hoge: fuga\r\n\r\n";
    228   SpdyHeaderBlock block;
    229   block["method"] = "GET";
    230   block["url"] = "/path";
    231   block["scheme"] = "http";
    232   block["version"] = "HTTP/1.0";
    233   block["hoge"] = "fuga";
    234   StringSaver saver;
    235   {
    236     InSequence s;
    237     EXPECT_CALL(*interface_, FindOrMakeNewSMConnectionInterface(_, _))
    238         .WillOnce(Return(mock_interface.get()));
    239     EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
    240     EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _))
    241         .WillOnce(DoAll(SaveArg<0>(&saver.data),
    242                         SaveArg<1>(&saver.size),
    243                         InvokeWithoutArgs(&saver, &StringSaver::Save),
    244                         Return(0)));
    245   }
    246   visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
    247   ASSERT_EQ(expected, saver.string);
    248 }
    249 
    250 TEST_P(SpdySMProxyTest, OnSynStream) {
    251   if (GetParam() == SPDY2) {
    252     // This test case is not for SPDY2.
    253     return;
    254   }
    255   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
    256   scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
    257   uint32 stream_id = 92;
    258   uint32 associated_id = 43;
    259   std::string expected = "GET /path HTTP/1.1\r\n"
    260       "Host: 127.0.0.1\r\n"
    261       "foo: bar\r\n\r\n";
    262   SpdyHeaderBlock block;
    263   block[":method"] = "GET";
    264   block[":host"] = "www.example.com";
    265   block[":path"] = "/path";
    266   block[":scheme"] = "http";
    267   block["foo"] = "bar";
    268   StringSaver saver;
    269   {
    270     InSequence s;
    271     EXPECT_CALL(*interface_,
    272                 FindOrMakeNewSMConnectionInterface(_, _))
    273         .WillOnce(Return(mock_interface.get()));
    274     EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
    275     EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _))
    276         .WillOnce(DoAll(SaveArg<0>(&saver.data),
    277                         SaveArg<1>(&saver.size),
    278                         InvokeWithoutArgs(&saver, &StringSaver::Save),
    279                         Return(0)));
    280   }
    281   visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
    282   ASSERT_EQ(expected, saver.string);
    283 }
    284 
    285 TEST_P(SpdySMProxyTest, OnStreamFrameData_SPDY2) {
    286   if (GetParam() != SPDY2) {
    287     // This test case is for SPDY2.
    288     return;
    289   }
    290   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
    291   scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
    292   uint32 stream_id = 92;
    293   uint32 associated_id = 43;
    294   SpdyHeaderBlock block;
    295   testing::MockFunction<void(int)> checkpoint;  // NOLINT
    296 
    297   scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12));
    298   block["method"] = "GET";
    299   block["url"] = "http://www.example.com/path";
    300   block["scheme"] = "http";
    301   block["version"] = "HTTP/1.0";
    302   {
    303     InSequence s;
    304     EXPECT_CALL(*interface_, FindOrMakeNewSMConnectionInterface(_, _))
    305         .WillOnce(Return(mock_interface.get()));
    306     EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
    307     EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)).Times(1);
    308     EXPECT_CALL(checkpoint, Call(0));
    309     EXPECT_CALL(*mock_interface,
    310                 ProcessWriteInput(frame->data(), frame->size())).Times(1);
    311   }
    312 
    313   visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
    314   checkpoint.Call(0);
    315   visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true);
    316 }
    317 
    318 TEST_P(SpdySMProxyTest, OnStreamFrameData) {
    319   if (GetParam() == SPDY2) {
    320     // This test case is not for SPDY2.
    321     return;
    322   }
    323   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
    324   scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
    325   uint32 stream_id = 92;
    326   uint32 associated_id = 43;
    327   SpdyHeaderBlock block;
    328   testing::MockFunction<void(int)> checkpoint;  // NOLINT
    329 
    330   scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12));
    331   block[":method"] = "GET";
    332   block[":host"] = "www.example.com";
    333   block[":path"] = "/path";
    334   block[":scheme"] = "http";
    335   block["foo"] = "bar";
    336   {
    337     InSequence s;
    338     EXPECT_CALL(*interface_,
    339                 FindOrMakeNewSMConnectionInterface(_, _))
    340         .WillOnce(Return(mock_interface.get()));
    341     EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
    342     EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)).Times(1);
    343     EXPECT_CALL(checkpoint, Call(0));
    344     EXPECT_CALL(*mock_interface,
    345                 ProcessWriteInput(frame->data(), frame->size())).Times(1);
    346   }
    347 
    348   visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
    349   checkpoint.Call(0);
    350   visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true);
    351 }
    352 
    353 TEST_P(SpdySMProxyTest, OnRstStream) {
    354   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
    355   uint32 stream_id = 82;
    356   MemCacheIter mci;
    357   mci.stream_id = stream_id;
    358 
    359   {
    360     BalsaHeaders headers;
    361     std::string filename = "foobar";
    362     memory_cache_->InsertFile(&headers, filename, "");
    363     mci.file_data = memory_cache_->GetFileData(filename);
    364   }
    365 
    366   interface_->AddToOutputOrder(mci);
    367   ASSERT_TRUE(HasStream(stream_id));
    368   visitor->OnRstStream(stream_id, RST_STREAM_INVALID);
    369   ASSERT_FALSE(HasStream(stream_id));
    370 }
    371 
    372 TEST_P(SpdySMProxyTest, ProcessReadInput) {
    373   ASSERT_EQ(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
    374   interface_->ProcessReadInput("", 1);
    375   ASSERT_EQ(SpdyFramer::SPDY_READING_COMMON_HEADER,
    376             interface_->spdy_framer()->state());
    377 }
    378 
    379 TEST_P(SpdySMProxyTest, ResetForNewConnection) {
    380   uint32 stream_id = 13;
    381   MemCacheIter mci;
    382   mci.stream_id = stream_id;
    383   // incomplete input
    384   const char input[] = {'\0', '\0', '\0'};
    385 
    386   {
    387     BalsaHeaders headers;
    388     std::string filename = "foobar";
    389     memory_cache_->InsertFile(&headers, filename, "");
    390     mci.file_data = memory_cache_->GetFileData(filename);
    391   }
    392 
    393   interface_->AddToOutputOrder(mci);
    394   ASSERT_TRUE(HasStream(stream_id));
    395   interface_->ProcessReadInput(input, sizeof(input));
    396   ASSERT_NE(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
    397 
    398   interface_->ResetForNewConnection();
    399   ASSERT_FALSE(HasStream(stream_id));
    400   ASSERT_EQ(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
    401 }
    402 
    403 TEST_P(SpdySMProxyTest, PostAcceptHook) {
    404   interface_->PostAcceptHook();
    405 
    406   ASSERT_EQ(1u, connection_->output_list()->size());
    407   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    408   DataFrame* df = *i++;
    409 
    410   {
    411     InSequence s;
    412     EXPECT_CALL(*spdy_framer_visitor_, OnSettings(false));
    413     EXPECT_CALL(*spdy_framer_visitor_,
    414                 OnSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 0u, 100u));
    415   }
    416   spdy_framer_->ProcessInput(df->data, df->size);
    417 }
    418 
    419 TEST_P(SpdySMProxyTest, NewStream) {
    420   // TODO(yhirano): SpdySM::NewStream leads to crash when
    421   // acceptor_->flip_handler_type_ != FLIP_HANDLER_SPDY_SERVER.
    422   // It should be fixed though I don't know the solution now.
    423 }
    424 
    425 TEST_P(SpdySMProxyTest, AddToOutputOrder) {
    426   uint32 stream_id = 13;
    427   MemCacheIter mci;
    428   mci.stream_id = stream_id;
    429 
    430   {
    431     BalsaHeaders headers;
    432     std::string filename = "foobar";
    433     memory_cache_->InsertFile(&headers, filename, "");
    434     mci.file_data = memory_cache_->GetFileData(filename);
    435   }
    436 
    437   interface_->AddToOutputOrder(mci);
    438   ASSERT_TRUE(HasStream(stream_id));
    439 }
    440 
    441 TEST_P(SpdySMProxyTest, SendErrorNotFound_SPDY2) {
    442   if (GetParam() != SPDY2) {
    443     // This test is for SPDY2.
    444     return;
    445   }
    446   uint32 stream_id = 82;
    447   SpdyHeaderBlock actual_header_block;
    448   const char* actual_data;
    449   size_t actual_size;
    450   testing::MockFunction<void(int)> checkpoint;  // NOLINT
    451 
    452   interface_->SendErrorNotFound(stream_id);
    453 
    454   ASSERT_EQ(2u, connection_->output_list()->size());
    455 
    456   {
    457     InSequence s;
    458     EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
    459         .WillOnce(SaveArg<2>(&actual_header_block));
    460     EXPECT_CALL(checkpoint, Call(0));
    461     EXPECT_CALL(*spdy_framer_visitor_,
    462                 OnDataFrameHeader(stream_id, _, true));
    463     EXPECT_CALL(*spdy_framer_visitor_,
    464                 OnStreamFrameData(stream_id, _, _, false)).Times(1)
    465         .WillOnce(DoAll(SaveArg<1>(&actual_data),
    466                         SaveArg<2>(&actual_size)));
    467     EXPECT_CALL(*spdy_framer_visitor_,
    468                 OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
    469   }
    470 
    471   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    472   DataFrame* df = *i++;
    473   spdy_framer_->ProcessInput(df->data, df->size);
    474   checkpoint.Call(0);
    475   df = *i++;
    476   spdy_framer_->ProcessInput(df->data, df->size);
    477 
    478   ASSERT_EQ(2, spdy_framer_->frames_received());
    479   ASSERT_EQ(2u, actual_header_block.size());
    480   ASSERT_EQ("404 Not Found", actual_header_block["status"]);
    481   ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
    482   ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
    483 }
    484 
    485 TEST_P(SpdySMProxyTest, SendErrorNotFound) {
    486   if (GetParam() == SPDY2) {
    487     // This test is not for SPDY2.
    488     return;
    489   }
    490   uint32 stream_id = 82;
    491   SpdyHeaderBlock actual_header_block;
    492   const char* actual_data;
    493   size_t actual_size;
    494   testing::MockFunction<void(int)> checkpoint;  // NOLINT
    495 
    496   interface_->SendErrorNotFound(stream_id);
    497 
    498   ASSERT_EQ(2u, connection_->output_list()->size());
    499 
    500   {
    501     InSequence s;
    502     EXPECT_CALL(*spdy_framer_visitor_,
    503                 OnSynReply(stream_id, false, _))
    504         .WillOnce(SaveArg<2>(&actual_header_block));
    505     EXPECT_CALL(checkpoint, Call(0));
    506     EXPECT_CALL(*spdy_framer_visitor_,
    507                 OnDataFrameHeader(stream_id, _, true));
    508     EXPECT_CALL(*spdy_framer_visitor_,
    509                 OnStreamFrameData(stream_id, _, _, false)).Times(1)
    510         .WillOnce(DoAll(SaveArg<1>(&actual_data),
    511                         SaveArg<2>(&actual_size)));
    512     EXPECT_CALL(*spdy_framer_visitor_,
    513                 OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
    514   }
    515 
    516   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    517   DataFrame* df = *i++;
    518   spdy_framer_->ProcessInput(df->data, df->size);
    519   checkpoint.Call(0);
    520   df = *i++;
    521   spdy_framer_->ProcessInput(df->data, df->size);
    522 
    523   ASSERT_EQ(2, spdy_framer_->frames_received());
    524   ASSERT_EQ(2u, actual_header_block.size());
    525   ASSERT_EQ("404 Not Found", actual_header_block[":status"]);
    526   ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
    527   ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
    528 }
    529 
    530 TEST_P(SpdySMProxyTest, SendSynStream_SPDY2) {
    531   if (GetParam() != SPDY2) {
    532     // This test is for SPDY2.
    533     return;
    534   }
    535   uint32 stream_id = 82;
    536   BalsaHeaders headers;
    537   SpdyHeaderBlock actual_header_block;
    538   headers.AppendHeader("key1", "value1");
    539   headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.0");
    540 
    541   interface_->SendSynStream(stream_id, headers);
    542 
    543   ASSERT_EQ(1u, connection_->output_list()->size());
    544   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    545   DataFrame* df = *i++;
    546 
    547   {
    548     InSequence s;
    549     EXPECT_CALL(*spdy_framer_visitor_,
    550                 OnSynStream(stream_id, 0, _, _, false, false, _))
    551         .WillOnce(SaveArg<6>(&actual_header_block));
    552   }
    553 
    554   spdy_framer_->ProcessInput(df->data, df->size);
    555   ASSERT_EQ(1, spdy_framer_->frames_received());
    556   ASSERT_EQ(4u, actual_header_block.size());
    557   ASSERT_EQ("GET", actual_header_block["method"]);
    558   ASSERT_EQ("HTTP/1.0", actual_header_block["version"]);
    559   ASSERT_EQ("/path", actual_header_block["url"]);
    560   ASSERT_EQ("value1", actual_header_block["key1"]);
    561 }
    562 
    563 TEST_P(SpdySMProxyTest, SendSynStream) {
    564   if (GetParam() == SPDY2) {
    565     // This test is not for SPDY2.
    566     return;
    567   }
    568   uint32 stream_id = 82;
    569   BalsaHeaders headers;
    570   SpdyHeaderBlock actual_header_block;
    571   headers.AppendHeader("key1", "value1");
    572   headers.AppendHeader("Host", "www.example.com");
    573   headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.1");
    574 
    575   interface_->SendSynStream(stream_id, headers);
    576 
    577   ASSERT_EQ(1u, connection_->output_list()->size());
    578   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    579   DataFrame* df = *i++;
    580 
    581   {
    582     InSequence s;
    583     EXPECT_CALL(*spdy_framer_visitor_,
    584                 OnSynStream(stream_id, 0, _, _, false, false, _))
    585         .WillOnce(SaveArg<6>(&actual_header_block));
    586   }
    587 
    588   spdy_framer_->ProcessInput(df->data, df->size);
    589   ASSERT_EQ(1, spdy_framer_->frames_received());
    590   ASSERT_EQ(5u, actual_header_block.size());
    591   ASSERT_EQ("GET", actual_header_block[":method"]);
    592   ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
    593   ASSERT_EQ("/path", actual_header_block[":path"]);
    594   ASSERT_EQ("www.example.com", actual_header_block[":host"]);
    595   ASSERT_EQ("value1", actual_header_block["key1"]);
    596 }
    597 
    598 TEST_P(SpdySMProxyTest, SendSynReply_SPDY2) {
    599   if (GetParam() != SPDY2) {
    600     // This test is for SPDY2.
    601     return;
    602   }
    603   uint32 stream_id = 82;
    604   BalsaHeaders headers;
    605   SpdyHeaderBlock actual_header_block;
    606   headers.AppendHeader("key1", "value1");
    607   headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
    608 
    609   interface_->SendSynReply(stream_id, headers);
    610 
    611   ASSERT_EQ(1u, connection_->output_list()->size());
    612   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    613   DataFrame* df = *i++;
    614 
    615   {
    616     InSequence s;
    617     EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
    618         .WillOnce(SaveArg<2>(&actual_header_block));
    619   }
    620 
    621   spdy_framer_->ProcessInput(df->data, df->size);
    622   ASSERT_EQ(1, spdy_framer_->frames_received());
    623   ASSERT_EQ(3u, actual_header_block.size());
    624   ASSERT_EQ("200 OK", actual_header_block["status"]);
    625   ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
    626   ASSERT_EQ("value1", actual_header_block["key1"]);
    627 }
    628 
    629 TEST_P(SpdySMProxyTest, SendSynReply) {
    630   if (GetParam() == SPDY2) {
    631     // This test is not for SPDY2.
    632     return;
    633   }
    634   uint32 stream_id = 82;
    635   BalsaHeaders headers;
    636   SpdyHeaderBlock actual_header_block;
    637   headers.AppendHeader("key1", "value1");
    638   headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
    639 
    640   interface_->SendSynReply(stream_id, headers);
    641 
    642   ASSERT_EQ(1u, connection_->output_list()->size());
    643   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    644   DataFrame* df = *i++;
    645 
    646   {
    647     InSequence s;
    648     EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
    649         .WillOnce(SaveArg<2>(&actual_header_block));
    650   }
    651 
    652   spdy_framer_->ProcessInput(df->data, df->size);
    653   ASSERT_EQ(1, spdy_framer_->frames_received());
    654   ASSERT_EQ(3u, actual_header_block.size());
    655   ASSERT_EQ("200 OK", actual_header_block[":status"]);
    656   ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
    657   ASSERT_EQ("value1", actual_header_block["key1"]);
    658 }
    659 
    660 TEST_P(SpdySMProxyTest, SendDataFrame) {
    661   uint32 stream_id = 133;
    662   SpdyDataFlags flags = DATA_FLAG_NONE;
    663   const char* actual_data;
    664   size_t actual_size;
    665 
    666   interface_->SendDataFrame(stream_id, "hello", 5, flags, true);
    667 
    668   ASSERT_EQ(1u, connection_->output_list()->size());
    669   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    670   DataFrame* df = *i++;
    671 
    672   {
    673     InSequence s;
    674     EXPECT_CALL(*spdy_framer_visitor_,
    675                 OnDataFrameHeader(stream_id, _, false));
    676     EXPECT_CALL(*spdy_framer_visitor_,
    677                 OnStreamFrameData(stream_id, _, _, false))
    678         .WillOnce(DoAll(SaveArg<1>(&actual_data), SaveArg<2>(&actual_size)));
    679   }
    680 
    681   spdy_framer_->ProcessInput(df->data, df->size);
    682   ASSERT_EQ(1, spdy_framer_->frames_received());
    683   ASSERT_EQ("hello", StringPiece(actual_data, actual_size));
    684 }
    685 
    686 TEST_P(SpdySMProxyTest, SendLongDataFrame) {
    687   uint32 stream_id = 133;
    688   SpdyDataFlags flags = DATA_FLAG_NONE;
    689   const char* actual_data;
    690   size_t actual_size;
    691 
    692   std::string data = std::string(kSpdySegmentSize, 'a') +
    693                      std::string(kSpdySegmentSize, 'b') + "c";
    694   interface_->SendDataFrame(stream_id, data.data(), data.size(), flags, true);
    695 
    696   {
    697     InSequence s;
    698     for (int i = 0; i < 3; ++i) {
    699         EXPECT_CALL(*spdy_framer_visitor_,
    700                     OnDataFrameHeader(stream_id, _, false));
    701         EXPECT_CALL(*spdy_framer_visitor_,
    702                     OnStreamFrameData(stream_id, _, _, false))
    703             .WillOnce(DoAll(SaveArg<1>(&actual_data),
    704                             SaveArg<2>(&actual_size)));
    705     }
    706   }
    707 
    708   ASSERT_EQ(3u, connection_->output_list()->size());
    709   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    710   DataFrame* df = *i++;
    711   spdy_framer_->ProcessInput(df->data, df->size);
    712   ASSERT_EQ(std::string(kSpdySegmentSize, 'a'),
    713             StringPiece(actual_data, actual_size));
    714 
    715   df = *i++;
    716   spdy_framer_->ProcessInput(df->data, df->size);
    717   ASSERT_EQ(std::string(kSpdySegmentSize, 'b'),
    718             StringPiece(actual_data, actual_size));
    719 
    720   df = *i++;
    721   spdy_framer_->ProcessInput(df->data, df->size);
    722   ASSERT_EQ("c", StringPiece(actual_data, actual_size));
    723 }
    724 
    725 TEST_P(SpdySMProxyTest, SendEOF_SPDY2) {
    726   // This test is for SPDY2.
    727   if (GetParam() != SPDY2) {
    728     return;
    729   }
    730 
    731   uint32 stream_id = 82;
    732   // SPDY2 data frame
    733   char empty_data_frame[] = {'\0', '\0', '\0', '\x52', '\x1', '\0', '\0', '\0'};
    734   MemCacheIter mci;
    735   mci.stream_id = stream_id;
    736 
    737   {
    738     BalsaHeaders headers;
    739     std::string filename = "foobar";
    740     memory_cache_->InsertFile(&headers, filename, "");
    741     mci.file_data = memory_cache_->GetFileData(filename);
    742   }
    743 
    744   interface_->AddToOutputOrder(mci);
    745   ASSERT_TRUE(HasStream(stream_id));
    746   interface_->SendEOF(stream_id);
    747   ASSERT_FALSE(HasStream(stream_id));
    748 
    749   ASSERT_EQ(1u, connection_->output_list()->size());
    750   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    751   DataFrame* df = *i++;
    752   ASSERT_EQ(StringPiece(empty_data_frame, sizeof(empty_data_frame)),
    753             StringPiece(df->data, df->size));
    754 }
    755 
    756 TEST_P(SpdySMProxyTest, SendEmptyDataFrame_SPDY2) {
    757   // This test is for SPDY2.
    758   if (GetParam() != SPDY2) {
    759     return;
    760   }
    761 
    762   uint32 stream_id = 133;
    763   SpdyDataFlags flags = DATA_FLAG_NONE;
    764   // SPDY2 data frame
    765   char expected[] = {'\0', '\0', '\0', '\x85', '\0', '\0', '\0', '\0'};
    766 
    767   interface_->SendDataFrame(stream_id, "hello", 0, flags, true);
    768 
    769   ASSERT_EQ(1u, connection_->output_list()->size());
    770   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    771   DataFrame* df = *i++;
    772 
    773   ASSERT_EQ(StringPiece(expected, sizeof(expected)),
    774             StringPiece(df->data, df->size));
    775 }
    776 
    777 TEST_P(SpdySMServerTest, OnSynStream) {
    778   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
    779   uint32 stream_id = 82;
    780   SpdyHeaderBlock spdy_headers;
    781   spdy_headers["url"] = "http://www.example.com/path";
    782   spdy_headers["method"] = "GET";
    783   spdy_headers["scheme"] = "http";
    784   spdy_headers["version"] = "HTTP/1.1";
    785 
    786   {
    787     BalsaHeaders headers;
    788     memory_cache_->InsertFile(&headers, "GET_/path", "");
    789   }
    790   visitor->OnSynStream(stream_id, 0, 0, 0, true, true, spdy_headers);
    791   ASSERT_TRUE(HasStream(stream_id));
    792 }
    793 
    794 TEST_P(SpdySMServerTest, NewStream) {
    795   uint32 stream_id = 13;
    796   std::string filename = "foobar";
    797 
    798   {
    799     BalsaHeaders headers;
    800     memory_cache_->InsertFile(&headers, filename, "");
    801   }
    802 
    803   interface_->NewStream(stream_id, 0, filename);
    804   ASSERT_TRUE(HasStream(stream_id));
    805 }
    806 
    807 TEST_P(SpdySMServerTest, NewStreamError) {
    808   uint32 stream_id = 82;
    809   SpdyHeaderBlock actual_header_block;
    810   const char* actual_data;
    811   size_t actual_size;
    812   testing::MockFunction<void(int)> checkpoint;  // NOLINT
    813 
    814   interface_->NewStream(stream_id, 0, "nonexistingfile");
    815 
    816   ASSERT_EQ(2u, connection_->output_list()->size());
    817 
    818   {
    819     InSequence s;
    820     EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
    821         .WillOnce(SaveArg<2>(&actual_header_block));
    822     EXPECT_CALL(checkpoint, Call(0));
    823     EXPECT_CALL(*spdy_framer_visitor_,
    824                 OnDataFrameHeader(stream_id, _, true));
    825     EXPECT_CALL(*spdy_framer_visitor_,
    826                 OnStreamFrameData(stream_id, _, _, false)).Times(1)
    827         .WillOnce(DoAll(SaveArg<1>(&actual_data),
    828                         SaveArg<2>(&actual_size)));
    829     EXPECT_CALL(*spdy_framer_visitor_,
    830                 OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
    831   }
    832 
    833   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    834   DataFrame* df = *i++;
    835   spdy_framer_->ProcessInput(df->data, df->size);
    836   checkpoint.Call(0);
    837   df = *i++;
    838   spdy_framer_->ProcessInput(df->data, df->size);
    839 
    840   ASSERT_EQ(2, spdy_framer_->frames_received());
    841   ASSERT_EQ(2u, actual_header_block.size());
    842   ASSERT_EQ("404 Not Found", actual_header_block["status"]);
    843   ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
    844   ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
    845 }
    846 
    847 }  // namespace
    848 
    849 }  // namespace net
    850