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 <cstddef> 6 #include <string> 7 #include <vector> 8 9 #include "base/memory/ref_counted.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/stl_util.h" 12 #include "base/strings/string_piece.h" 13 #include "net/base/completion_callback.h" 14 #include "net/base/net_log_unittest.h" 15 #include "net/base/request_priority.h" 16 #include "net/socket/next_proto.h" 17 #include "net/socket/socket_test_util.h" 18 #include "net/spdy/buffered_spdy_framer.h" 19 #include "net/spdy/spdy_http_utils.h" 20 #include "net/spdy/spdy_protocol.h" 21 #include "net/spdy/spdy_session.h" 22 #include "net/spdy/spdy_stream.h" 23 #include "net/spdy/spdy_stream_test_util.h" 24 #include "net/spdy/spdy_test_util_common.h" 25 #include "testing/gtest/include/gtest/gtest.h" 26 27 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc 28 // 29 namespace net { 30 31 namespace test { 32 33 namespace { 34 35 const char kStreamUrl[] = "http://www.google.com/"; 36 const char kPostBody[] = "\0hello!\xff"; 37 const size_t kPostBodyLength = arraysize(kPostBody); 38 const base::StringPiece kPostBodyStringPiece(kPostBody, kPostBodyLength); 39 40 class SpdyStreamTest : public ::testing::Test, 41 public ::testing::WithParamInterface<NextProto> { 42 protected: 43 // A function that takes a SpdyStream and the number of bytes which 44 // will unstall the next frame completely. 45 typedef base::Callback<void(const base::WeakPtr<SpdyStream>&, int32)> 46 UnstallFunction; 47 48 SpdyStreamTest() 49 : spdy_util_(GetParam()), 50 session_deps_(GetParam()), 51 offset_(0) {} 52 53 base::WeakPtr<SpdySession> CreateDefaultSpdySession() { 54 SpdySessionKey key(HostPortPair("www.google.com", 80), 55 ProxyServer::Direct(), 56 PRIVACY_MODE_DISABLED); 57 return CreateInsecureSpdySession(session_, key, BoundNetLog()); 58 } 59 60 virtual void TearDown() { 61 base::MessageLoop::current()->RunUntilIdle(); 62 } 63 64 void RunResumeAfterUnstallRequestResponseTest( 65 const UnstallFunction& unstall_function); 66 67 void RunResumeAfterUnstallBidirectionalTest( 68 const UnstallFunction& unstall_function); 69 70 // Add{Read,Write}() populates lists that are eventually passed to a 71 // SocketData class. |frame| must live for the whole test. 72 73 void AddRead(const SpdyFrame& frame) { 74 reads_.push_back(CreateMockRead(frame, offset_++)); 75 } 76 77 void AddWrite(const SpdyFrame& frame) { 78 writes_.push_back(CreateMockWrite(frame, offset_++)); 79 } 80 81 void AddReadEOF() { 82 reads_.push_back(MockRead(ASYNC, 0, offset_++)); 83 } 84 85 MockRead* GetReads() { 86 return vector_as_array(&reads_); 87 } 88 89 size_t GetNumReads() const { 90 return reads_.size(); 91 } 92 93 MockWrite* GetWrites() { 94 return vector_as_array(&writes_); 95 } 96 97 int GetNumWrites() const { 98 return writes_.size(); 99 } 100 101 SpdyTestUtil spdy_util_; 102 SpdySessionDependencies session_deps_; 103 scoped_refptr<HttpNetworkSession> session_; 104 105 private: 106 // Used by Add{Read,Write}() above. 107 std::vector<MockWrite> writes_; 108 std::vector<MockRead> reads_; 109 int offset_; 110 }; 111 112 INSTANTIATE_TEST_CASE_P( 113 NextProto, 114 SpdyStreamTest, 115 testing::Values(kProtoDeprecatedSPDY2, 116 kProtoSPDY3, kProtoSPDY31, kProtoSPDY4)); 117 118 TEST_P(SpdyStreamTest, SendDataAfterOpen) { 119 GURL url(kStreamUrl); 120 121 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); 122 123 scoped_ptr<SpdyFrame> req( 124 spdy_util_.ConstructSpdyPost( 125 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0)); 126 AddWrite(*req); 127 128 scoped_ptr<SpdyFrame> resp( 129 spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); 130 AddRead(*resp); 131 132 scoped_ptr<SpdyFrame> msg( 133 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false)); 134 AddWrite(*msg); 135 136 scoped_ptr<SpdyFrame> echo( 137 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false)); 138 AddRead(*echo); 139 140 AddReadEOF(); 141 142 OrderedSocketData data(GetReads(), GetNumReads(), 143 GetWrites(), GetNumWrites()); 144 MockConnect connect_data(SYNCHRONOUS, OK); 145 data.set_connect_data(connect_data); 146 147 session_deps_.socket_factory->AddSocketDataProvider(&data); 148 149 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 150 151 base::WeakPtr<SpdyStream> stream = 152 CreateStreamSynchronously( 153 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog()); 154 ASSERT_TRUE(stream.get() != NULL); 155 156 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); 157 stream->SetDelegate(&delegate); 158 159 EXPECT_FALSE(stream->HasUrlFromHeaders()); 160 161 scoped_ptr<SpdyHeaderBlock> headers( 162 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)); 163 EXPECT_EQ(ERR_IO_PENDING, 164 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); 165 EXPECT_TRUE(stream->HasUrlFromHeaders()); 166 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 167 168 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); 169 170 EXPECT_TRUE(delegate.send_headers_completed()); 171 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); 172 EXPECT_EQ(std::string(kPostBody, kPostBodyLength), 173 delegate.TakeReceivedData()); 174 EXPECT_TRUE(data.at_write_eof()); 175 } 176 177 TEST_P(SpdyStreamTest, PushedStream) { 178 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); 179 180 AddReadEOF(); 181 182 OrderedSocketData data(GetReads(), GetNumReads(), 183 GetWrites(), GetNumWrites()); 184 MockConnect connect_data(SYNCHRONOUS, OK); 185 data.set_connect_data(connect_data); 186 187 session_deps_.socket_factory->AddSocketDataProvider(&data); 188 189 base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession()); 190 191 // Conjure up a stream. 192 SpdyStream stream(SPDY_PUSH_STREAM, 193 spdy_session, 194 GURL(), 195 DEFAULT_PRIORITY, 196 kSpdyStreamInitialWindowSize, 197 kSpdyStreamInitialWindowSize, 198 BoundNetLog()); 199 stream.set_stream_id(2); 200 EXPECT_FALSE(stream.HasUrlFromHeaders()); 201 202 // Set required request headers. 203 SpdyHeaderBlock request_headers; 204 spdy_util_.AddUrlToHeaderBlock(kStreamUrl, &request_headers); 205 stream.OnPushPromiseHeadersReceived(request_headers); 206 207 // Send some basic response headers. 208 SpdyHeaderBlock response; 209 response[spdy_util_.GetStatusKey()] = "200"; 210 response[spdy_util_.GetVersionKey()] = "OK"; 211 stream.OnInitialResponseHeadersReceived( 212 response, base::Time::Now(), base::TimeTicks::Now()); 213 214 // And some more headers. 215 // TODO(baranovich): not valid for HTTP 2. 216 SpdyHeaderBlock headers; 217 headers["alpha"] = "beta"; 218 stream.OnAdditionalResponseHeadersReceived(headers); 219 220 EXPECT_TRUE(stream.HasUrlFromHeaders()); 221 EXPECT_EQ(kStreamUrl, stream.GetUrlFromHeaders().spec()); 222 223 StreamDelegateDoNothing delegate(stream.GetWeakPtr()); 224 stream.SetDelegate(&delegate); 225 226 base::MessageLoop::current()->RunUntilIdle(); 227 228 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); 229 EXPECT_EQ("beta", delegate.GetResponseHeaderValue("alpha")); 230 231 EXPECT_TRUE(spdy_session == NULL); 232 } 233 234 TEST_P(SpdyStreamTest, StreamError) { 235 GURL url(kStreamUrl); 236 237 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); 238 239 scoped_ptr<SpdyFrame> req( 240 spdy_util_.ConstructSpdyPost( 241 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0)); 242 AddWrite(*req); 243 244 scoped_ptr<SpdyFrame> resp( 245 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); 246 AddRead(*resp); 247 248 scoped_ptr<SpdyFrame> msg( 249 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false)); 250 AddWrite(*msg); 251 252 scoped_ptr<SpdyFrame> echo( 253 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false)); 254 AddRead(*echo); 255 256 AddReadEOF(); 257 258 CapturingBoundNetLog log; 259 260 OrderedSocketData data(GetReads(), GetNumReads(), 261 GetWrites(), GetNumWrites()); 262 MockConnect connect_data(SYNCHRONOUS, OK); 263 data.set_connect_data(connect_data); 264 265 session_deps_.socket_factory->AddSocketDataProvider(&data); 266 267 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 268 269 base::WeakPtr<SpdyStream> stream = 270 CreateStreamSynchronously( 271 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound()); 272 ASSERT_TRUE(stream.get() != NULL); 273 274 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); 275 stream->SetDelegate(&delegate); 276 277 EXPECT_FALSE(stream->HasUrlFromHeaders()); 278 279 scoped_ptr<SpdyHeaderBlock> headers( 280 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)); 281 EXPECT_EQ(ERR_IO_PENDING, 282 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); 283 EXPECT_TRUE(stream->HasUrlFromHeaders()); 284 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 285 286 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); 287 288 const SpdyStreamId stream_id = delegate.stream_id(); 289 290 EXPECT_TRUE(delegate.send_headers_completed()); 291 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); 292 EXPECT_EQ(std::string(kPostBody, kPostBodyLength), 293 delegate.TakeReceivedData()); 294 EXPECT_TRUE(data.at_write_eof()); 295 296 // Check that the NetLog was filled reasonably. 297 net::CapturingNetLog::CapturedEntryList entries; 298 log.GetEntries(&entries); 299 EXPECT_LT(0u, entries.size()); 300 301 // Check that we logged SPDY_STREAM_ERROR correctly. 302 int pos = net::ExpectLogContainsSomewhere( 303 entries, 0, 304 net::NetLog::TYPE_SPDY_STREAM_ERROR, 305 net::NetLog::PHASE_NONE); 306 307 int stream_id2; 308 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2)); 309 EXPECT_EQ(static_cast<int>(stream_id), stream_id2); 310 } 311 312 // Make sure that large blocks of data are properly split up into 313 // frame-sized chunks for a request/response (i.e., an HTTP-like) 314 // stream. 315 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) { 316 GURL url(kStreamUrl); 317 318 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); 319 320 scoped_ptr<SpdyFrame> req( 321 spdy_util_.ConstructSpdyPost( 322 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0)); 323 AddWrite(*req); 324 325 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x'); 326 scoped_ptr<SpdyFrame> chunk( 327 spdy_util_.ConstructSpdyBodyFrame( 328 1, chunk_data.data(), chunk_data.length(), false)); 329 AddWrite(*chunk); 330 AddWrite(*chunk); 331 332 scoped_ptr<SpdyFrame> last_chunk( 333 spdy_util_.ConstructSpdyBodyFrame( 334 1, chunk_data.data(), chunk_data.length(), true)); 335 AddWrite(*last_chunk); 336 337 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); 338 AddRead(*resp); 339 340 AddReadEOF(); 341 342 OrderedSocketData data(GetReads(), GetNumReads(), 343 GetWrites(), GetNumWrites()); 344 MockConnect connect_data(SYNCHRONOUS, OK); 345 data.set_connect_data(connect_data); 346 347 session_deps_.socket_factory->AddSocketDataProvider(&data); 348 349 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 350 351 base::WeakPtr<SpdyStream> stream = 352 CreateStreamSynchronously( 353 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog()); 354 ASSERT_TRUE(stream.get() != NULL); 355 356 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x'); 357 StreamDelegateWithBody delegate(stream, body_data); 358 stream->SetDelegate(&delegate); 359 360 EXPECT_FALSE(stream->HasUrlFromHeaders()); 361 362 scoped_ptr<SpdyHeaderBlock> headers( 363 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)); 364 EXPECT_EQ(ERR_IO_PENDING, 365 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); 366 EXPECT_TRUE(stream->HasUrlFromHeaders()); 367 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 368 369 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); 370 371 EXPECT_TRUE(delegate.send_headers_completed()); 372 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); 373 EXPECT_EQ(std::string(), delegate.TakeReceivedData()); 374 EXPECT_TRUE(data.at_write_eof()); 375 } 376 377 // Make sure that large blocks of data are properly split up into 378 // frame-sized chunks for a bidirectional (i.e., non-HTTP-like) 379 // stream. 380 TEST_P(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) { 381 GURL url(kStreamUrl); 382 383 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); 384 385 scoped_ptr<SpdyFrame> req( 386 spdy_util_.ConstructSpdyPost( 387 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0)); 388 AddWrite(*req); 389 390 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); 391 AddRead(*resp); 392 393 std::string chunk_data(kMaxSpdyFrameChunkSize, 'x'); 394 scoped_ptr<SpdyFrame> chunk( 395 spdy_util_.ConstructSpdyBodyFrame( 396 1, chunk_data.data(), chunk_data.length(), false)); 397 AddWrite(*chunk); 398 AddWrite(*chunk); 399 AddWrite(*chunk); 400 401 AddReadEOF(); 402 403 OrderedSocketData data(GetReads(), GetNumReads(), 404 GetWrites(), GetNumWrites()); 405 MockConnect connect_data(SYNCHRONOUS, OK); 406 data.set_connect_data(connect_data); 407 408 session_deps_.socket_factory->AddSocketDataProvider(&data); 409 410 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 411 412 base::WeakPtr<SpdyStream> stream = 413 CreateStreamSynchronously( 414 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog()); 415 ASSERT_TRUE(stream.get() != NULL); 416 417 std::string body_data(3 * kMaxSpdyFrameChunkSize, 'x'); 418 StreamDelegateSendImmediate delegate(stream, body_data); 419 stream->SetDelegate(&delegate); 420 421 EXPECT_FALSE(stream->HasUrlFromHeaders()); 422 423 scoped_ptr<SpdyHeaderBlock> headers( 424 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)); 425 EXPECT_EQ(ERR_IO_PENDING, 426 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); 427 EXPECT_TRUE(stream->HasUrlFromHeaders()); 428 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 429 430 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); 431 432 EXPECT_TRUE(delegate.send_headers_completed()); 433 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); 434 EXPECT_EQ(std::string(), delegate.TakeReceivedData()); 435 EXPECT_TRUE(data.at_write_eof()); 436 } 437 438 // Receiving a header with uppercase ASCII should result in a protocol 439 // error. 440 TEST_P(SpdyStreamTest, UpperCaseHeaders) { 441 GURL url(kStreamUrl); 442 443 session_ = 444 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); 445 446 scoped_ptr<SpdyFrame> syn( 447 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); 448 AddWrite(*syn); 449 450 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"}; 451 scoped_ptr<SpdyFrame> 452 reply(spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1)); 453 AddRead(*reply); 454 455 scoped_ptr<SpdyFrame> rst( 456 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); 457 AddWrite(*rst); 458 459 AddReadEOF(); 460 461 DeterministicSocketData data(GetReads(), GetNumReads(), 462 GetWrites(), GetNumWrites()); 463 MockConnect connect_data(SYNCHRONOUS, OK); 464 data.set_connect_data(connect_data); 465 466 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); 467 468 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 469 470 base::WeakPtr<SpdyStream> stream = 471 CreateStreamSynchronously( 472 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog()); 473 ASSERT_TRUE(stream.get() != NULL); 474 475 StreamDelegateDoNothing delegate(stream); 476 stream->SetDelegate(&delegate); 477 478 EXPECT_FALSE(stream->HasUrlFromHeaders()); 479 480 scoped_ptr<SpdyHeaderBlock> headers( 481 spdy_util_.ConstructGetHeaderBlock(kStreamUrl)); 482 EXPECT_EQ(ERR_IO_PENDING, 483 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND)); 484 EXPECT_TRUE(stream->HasUrlFromHeaders()); 485 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 486 487 data.RunFor(4); 488 489 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose()); 490 } 491 492 // Receiving a header with uppercase ASCII should result in a protocol 493 // error even for a push stream. 494 TEST_P(SpdyStreamTest, UpperCaseHeadersOnPush) { 495 GURL url(kStreamUrl); 496 497 session_ = 498 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); 499 500 scoped_ptr<SpdyFrame> syn( 501 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); 502 AddWrite(*syn); 503 504 scoped_ptr<SpdyFrame> 505 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); 506 AddRead(*reply); 507 508 const char* const extra_headers[] = {"X-UpperCase", "yes"}; 509 scoped_ptr<SpdyFrame> 510 push(spdy_util_.ConstructSpdyPush(extra_headers, 1, 2, 1, kStreamUrl)); 511 AddRead(*push); 512 513 scoped_ptr<SpdyFrame> rst( 514 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR)); 515 AddWrite(*rst); 516 517 AddReadEOF(); 518 519 DeterministicSocketData data(GetReads(), GetNumReads(), 520 GetWrites(), GetNumWrites()); 521 MockConnect connect_data(SYNCHRONOUS, OK); 522 data.set_connect_data(connect_data); 523 524 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); 525 526 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 527 528 base::WeakPtr<SpdyStream> stream = 529 CreateStreamSynchronously( 530 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog()); 531 ASSERT_TRUE(stream.get() != NULL); 532 533 StreamDelegateDoNothing delegate(stream); 534 stream->SetDelegate(&delegate); 535 536 EXPECT_FALSE(stream->HasUrlFromHeaders()); 537 538 scoped_ptr<SpdyHeaderBlock> headers( 539 spdy_util_.ConstructGetHeaderBlock(kStreamUrl)); 540 EXPECT_EQ(ERR_IO_PENDING, 541 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND)); 542 EXPECT_TRUE(stream->HasUrlFromHeaders()); 543 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 544 545 data.RunFor(4); 546 547 base::WeakPtr<SpdyStream> push_stream; 548 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog())); 549 EXPECT_FALSE(push_stream); 550 551 data.RunFor(1); 552 553 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); 554 } 555 556 // Receiving a header with uppercase ASCII in a HEADERS frame should 557 // result in a protocol error. 558 TEST_P(SpdyStreamTest, UpperCaseHeadersInHeadersFrame) { 559 GURL url(kStreamUrl); 560 561 session_ = 562 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); 563 564 scoped_ptr<SpdyFrame> syn( 565 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); 566 AddWrite(*syn); 567 568 scoped_ptr<SpdyFrame> 569 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); 570 AddRead(*reply); 571 572 scoped_ptr<SpdyFrame> 573 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl)); 574 AddRead(*push); 575 576 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock()); 577 (*late_headers)["X-UpperCase"] = "yes"; 578 scoped_ptr<SpdyFrame> headers_frame( 579 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(), 580 false, 581 2, 582 LOWEST, 583 HEADERS, 584 CONTROL_FLAG_NONE, 585 0)); 586 AddRead(*headers_frame); 587 588 scoped_ptr<SpdyFrame> rst( 589 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR)); 590 AddWrite(*rst); 591 592 AddReadEOF(); 593 594 DeterministicSocketData data(GetReads(), GetNumReads(), 595 GetWrites(), GetNumWrites()); 596 MockConnect connect_data(SYNCHRONOUS, OK); 597 data.set_connect_data(connect_data); 598 599 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); 600 601 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 602 603 base::WeakPtr<SpdyStream> stream = 604 CreateStreamSynchronously( 605 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog()); 606 ASSERT_TRUE(stream.get() != NULL); 607 608 StreamDelegateDoNothing delegate(stream); 609 stream->SetDelegate(&delegate); 610 611 EXPECT_FALSE(stream->HasUrlFromHeaders()); 612 613 scoped_ptr<SpdyHeaderBlock> headers( 614 spdy_util_.ConstructGetHeaderBlock(kStreamUrl)); 615 EXPECT_EQ(ERR_IO_PENDING, 616 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND)); 617 EXPECT_TRUE(stream->HasUrlFromHeaders()); 618 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 619 620 data.RunFor(3); 621 622 base::WeakPtr<SpdyStream> push_stream; 623 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog())); 624 EXPECT_TRUE(push_stream); 625 626 data.RunFor(1); 627 628 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog())); 629 EXPECT_FALSE(push_stream); 630 631 data.RunFor(2); 632 633 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); 634 } 635 636 // Receiving a duplicate header in a HEADERS frame should result in a 637 // protocol error. 638 TEST_P(SpdyStreamTest, DuplicateHeaders) { 639 GURL url(kStreamUrl); 640 641 session_ = 642 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); 643 644 scoped_ptr<SpdyFrame> syn( 645 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); 646 AddWrite(*syn); 647 648 scoped_ptr<SpdyFrame> 649 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); 650 AddRead(*reply); 651 652 scoped_ptr<SpdyFrame> 653 push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kStreamUrl)); 654 AddRead(*push); 655 656 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock()); 657 (*late_headers)[spdy_util_.GetStatusKey()] = "500 Server Error"; 658 scoped_ptr<SpdyFrame> headers_frame( 659 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(), 660 false, 661 2, 662 LOWEST, 663 HEADERS, 664 CONTROL_FLAG_NONE, 665 0)); 666 AddRead(*headers_frame); 667 668 scoped_ptr<SpdyFrame> rst( 669 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR)); 670 AddWrite(*rst); 671 672 AddReadEOF(); 673 674 DeterministicSocketData data(GetReads(), GetNumReads(), 675 GetWrites(), GetNumWrites()); 676 MockConnect connect_data(SYNCHRONOUS, OK); 677 data.set_connect_data(connect_data); 678 679 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); 680 681 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 682 683 base::WeakPtr<SpdyStream> stream = 684 CreateStreamSynchronously( 685 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog()); 686 ASSERT_TRUE(stream.get() != NULL); 687 688 StreamDelegateDoNothing delegate(stream); 689 stream->SetDelegate(&delegate); 690 691 EXPECT_FALSE(stream->HasUrlFromHeaders()); 692 693 scoped_ptr<SpdyHeaderBlock> headers( 694 spdy_util_.ConstructGetHeaderBlock(kStreamUrl)); 695 EXPECT_EQ(ERR_IO_PENDING, 696 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND)); 697 EXPECT_TRUE(stream->HasUrlFromHeaders()); 698 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 699 700 data.RunFor(3); 701 702 base::WeakPtr<SpdyStream> push_stream; 703 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog())); 704 EXPECT_TRUE(push_stream); 705 706 data.RunFor(1); 707 708 EXPECT_EQ(OK, session->GetPushStream(url, &push_stream, BoundNetLog())); 709 EXPECT_FALSE(push_stream); 710 711 data.RunFor(2); 712 713 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); 714 } 715 716 // The tests below are only for SPDY/3 and above. 717 718 // Call IncreaseSendWindowSize on a stream with a large enough delta 719 // to overflow an int32. The SpdyStream should handle that case 720 // gracefully. 721 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) { 722 if (spdy_util_.protocol() < kProtoSPDY3) 723 return; 724 725 session_ = 726 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); 727 728 scoped_ptr<SpdyFrame> req( 729 spdy_util_.ConstructSpdyPost( 730 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0)); 731 AddWrite(*req); 732 733 // Triggered by the overflowing call to IncreaseSendWindowSize 734 // below. 735 scoped_ptr<SpdyFrame> rst( 736 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR)); 737 AddWrite(*rst); 738 739 AddReadEOF(); 740 741 CapturingBoundNetLog log; 742 743 DeterministicSocketData data(GetReads(), GetNumReads(), 744 GetWrites(), GetNumWrites()); 745 MockConnect connect_data(SYNCHRONOUS, OK); 746 data.set_connect_data(connect_data); 747 748 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); 749 750 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 751 GURL url(kStreamUrl); 752 753 base::WeakPtr<SpdyStream> stream = 754 CreateStreamSynchronously( 755 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, log.bound()); 756 ASSERT_TRUE(stream.get() != NULL); 757 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); 758 stream->SetDelegate(&delegate); 759 760 scoped_ptr<SpdyHeaderBlock> headers( 761 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)); 762 EXPECT_EQ(ERR_IO_PENDING, 763 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); 764 EXPECT_TRUE(stream->HasUrlFromHeaders()); 765 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 766 767 data.RunFor(1); 768 769 int32 old_send_window_size = stream->send_window_size(); 770 ASSERT_GT(old_send_window_size, 0); 771 int32 delta_window_size = kint32max - old_send_window_size + 1; 772 stream->IncreaseSendWindowSize(delta_window_size); 773 EXPECT_EQ(NULL, stream.get()); 774 775 data.RunFor(2); 776 777 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate.WaitForClose()); 778 } 779 780 // Functions used with 781 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test(). 782 783 void StallStream(const base::WeakPtr<SpdyStream>& stream) { 784 // Reduce the send window size to 0 to stall. 785 while (stream->send_window_size() > 0) { 786 stream->DecreaseSendWindowSize( 787 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size())); 788 } 789 } 790 791 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream, 792 int32 delta_window_size) { 793 EXPECT_TRUE(stream->send_stalled_by_flow_control()); 794 stream->IncreaseSendWindowSize(delta_window_size); 795 EXPECT_FALSE(stream->send_stalled_by_flow_control()); 796 } 797 798 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream, 799 int32 delta_window_size) { 800 // Make sure that negative adjustments are handled properly. 801 EXPECT_TRUE(stream->send_stalled_by_flow_control()); 802 stream->AdjustSendWindowSize(-delta_window_size); 803 EXPECT_TRUE(stream->send_stalled_by_flow_control()); 804 stream->AdjustSendWindowSize(+delta_window_size); 805 EXPECT_TRUE(stream->send_stalled_by_flow_control()); 806 stream->AdjustSendWindowSize(+delta_window_size); 807 EXPECT_FALSE(stream->send_stalled_by_flow_control()); 808 } 809 810 // Given an unstall function, runs a test to make sure that a 811 // request/response (i.e., an HTTP-like) stream resumes after a stall 812 // and unstall. 813 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest( 814 const UnstallFunction& unstall_function) { 815 GURL url(kStreamUrl); 816 817 session_ = 818 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); 819 820 scoped_ptr<SpdyFrame> req( 821 spdy_util_.ConstructSpdyPost( 822 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0)); 823 AddWrite(*req); 824 825 scoped_ptr<SpdyFrame> body( 826 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, true)); 827 AddWrite(*body); 828 829 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); 830 AddRead(*resp); 831 832 AddReadEOF(); 833 834 DeterministicSocketData data(GetReads(), GetNumReads(), 835 GetWrites(), GetNumWrites()); 836 MockConnect connect_data(SYNCHRONOUS, OK); 837 data.set_connect_data(connect_data); 838 839 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); 840 841 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 842 843 base::WeakPtr<SpdyStream> stream = 844 CreateStreamSynchronously( 845 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog()); 846 ASSERT_TRUE(stream.get() != NULL); 847 848 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece); 849 stream->SetDelegate(&delegate); 850 851 EXPECT_FALSE(stream->HasUrlFromHeaders()); 852 EXPECT_FALSE(stream->send_stalled_by_flow_control()); 853 854 scoped_ptr<SpdyHeaderBlock> headers( 855 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)); 856 EXPECT_EQ(ERR_IO_PENDING, 857 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); 858 EXPECT_TRUE(stream->HasUrlFromHeaders()); 859 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 860 861 StallStream(stream); 862 863 data.RunFor(1); 864 865 EXPECT_TRUE(stream->send_stalled_by_flow_control()); 866 867 unstall_function.Run(stream, kPostBodyLength); 868 869 EXPECT_FALSE(stream->send_stalled_by_flow_control()); 870 871 data.RunFor(3); 872 873 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); 874 875 EXPECT_TRUE(delegate.send_headers_completed()); 876 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status")); 877 EXPECT_EQ(std::string(), delegate.TakeReceivedData()); 878 EXPECT_TRUE(data.at_write_eof()); 879 } 880 881 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) { 882 if (spdy_util_.protocol() < kProtoSPDY3) 883 return; 884 885 RunResumeAfterUnstallRequestResponseTest( 886 base::Bind(&IncreaseStreamSendWindowSize)); 887 } 888 889 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) { 890 if (spdy_util_.protocol() < kProtoSPDY3) 891 return; 892 893 RunResumeAfterUnstallRequestResponseTest( 894 base::Bind(&AdjustStreamSendWindowSize)); 895 } 896 897 // Given an unstall function, runs a test to make sure that a 898 // bidirectional (i.e., non-HTTP-like) stream resumes after a stall 899 // and unstall. 900 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest( 901 const UnstallFunction& unstall_function) { 902 GURL url(kStreamUrl); 903 904 session_ = 905 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); 906 907 scoped_ptr<SpdyFrame> req( 908 spdy_util_.ConstructSpdyPost( 909 kStreamUrl, 1, kPostBodyLength, LOWEST, NULL, 0)); 910 AddWrite(*req); 911 912 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); 913 AddRead(*resp); 914 915 scoped_ptr<SpdyFrame> msg( 916 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false)); 917 AddWrite(*msg); 918 919 scoped_ptr<SpdyFrame> echo( 920 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false)); 921 AddRead(*echo); 922 923 AddReadEOF(); 924 925 DeterministicSocketData data(GetReads(), GetNumReads(), 926 GetWrites(), GetNumWrites()); 927 MockConnect connect_data(SYNCHRONOUS, OK); 928 data.set_connect_data(connect_data); 929 930 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); 931 932 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 933 934 base::WeakPtr<SpdyStream> stream = 935 CreateStreamSynchronously( 936 SPDY_BIDIRECTIONAL_STREAM, session, url, LOWEST, BoundNetLog()); 937 ASSERT_TRUE(stream.get() != NULL); 938 939 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); 940 stream->SetDelegate(&delegate); 941 942 EXPECT_FALSE(stream->HasUrlFromHeaders()); 943 944 scoped_ptr<SpdyHeaderBlock> headers( 945 spdy_util_.ConstructPostHeaderBlock(kStreamUrl, kPostBodyLength)); 946 EXPECT_EQ(ERR_IO_PENDING, 947 stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); 948 EXPECT_TRUE(stream->HasUrlFromHeaders()); 949 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 950 951 data.RunFor(1); 952 953 EXPECT_FALSE(stream->send_stalled_by_flow_control()); 954 955 StallStream(stream); 956 957 data.RunFor(1); 958 959 EXPECT_TRUE(stream->send_stalled_by_flow_control()); 960 961 unstall_function.Run(stream, kPostBodyLength); 962 963 EXPECT_FALSE(stream->send_stalled_by_flow_control()); 964 965 data.RunFor(3); 966 967 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); 968 969 EXPECT_TRUE(delegate.send_headers_completed()); 970 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status")); 971 EXPECT_EQ(std::string(kPostBody, kPostBodyLength), 972 delegate.TakeReceivedData()); 973 EXPECT_TRUE(data.at_write_eof()); 974 } 975 976 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) { 977 if (spdy_util_.protocol() < kProtoSPDY3) 978 return; 979 980 RunResumeAfterUnstallBidirectionalTest( 981 base::Bind(&IncreaseStreamSendWindowSize)); 982 } 983 984 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) { 985 if (spdy_util_.protocol() < kProtoSPDY3) 986 return; 987 988 RunResumeAfterUnstallBidirectionalTest( 989 base::Bind(&AdjustStreamSendWindowSize)); 990 } 991 992 // Test calculation of amount of bytes received from network. 993 TEST_P(SpdyStreamTest, ReceivedBytes) { 994 GURL url(kStreamUrl); 995 996 session_ = 997 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_); 998 999 scoped_ptr<SpdyFrame> syn( 1000 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); 1001 AddWrite(*syn); 1002 1003 scoped_ptr<SpdyFrame> 1004 reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); 1005 AddRead(*reply); 1006 1007 scoped_ptr<SpdyFrame> msg( 1008 spdy_util_.ConstructSpdyBodyFrame(1, kPostBody, kPostBodyLength, false)); 1009 AddRead(*msg); 1010 1011 AddReadEOF(); 1012 1013 DeterministicSocketData data(GetReads(), GetNumReads(), 1014 GetWrites(), GetNumWrites()); 1015 MockConnect connect_data(SYNCHRONOUS, OK); 1016 data.set_connect_data(connect_data); 1017 1018 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); 1019 1020 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); 1021 1022 base::WeakPtr<SpdyStream> stream = 1023 CreateStreamSynchronously( 1024 SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog()); 1025 ASSERT_TRUE(stream.get() != NULL); 1026 1027 StreamDelegateDoNothing delegate(stream); 1028 stream->SetDelegate(&delegate); 1029 1030 EXPECT_FALSE(stream->HasUrlFromHeaders()); 1031 1032 scoped_ptr<SpdyHeaderBlock> headers( 1033 spdy_util_.ConstructGetHeaderBlock(kStreamUrl)); 1034 EXPECT_EQ(ERR_IO_PENDING, 1035 stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND)); 1036 EXPECT_TRUE(stream->HasUrlFromHeaders()); 1037 EXPECT_EQ(kStreamUrl, stream->GetUrlFromHeaders().spec()); 1038 1039 int64 reply_frame_len = reply->size(); 1040 int64 data_header_len = spdy_util_.CreateFramer(false) 1041 ->GetDataFrameMinimumSize(); 1042 int64 data_frame_len = data_header_len + kPostBodyLength; 1043 int64 response_len = reply_frame_len + data_frame_len; 1044 1045 EXPECT_EQ(0, stream->raw_received_bytes()); 1046 data.RunFor(1); // SYN 1047 EXPECT_EQ(0, stream->raw_received_bytes()); 1048 data.RunFor(1); // REPLY 1049 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes()); 1050 data.RunFor(1); // DATA 1051 EXPECT_EQ(response_len, stream->raw_received_bytes()); 1052 data.RunFor(1); // FIN 1053 1054 EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose()); 1055 } 1056 1057 } // namespace 1058 1059 } // namespace test 1060 1061 } // namespace net 1062