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