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
20namespace net {
21
22using ::base::StringPiece;
23using ::testing::_;
24using ::testing::InSequence;
25using ::testing::InvokeWithoutArgs;
26using ::testing::Return;
27using ::testing::SaveArg;
28using ::testing::Values;
29
30namespace {
31
32struct 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
42class 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
72class 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.
99class 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
119class 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
190class SpdySMProxyTest : public SpdySMTestBase {
191 public:
192  SpdySMProxyTest() : SpdySMTestBase(FLIP_HANDLER_PROXY) {}
193  virtual ~SpdySMProxyTest() {}
194};
195
196class SpdySMServerTest : public SpdySMTestBase {
197 public:
198  SpdySMServerTest() : SpdySMTestBase(FLIP_HANDLER_SPDY_SERVER) {}
199  virtual ~SpdySMServerTest() {}
200};
201
202INSTANTIATE_TEST_CASE_P(SpdySMProxyTest,
203                        SpdySMProxyTest,
204                        Values(SPDY2, SPDY3, SPDY4));
205INSTANTIATE_TEST_CASE_P(SpdySMServerTest, SpdySMServerTest, Values(SPDY2));
206
207TEST_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
216TEST_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
250TEST_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
285TEST_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
318TEST_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
353TEST_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
372TEST_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
379TEST_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
403TEST_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
415TEST_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
431TEST_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
437TEST_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
453TEST_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
502TEST_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
553TEST_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
586TEST_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
621TEST_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
657TEST_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
693TEST_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
719TEST_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
758TEST_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
789TEST_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
810TEST_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
827TEST_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
840TEST_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