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