• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
StringSavernet::__anon72099feb0111::StringSaver34   StringSaver() : data(NULL), size(0) {}
Savenet::__anon72099feb0111::StringSaver35   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:
~SpdyFramerVisitor()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:
FakeSMConnection(EpollServer * epoll_server,SSLState * ssl_state,MemoryCache * memory_cache,FlipAcceptor * acceptor,std::string log_prefix)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:
~TestSpdySM()101   virtual ~TestSpdySM() {}
TestSpdySM(SMConnection * connection,SMInterface * sm_http_interface,EpollServer * epoll_server,MemoryCache * memory_cache,FlipAcceptor * acceptor,SpdyMajorVersion version)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:
SpdySMTestBase(FlipHandlerType type)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 
~SpdySMTestBase()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 
HasStream(uint32 stream_id)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:
SpdySMProxyTest()192   SpdySMProxyTest() : SpdySMTestBase(FLIP_HANDLER_PROXY) {}
~SpdySMProxyTest()193   virtual ~SpdySMProxyTest() {}
194 };
195 
196 class SpdySMServerTest : public SpdySMTestBase {
197  public:
SpdySMServerTest()198   SpdySMServerTest() : SpdySMTestBase(FLIP_HANDLER_SPDY_SERVER) {}
~SpdySMServerTest()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 
TEST_P(SpdySMProxyTest,InitSMConnection)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 
TEST_P(SpdySMProxyTest,OnSynStream_SPDY2)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 
TEST_P(SpdySMProxyTest,OnSynStream)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 
TEST_P(SpdySMProxyTest,OnStreamFrameData_SPDY2)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 
TEST_P(SpdySMProxyTest,OnStreamFrameData)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 
TEST_P(SpdySMProxyTest,OnRstStream)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 
TEST_P(SpdySMProxyTest,ProcessReadInput)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 
TEST_P(SpdySMProxyTest,ResetForNewConnection)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 
TEST_P(SpdySMProxyTest,CreateFramer)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 
TEST_P(SpdySMProxyTest,PostAcceptHook)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 
TEST_P(SpdySMProxyTest,NewStream)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 
TEST_P(SpdySMProxyTest,AddToOutputOrder)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 
TEST_P(SpdySMProxyTest,SendErrorNotFound_SPDY2)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 
TEST_P(SpdySMProxyTest,SendErrorNotFound)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 
TEST_P(SpdySMProxyTest,SendSynStream_SPDY2)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 
TEST_P(SpdySMProxyTest,SendSynStream)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 
TEST_P(SpdySMProxyTest,SendSynReply_SPDY2)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 
TEST_P(SpdySMProxyTest,SendSynReply)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 
TEST_P(SpdySMProxyTest,SendDataFrame)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 
TEST_P(SpdySMProxyTest,SendLongDataFrame)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 
TEST_P(SpdySMProxyTest,SendEOF_SPDY2)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 
TEST_P(SpdySMProxyTest,SendEmptyDataFrame_SPDY2)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 
TEST_P(SpdySMServerTest,OnSynStream)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 
TEST_P(SpdySMServerTest,NewStream)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 
TEST_P(SpdySMServerTest,NewStreamError)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