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