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 MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type)); 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, 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, 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, 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 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 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_TRUE(interface_->spdy_framer() == NULL); 401 } 402 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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