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