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