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