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_METHOD6(OnSynStream,
     48                void(SpdyStreamId,
     49                     SpdyStreamId,
     50                     SpdyPriority,
     51                     bool,
     52                     bool,
     53                     const SpdyHeaderBlock&));
     54   MOCK_METHOD3(OnSynReply, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
     55   MOCK_METHOD3(OnHeaders, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
     56   MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId, size_t, bool));
     57   MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId,
     58                                        const char*,
     59                                        size_t,
     60                                        bool));
     61   MOCK_METHOD1(OnSettings, void(bool clear_persisted));
     62   MOCK_METHOD3(OnSetting, void(SpdySettingsIds, uint8, uint32));
     63   MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
     64   MOCK_METHOD2(OnRstStream, void(SpdyStreamId, SpdyRstStreamStatus));
     65   MOCK_METHOD2(OnGoAway, void(SpdyStreamId, SpdyGoAwayStatus));
     66   MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId, uint32));
     67   MOCK_METHOD3(OnPushPromise,
     68                void(SpdyStreamId, SpdyStreamId, const SpdyHeaderBlock&));
     69   MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
     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, 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, 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, false));
    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, 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, false));
    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, 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_TRUE(interface_->spdy_framer() == NULL);
    401 }
    402 
    403 TEST_P(SpdySMProxyTest, CreateFramer) {
    404   interface_->ResetForNewConnection();
    405   interface_->CreateFramer(SPDY2);
    406   ASSERT_TRUE(interface_->spdy_framer() != NULL);
    407   ASSERT_EQ(interface_->spdy_version(), SPDY2);
    408 
    409   interface_->ResetForNewConnection();
    410   interface_->CreateFramer(SPDY3);
    411   ASSERT_TRUE(interface_->spdy_framer() != NULL);
    412   ASSERT_EQ(interface_->spdy_version(), SPDY3);
    413 }
    414 
    415 TEST_P(SpdySMProxyTest, PostAcceptHook) {
    416   interface_->PostAcceptHook();
    417 
    418   ASSERT_EQ(1u, connection_->output_list()->size());
    419   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    420   DataFrame* df = *i++;
    421 
    422   {
    423     InSequence s;
    424     EXPECT_CALL(*spdy_framer_visitor_, OnSettings(false));
    425     EXPECT_CALL(*spdy_framer_visitor_,
    426                 OnSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 0u, 100u));
    427   }
    428   spdy_framer_->ProcessInput(df->data, df->size);
    429 }
    430 
    431 TEST_P(SpdySMProxyTest, NewStream) {
    432   // TODO(yhirano): SpdySM::NewStream leads to crash when
    433   // acceptor_->flip_handler_type_ != FLIP_HANDLER_SPDY_SERVER.
    434   // It should be fixed though I don't know the solution now.
    435 }
    436 
    437 TEST_P(SpdySMProxyTest, AddToOutputOrder) {
    438   uint32 stream_id = 13;
    439   MemCacheIter mci;
    440   mci.stream_id = stream_id;
    441 
    442   {
    443     BalsaHeaders headers;
    444     std::string filename = "foobar";
    445     memory_cache_->InsertFile(&headers, filename, "");
    446     mci.file_data = memory_cache_->GetFileData(filename);
    447   }
    448 
    449   interface_->AddToOutputOrder(mci);
    450   ASSERT_TRUE(HasStream(stream_id));
    451 }
    452 
    453 TEST_P(SpdySMProxyTest, SendErrorNotFound_SPDY2) {
    454   if (GetParam() != SPDY2) {
    455     // This test is for SPDY2.
    456     return;
    457   }
    458   uint32 stream_id = 82;
    459   SpdyHeaderBlock actual_header_block;
    460   const char* actual_data;
    461   size_t actual_size;
    462   testing::MockFunction<void(int)> checkpoint;  // NOLINT
    463 
    464   interface_->SendErrorNotFound(stream_id);
    465 
    466   ASSERT_EQ(2u, connection_->output_list()->size());
    467 
    468   {
    469     InSequence s;
    470     if (GetParam() < SPDY4) {
    471       EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
    472           .WillOnce(SaveArg<2>(&actual_header_block));
    473     } else {
    474       EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
    475           .WillOnce(SaveArg<2>(&actual_header_block));
    476     }
    477     EXPECT_CALL(checkpoint, Call(0));
    478     EXPECT_CALL(*spdy_framer_visitor_,
    479                 OnDataFrameHeader(stream_id, _, true));
    480     EXPECT_CALL(*spdy_framer_visitor_,
    481                 OnStreamFrameData(stream_id, _, _, false)).Times(1)
    482         .WillOnce(DoAll(SaveArg<1>(&actual_data),
    483                         SaveArg<2>(&actual_size)));
    484     EXPECT_CALL(*spdy_framer_visitor_,
    485                 OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
    486   }
    487 
    488   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    489   DataFrame* df = *i++;
    490   spdy_framer_->ProcessInput(df->data, df->size);
    491   checkpoint.Call(0);
    492   df = *i++;
    493   spdy_framer_->ProcessInput(df->data, df->size);
    494 
    495   ASSERT_EQ(2, spdy_framer_->frames_received());
    496   ASSERT_EQ(2u, actual_header_block.size());
    497   ASSERT_EQ("404 Not Found", actual_header_block["status"]);
    498   ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
    499   ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
    500 }
    501 
    502 TEST_P(SpdySMProxyTest, SendErrorNotFound) {
    503   if (GetParam() == SPDY2) {
    504     // This test is not for SPDY2.
    505     return;
    506   }
    507   uint32 stream_id = 82;
    508   SpdyHeaderBlock actual_header_block;
    509   const char* actual_data;
    510   size_t actual_size;
    511   testing::MockFunction<void(int)> checkpoint;  // NOLINT
    512 
    513   interface_->SendErrorNotFound(stream_id);
    514 
    515   ASSERT_EQ(2u, connection_->output_list()->size());
    516 
    517   {
    518     InSequence s;
    519     if (GetParam() < SPDY4) {
    520       EXPECT_CALL(*spdy_framer_visitor_,
    521                   OnSynReply(stream_id, false, _))
    522           .WillOnce(SaveArg<2>(&actual_header_block));
    523     } else {
    524       EXPECT_CALL(*spdy_framer_visitor_,
    525                   OnHeaders(stream_id, false, _))
    526           .WillOnce(SaveArg<2>(&actual_header_block));
    527     }
    528     EXPECT_CALL(checkpoint, Call(0));
    529     EXPECT_CALL(*spdy_framer_visitor_,
    530                 OnDataFrameHeader(stream_id, _, true));
    531     EXPECT_CALL(*spdy_framer_visitor_,
    532                 OnStreamFrameData(stream_id, _, _, false)).Times(1)
    533         .WillOnce(DoAll(SaveArg<1>(&actual_data),
    534                         SaveArg<2>(&actual_size)));
    535     EXPECT_CALL(*spdy_framer_visitor_,
    536                 OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
    537   }
    538 
    539   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    540   DataFrame* df = *i++;
    541   spdy_framer_->ProcessInput(df->data, df->size);
    542   checkpoint.Call(0);
    543   df = *i++;
    544   spdy_framer_->ProcessInput(df->data, df->size);
    545 
    546   ASSERT_EQ(2, spdy_framer_->frames_received());
    547   ASSERT_EQ(2u, actual_header_block.size());
    548   ASSERT_EQ("404 Not Found", actual_header_block[":status"]);
    549   ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
    550   ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
    551 }
    552 
    553 TEST_P(SpdySMProxyTest, SendSynStream_SPDY2) {
    554   if (GetParam() != SPDY2) {
    555     // This test is for SPDY2.
    556     return;
    557   }
    558   uint32 stream_id = 82;
    559   BalsaHeaders headers;
    560   SpdyHeaderBlock actual_header_block;
    561   headers.AppendHeader("key1", "value1");
    562   headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.0");
    563 
    564   interface_->SendSynStream(stream_id, headers);
    565 
    566   ASSERT_EQ(1u, connection_->output_list()->size());
    567   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    568   DataFrame* df = *i++;
    569 
    570   {
    571     InSequence s;
    572     EXPECT_CALL(*spdy_framer_visitor_,
    573                 OnSynStream(stream_id, 0, _, false, false, _))
    574         .WillOnce(SaveArg<5>(&actual_header_block));
    575   }
    576 
    577   spdy_framer_->ProcessInput(df->data, df->size);
    578   ASSERT_EQ(1, spdy_framer_->frames_received());
    579   ASSERT_EQ(4u, actual_header_block.size());
    580   ASSERT_EQ("GET", actual_header_block["method"]);
    581   ASSERT_EQ("HTTP/1.0", actual_header_block["version"]);
    582   ASSERT_EQ("/path", actual_header_block["url"]);
    583   ASSERT_EQ("value1", actual_header_block["key1"]);
    584 }
    585 
    586 TEST_P(SpdySMProxyTest, SendSynStream) {
    587   if (GetParam() == SPDY2) {
    588     // This test is not for SPDY2.
    589     return;
    590   }
    591   uint32 stream_id = 82;
    592   BalsaHeaders headers;
    593   SpdyHeaderBlock actual_header_block;
    594   headers.AppendHeader("key1", "value1");
    595   headers.AppendHeader("Host", "www.example.com");
    596   headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.1");
    597 
    598   interface_->SendSynStream(stream_id, headers);
    599 
    600   ASSERT_EQ(1u, connection_->output_list()->size());
    601   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    602   DataFrame* df = *i++;
    603 
    604   {
    605     InSequence s;
    606     EXPECT_CALL(*spdy_framer_visitor_,
    607                 OnSynStream(stream_id, 0, _, false, false, _))
    608         .WillOnce(SaveArg<5>(&actual_header_block));
    609   }
    610 
    611   spdy_framer_->ProcessInput(df->data, df->size);
    612   ASSERT_EQ(1, spdy_framer_->frames_received());
    613   ASSERT_EQ(5u, actual_header_block.size());
    614   ASSERT_EQ("GET", actual_header_block[":method"]);
    615   ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
    616   ASSERT_EQ("/path", actual_header_block[":path"]);
    617   ASSERT_EQ("www.example.com", actual_header_block[":host"]);
    618   ASSERT_EQ("value1", actual_header_block["key1"]);
    619 }
    620 
    621 TEST_P(SpdySMProxyTest, SendSynReply_SPDY2) {
    622   if (GetParam() != SPDY2) {
    623     // This test is for SPDY2.
    624     return;
    625   }
    626   uint32 stream_id = 82;
    627   BalsaHeaders headers;
    628   SpdyHeaderBlock actual_header_block;
    629   headers.AppendHeader("key1", "value1");
    630   headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
    631 
    632   interface_->SendSynReply(stream_id, headers);
    633 
    634   ASSERT_EQ(1u, connection_->output_list()->size());
    635   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    636   DataFrame* df = *i++;
    637 
    638   {
    639     InSequence s;
    640     if (GetParam() < SPDY4) {
    641       EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
    642           .WillOnce(SaveArg<2>(&actual_header_block));
    643     } else {
    644       EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
    645           .WillOnce(SaveArg<2>(&actual_header_block));
    646     }
    647   }
    648 
    649   spdy_framer_->ProcessInput(df->data, df->size);
    650   ASSERT_EQ(1, spdy_framer_->frames_received());
    651   ASSERT_EQ(3u, actual_header_block.size());
    652   ASSERT_EQ("200 OK", actual_header_block["status"]);
    653   ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
    654   ASSERT_EQ("value1", actual_header_block["key1"]);
    655 }
    656 
    657 TEST_P(SpdySMProxyTest, SendSynReply) {
    658   if (GetParam() == SPDY2) {
    659     // This test is not for SPDY2.
    660     return;
    661   }
    662   uint32 stream_id = 82;
    663   BalsaHeaders headers;
    664   SpdyHeaderBlock actual_header_block;
    665   headers.AppendHeader("key1", "value1");
    666   headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
    667 
    668   interface_->SendSynReply(stream_id, headers);
    669 
    670   ASSERT_EQ(1u, connection_->output_list()->size());
    671   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    672   DataFrame* df = *i++;
    673 
    674   {
    675     InSequence s;
    676     if (GetParam() < SPDY4) {
    677       EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
    678           .WillOnce(SaveArg<2>(&actual_header_block));
    679     } else {
    680       EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
    681           .WillOnce(SaveArg<2>(&actual_header_block));
    682     }
    683   }
    684 
    685   spdy_framer_->ProcessInput(df->data, df->size);
    686   ASSERT_EQ(1, spdy_framer_->frames_received());
    687   ASSERT_EQ(3u, actual_header_block.size());
    688   ASSERT_EQ("200 OK", actual_header_block[":status"]);
    689   ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
    690   ASSERT_EQ("value1", actual_header_block["key1"]);
    691 }
    692 
    693 TEST_P(SpdySMProxyTest, SendDataFrame) {
    694   uint32 stream_id = 133;
    695   SpdyDataFlags flags = DATA_FLAG_NONE;
    696   const char* actual_data;
    697   size_t actual_size;
    698 
    699   interface_->SendDataFrame(stream_id, "hello", 5, flags, true);
    700 
    701   ASSERT_EQ(1u, connection_->output_list()->size());
    702   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    703   DataFrame* df = *i++;
    704 
    705   {
    706     InSequence s;
    707     EXPECT_CALL(*spdy_framer_visitor_,
    708                 OnDataFrameHeader(stream_id, _, false));
    709     EXPECT_CALL(*spdy_framer_visitor_,
    710                 OnStreamFrameData(stream_id, _, _, false))
    711         .WillOnce(DoAll(SaveArg<1>(&actual_data), SaveArg<2>(&actual_size)));
    712   }
    713 
    714   spdy_framer_->ProcessInput(df->data, df->size);
    715   ASSERT_EQ(1, spdy_framer_->frames_received());
    716   ASSERT_EQ("hello", StringPiece(actual_data, actual_size));
    717 }
    718 
    719 TEST_P(SpdySMProxyTest, SendLongDataFrame) {
    720   uint32 stream_id = 133;
    721   SpdyDataFlags flags = DATA_FLAG_NONE;
    722   const char* actual_data;
    723   size_t actual_size;
    724 
    725   std::string data = std::string(kSpdySegmentSize, 'a') +
    726                      std::string(kSpdySegmentSize, 'b') + "c";
    727   interface_->SendDataFrame(stream_id, data.data(), data.size(), flags, true);
    728 
    729   {
    730     InSequence s;
    731     for (int i = 0; i < 3; ++i) {
    732         EXPECT_CALL(*spdy_framer_visitor_,
    733                     OnDataFrameHeader(stream_id, _, false));
    734         EXPECT_CALL(*spdy_framer_visitor_,
    735                     OnStreamFrameData(stream_id, _, _, false))
    736             .WillOnce(DoAll(SaveArg<1>(&actual_data),
    737                             SaveArg<2>(&actual_size)));
    738     }
    739   }
    740 
    741   ASSERT_EQ(3u, connection_->output_list()->size());
    742   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    743   DataFrame* df = *i++;
    744   spdy_framer_->ProcessInput(df->data, df->size);
    745   ASSERT_EQ(std::string(kSpdySegmentSize, 'a'),
    746             StringPiece(actual_data, actual_size));
    747 
    748   df = *i++;
    749   spdy_framer_->ProcessInput(df->data, df->size);
    750   ASSERT_EQ(std::string(kSpdySegmentSize, 'b'),
    751             StringPiece(actual_data, actual_size));
    752 
    753   df = *i++;
    754   spdy_framer_->ProcessInput(df->data, df->size);
    755   ASSERT_EQ("c", StringPiece(actual_data, actual_size));
    756 }
    757 
    758 TEST_P(SpdySMProxyTest, SendEOF_SPDY2) {
    759   // This test is for SPDY2.
    760   if (GetParam() != SPDY2) {
    761     return;
    762   }
    763 
    764   uint32 stream_id = 82;
    765   // SPDY2 data frame
    766   char empty_data_frame[] = {'\0', '\0', '\0', '\x52', '\x1', '\0', '\0', '\0'};
    767   MemCacheIter mci;
    768   mci.stream_id = stream_id;
    769 
    770   {
    771     BalsaHeaders headers;
    772     std::string filename = "foobar";
    773     memory_cache_->InsertFile(&headers, filename, "");
    774     mci.file_data = memory_cache_->GetFileData(filename);
    775   }
    776 
    777   interface_->AddToOutputOrder(mci);
    778   ASSERT_TRUE(HasStream(stream_id));
    779   interface_->SendEOF(stream_id);
    780   ASSERT_FALSE(HasStream(stream_id));
    781 
    782   ASSERT_EQ(1u, connection_->output_list()->size());
    783   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    784   DataFrame* df = *i++;
    785   ASSERT_EQ(StringPiece(empty_data_frame, sizeof(empty_data_frame)),
    786             StringPiece(df->data, df->size));
    787 }
    788 
    789 TEST_P(SpdySMProxyTest, SendEmptyDataFrame_SPDY2) {
    790   // This test is for SPDY2.
    791   if (GetParam() != SPDY2) {
    792     return;
    793   }
    794 
    795   uint32 stream_id = 133;
    796   SpdyDataFlags flags = DATA_FLAG_NONE;
    797   // SPDY2 data frame
    798   char expected[] = {'\0', '\0', '\0', '\x85', '\0', '\0', '\0', '\0'};
    799 
    800   interface_->SendDataFrame(stream_id, "hello", 0, flags, true);
    801 
    802   ASSERT_EQ(1u, connection_->output_list()->size());
    803   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    804   DataFrame* df = *i++;
    805 
    806   ASSERT_EQ(StringPiece(expected, sizeof(expected)),
    807             StringPiece(df->data, df->size));
    808 }
    809 
    810 TEST_P(SpdySMServerTest, OnSynStream) {
    811   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
    812   uint32 stream_id = 82;
    813   SpdyHeaderBlock spdy_headers;
    814   spdy_headers["url"] = "http://www.example.com/path";
    815   spdy_headers["method"] = "GET";
    816   spdy_headers["scheme"] = "http";
    817   spdy_headers["version"] = "HTTP/1.1";
    818 
    819   {
    820     BalsaHeaders headers;
    821     memory_cache_->InsertFile(&headers, "GET_/path", "");
    822   }
    823   visitor->OnSynStream(stream_id, 0, 0, true, true, spdy_headers);
    824   ASSERT_TRUE(HasStream(stream_id));
    825 }
    826 
    827 TEST_P(SpdySMServerTest, NewStream) {
    828   uint32 stream_id = 13;
    829   std::string filename = "foobar";
    830 
    831   {
    832     BalsaHeaders headers;
    833     memory_cache_->InsertFile(&headers, filename, "");
    834   }
    835 
    836   interface_->NewStream(stream_id, 0, filename);
    837   ASSERT_TRUE(HasStream(stream_id));
    838 }
    839 
    840 TEST_P(SpdySMServerTest, NewStreamError) {
    841   uint32 stream_id = 82;
    842   SpdyHeaderBlock actual_header_block;
    843   const char* actual_data;
    844   size_t actual_size;
    845   testing::MockFunction<void(int)> checkpoint;  // NOLINT
    846 
    847   interface_->NewStream(stream_id, 0, "nonexistingfile");
    848 
    849   ASSERT_EQ(2u, connection_->output_list()->size());
    850 
    851   {
    852     InSequence s;
    853     if (GetParam() < SPDY4) {
    854       EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
    855           .WillOnce(SaveArg<2>(&actual_header_block));
    856     } else {
    857       EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
    858           .WillOnce(SaveArg<2>(&actual_header_block));
    859     }
    860     EXPECT_CALL(checkpoint, Call(0));
    861     EXPECT_CALL(*spdy_framer_visitor_,
    862                 OnDataFrameHeader(stream_id, _, true));
    863     EXPECT_CALL(*spdy_framer_visitor_,
    864                 OnStreamFrameData(stream_id, _, _, false)).Times(1)
    865         .WillOnce(DoAll(SaveArg<1>(&actual_data),
    866                         SaveArg<2>(&actual_size)));
    867     EXPECT_CALL(*spdy_framer_visitor_,
    868                 OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
    869   }
    870 
    871   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
    872   DataFrame* df = *i++;
    873   spdy_framer_->ProcessInput(df->data, df->size);
    874   checkpoint.Call(0);
    875   df = *i++;
    876   spdy_framer_->ProcessInput(df->data, df->size);
    877 
    878   ASSERT_EQ(2, spdy_framer_->frames_received());
    879   ASSERT_EQ(2u, actual_header_block.size());
    880   ASSERT_EQ("404 Not Found", actual_header_block["status"]);
    881   ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
    882   ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
    883 }
    884 
    885 }  // namespace
    886 
    887 }  // namespace net
    888