| 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 "net/spdy/spdy_stream.h" | |
| 6 | |
| 7 #include <stdint.h> | |
| 8 | |
| 9 #include <algorithm> | |
| 10 #include <cstddef> | |
| 11 #include <limits> | |
| 12 #include <memory> | |
| 13 #include <utility> | |
| 14 #include <vector> | |
| 15 | |
| 16 #include "base/memory/ref_counted.h" | |
| 17 #include "base/run_loop.h" | |
| 18 #include "net/base/completion_callback.h" | |
| 19 #include "net/base/request_priority.h" | |
| 20 #include "net/log/net_log_event_type.h" | |
| 21 #include "net/log/test_net_log.h" | |
| 22 #include "net/log/test_net_log_entry.h" | |
| 23 #include "net/log/test_net_log_util.h" | |
| 24 #include "net/socket/socket_test_util.h" | |
| 25 #include "net/spdy/buffered_spdy_framer.h" | |
| 26 #include "net/spdy/platform/api/spdy_string_piece.h" | |
| 27 #include "net/spdy/spdy_http_utils.h" | |
| 28 #include "net/spdy/spdy_protocol.h" | |
| 29 #include "net/spdy/spdy_session.h" | |
| 30 #include "net/spdy/spdy_stream_test_util.h" | |
| 31 #include "net/spdy/spdy_test_util_common.h" | |
| 32 #include "net/test/cert_test_util.h" | |
| 33 #include "net/test/gtest_util.h" | |
| 34 #include "net/test/test_data_directory.h" | |
| 35 #include "testing/gmock/include/gmock/gmock.h" | |
| 36 #include "testing/gtest/include/gtest/gtest.h" | |
| 37 | |
| 38 // TODO(ukai): factor out common part with spdy_http_stream_unittest.cc | |
| 39 // | |
| 40 namespace net { | |
| 41 | |
| 42 namespace test { | |
| 43 | |
| 44 namespace { | |
| 45 | |
| 46 const char kPushUrl[] = "https://www.example.org/push"; | |
| 47 const char kPostBody[] = "\0hello!\xff"; | |
| 48 const size_t kPostBodyLength = arraysize(kPostBody); | |
| 49 const SpdyStringPiece kPostBodyStringPiece(kPostBody, kPostBodyLength); | |
| 50 | |
| 51 static base::TimeTicks g_time_now; | |
| 52 | |
| 53 base::TimeTicks InstantaneousReads() { | |
| 54 return g_time_now; | |
| 55 } | |
| 56 | |
| 57 } // namespace | |
| 58 | |
| 59 class SpdyStreamTest : public ::testing::Test { | |
| 60 protected: | |
| 61 // A function that takes a SpdyStream and the number of bytes which | |
| 62 // will unstall the next frame completely. | |
| 63 typedef base::Callback<void(const base::WeakPtr<SpdyStream>&, int32_t)> | |
| 64 UnstallFunction; | |
| 65 | |
| 66 SpdyStreamTest() | |
| 67 : url_(kDefaultUrl), | |
| 68 session_(SpdySessionDependencies::SpdyCreateSession(&session_deps_)), | |
| 69 offset_(0), | |
| 70 ssl_(SYNCHRONOUS, OK) {} | |
| 71 | |
| 72 ~SpdyStreamTest() override {} | |
| 73 | |
| 74 base::WeakPtr<SpdySession> CreateDefaultSpdySession() { | |
| 75 SpdySessionKey key(HostPortPair::FromURL(url_), ProxyServer::Direct(), | |
| 76 PRIVACY_MODE_DISABLED); | |
| 77 return CreateSecureSpdySession(session_.get(), key, NetLogWithSource()); | |
| 78 } | |
| 79 | |
| 80 void TearDown() override { base::RunLoop().RunUntilIdle(); } | |
| 81 | |
| 82 void RunResumeAfterUnstallRequestResponseTest( | |
| 83 const UnstallFunction& unstall_function); | |
| 84 | |
| 85 void RunResumeAfterUnstallBidirectionalTest( | |
| 86 const UnstallFunction& unstall_function); | |
| 87 | |
| 88 // Add{Read,Write}() populates lists that are eventually passed to a | |
| 89 // SocketData class. |frame| must live for the whole test. | |
| 90 | |
| 91 void AddRead(const SpdySerializedFrame& frame) { | |
| 92 reads_.push_back(CreateMockRead(frame, offset_++)); | |
| 93 } | |
| 94 | |
| 95 void AddWrite(const SpdySerializedFrame& frame) { | |
| 96 writes_.push_back(CreateMockWrite(frame, offset_++)); | |
| 97 } | |
| 98 | |
| 99 void AddReadEOF() { | |
| 100 reads_.push_back(MockRead(ASYNC, 0, offset_++)); | |
| 101 } | |
| 102 | |
| 103 void AddWritePause() { | |
| 104 writes_.push_back(MockWrite(ASYNC, ERR_IO_PENDING, offset_++)); | |
| 105 } | |
| 106 | |
| 107 void AddReadPause() { | |
| 108 reads_.push_back(MockRead(ASYNC, ERR_IO_PENDING, offset_++)); | |
| 109 } | |
| 110 | |
| 111 MockRead* GetReads() { return reads_.data(); } | |
| 112 | |
| 113 size_t GetNumReads() const { | |
| 114 return reads_.size(); | |
| 115 } | |
| 116 | |
| 117 MockWrite* GetWrites() { return writes_.data(); } | |
| 118 | |
| 119 int GetNumWrites() const { | |
| 120 return writes_.size(); | |
| 121 } | |
| 122 | |
| 123 void ActivatePushStream(SpdySession* session, SpdyStream* stream) { | |
| 124 std::unique_ptr<SpdyStream> activated = | |
| 125 session->ActivateCreatedStream(stream); | |
| 126 activated->set_stream_id(2); | |
| 127 session->InsertActivatedStream(std::move(activated)); | |
| 128 } | |
| 129 | |
| 130 void AddSSLSocketData() { | |
| 131 // Load a cert that is valid for | |
| 132 // www.example.org, mail.example.org, and mail.example.com. | |
| 133 ssl_.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"); | |
| 134 ASSERT_TRUE(ssl_.cert); | |
| 135 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_); | |
| 136 } | |
| 137 | |
| 138 const GURL url_; | |
| 139 SpdyTestUtil spdy_util_; | |
| 140 SpdySessionDependencies session_deps_; | |
| 141 std::unique_ptr<HttpNetworkSession> session_; | |
| 142 | |
| 143 private: | |
| 144 // Used by Add{Read,Write}() above. | |
| 145 std::vector<MockWrite> writes_; | |
| 146 std::vector<MockRead> reads_; | |
| 147 int offset_; | |
| 148 SSLSocketDataProvider ssl_; | |
| 149 }; | |
| 150 | |
| 151 TEST_F(SpdyStreamTest, SendDataAfterOpen) { | |
| 152 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
| 153 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
| 154 AddWrite(req); | |
| 155 | |
| 156 SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0)); | |
| 157 AddRead(resp); | |
| 158 | |
| 159 SpdySerializedFrame msg( | |
| 160 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
| 161 AddWrite(msg); | |
| 162 | |
| 163 SpdySerializedFrame echo( | |
| 164 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
| 165 AddRead(echo); | |
| 166 | |
| 167 AddReadEOF(); | |
| 168 | |
| 169 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 170 GetNumWrites()); | |
| 171 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 172 data.set_connect_data(connect_data); | |
| 173 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 174 | |
| 175 AddSSLSocketData(); | |
| 176 | |
| 177 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 178 | |
| 179 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 180 SPDY_BIDIRECTIONAL_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 181 ASSERT_TRUE(stream); | |
| 182 | |
| 183 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); | |
| 184 stream->SetDelegate(&delegate); | |
| 185 | |
| 186 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 187 | |
| 188 SpdyHeaderBlock headers( | |
| 189 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
| 190 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
| 191 IsError(ERR_IO_PENDING)); | |
| 192 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 193 | |
| 194 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
| 195 | |
| 196 EXPECT_TRUE(delegate.send_headers_completed()); | |
| 197 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
| 198 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
| 199 delegate.TakeReceivedData()); | |
| 200 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 201 } | |
| 202 | |
| 203 // Delegate that receives trailers. | |
| 204 class StreamDelegateWithTrailers : public test::StreamDelegateWithBody { | |
| 205 public: | |
| 206 StreamDelegateWithTrailers(const base::WeakPtr<SpdyStream>& stream, | |
| 207 SpdyStringPiece data) | |
| 208 : StreamDelegateWithBody(stream, data) {} | |
| 209 | |
| 210 ~StreamDelegateWithTrailers() override {} | |
| 211 | |
| 212 void OnTrailers(const SpdyHeaderBlock& trailers) override { | |
| 213 trailers_ = trailers.Clone(); | |
| 214 } | |
| 215 | |
| 216 const SpdyHeaderBlock& trailers() const { return trailers_; } | |
| 217 | |
| 218 private: | |
| 219 SpdyHeaderBlock trailers_; | |
| 220 }; | |
| 221 | |
| 222 // Regression test for https://crbug.com/481033. | |
| 223 TEST_F(SpdyStreamTest, Trailers) { | |
| 224 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
| 225 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
| 226 AddWrite(req); | |
| 227 | |
| 228 SpdySerializedFrame msg( | |
| 229 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
| 230 AddWrite(msg); | |
| 231 | |
| 232 SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0)); | |
| 233 AddRead(resp); | |
| 234 | |
| 235 SpdySerializedFrame echo( | |
| 236 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
| 237 AddRead(echo); | |
| 238 | |
| 239 SpdyHeaderBlock late_headers; | |
| 240 late_headers["foo"] = "bar"; | |
| 241 SpdySerializedFrame trailers(spdy_util_.ConstructSpdyResponseHeaders( | |
| 242 1, std::move(late_headers), false)); | |
| 243 AddRead(trailers); | |
| 244 | |
| 245 AddReadEOF(); | |
| 246 | |
| 247 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 248 GetNumWrites()); | |
| 249 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 250 data.set_connect_data(connect_data); | |
| 251 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 252 | |
| 253 AddSSLSocketData(); | |
| 254 | |
| 255 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 256 | |
| 257 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 258 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 259 ASSERT_TRUE(stream); | |
| 260 | |
| 261 StreamDelegateWithTrailers delegate(stream, kPostBodyStringPiece); | |
| 262 stream->SetDelegate(&delegate); | |
| 263 | |
| 264 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 265 | |
| 266 SpdyHeaderBlock headers( | |
| 267 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
| 268 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
| 269 IsError(ERR_IO_PENDING)); | |
| 270 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 271 | |
| 272 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
| 273 | |
| 274 EXPECT_TRUE(delegate.send_headers_completed()); | |
| 275 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
| 276 const SpdyHeaderBlock& received_trailers = delegate.trailers(); | |
| 277 SpdyHeaderBlock::const_iterator it = received_trailers.find("foo"); | |
| 278 EXPECT_EQ("bar", it->second); | |
| 279 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
| 280 delegate.TakeReceivedData()); | |
| 281 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 282 } | |
| 283 | |
| 284 TEST_F(SpdyStreamTest, PushedStream) { | |
| 285 SpdySerializedFrame req( | |
| 286 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 287 AddWrite(req); | |
| 288 | |
| 289 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
| 290 AddRead(reply); | |
| 291 | |
| 292 SpdySerializedFrame push( | |
| 293 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushUrl)); | |
| 294 AddRead(push); | |
| 295 | |
| 296 SpdySerializedFrame priority( | |
| 297 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
| 298 AddWrite(priority); | |
| 299 | |
| 300 AddReadPause(); | |
| 301 | |
| 302 SpdyStringPiece pushed_msg("foo"); | |
| 303 SpdySerializedFrame pushed_body(spdy_util_.ConstructSpdyDataFrame( | |
| 304 2, pushed_msg.data(), pushed_msg.size(), true)); | |
| 305 AddRead(pushed_body); | |
| 306 | |
| 307 SpdyStringPiece msg("bar"); | |
| 308 SpdySerializedFrame body( | |
| 309 spdy_util_.ConstructSpdyDataFrame(1, msg.data(), msg.size(), true)); | |
| 310 AddRead(body); | |
| 311 | |
| 312 AddReadEOF(); | |
| 313 | |
| 314 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 315 GetNumWrites()); | |
| 316 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 317 data.set_connect_data(connect_data); | |
| 318 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 319 | |
| 320 AddSSLSocketData(); | |
| 321 | |
| 322 g_time_now = base::TimeTicks::Now(); | |
| 323 session_deps_.time_func = InstantaneousReads; | |
| 324 session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); | |
| 325 | |
| 326 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 327 | |
| 328 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 329 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 330 ASSERT_TRUE(stream); | |
| 331 | |
| 332 StreamDelegateDoNothing delegate(stream); | |
| 333 stream->SetDelegate(&delegate); | |
| 334 | |
| 335 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 336 | |
| 337 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 338 EXPECT_THAT( | |
| 339 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
| 340 IsError(ERR_IO_PENDING)); | |
| 341 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 342 | |
| 343 data.RunUntilPaused(); | |
| 344 | |
| 345 SpdyStream* push_stream; | |
| 346 EXPECT_THAT(session->GetPushStream(GURL(kPushUrl), IDLE, &push_stream, | |
| 347 NetLogWithSource()), | |
| 348 IsOk()); | |
| 349 ASSERT_TRUE(push_stream); | |
| 350 EXPECT_EQ(kPushUrl, push_stream->GetUrlFromHeaders().spec()); | |
| 351 | |
| 352 LoadTimingInfo load_timing_info; | |
| 353 EXPECT_TRUE(push_stream->GetLoadTimingInfo(&load_timing_info)); | |
| 354 EXPECT_EQ(g_time_now, load_timing_info.push_start); | |
| 355 EXPECT_TRUE(load_timing_info.push_end.is_null()); | |
| 356 | |
| 357 StreamDelegateDoNothing push_delegate(push_stream->GetWeakPtr()); | |
| 358 push_stream->SetDelegate(&push_delegate); | |
| 359 | |
| 360 data.Resume(); | |
| 361 | |
| 362 EXPECT_TRUE(push_stream->GetLoadTimingInfo(&load_timing_info)); | |
| 363 EXPECT_EQ(g_time_now, load_timing_info.push_start); | |
| 364 EXPECT_FALSE(load_timing_info.push_end.is_null()); | |
| 365 | |
| 366 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
| 367 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
| 368 EXPECT_EQ(msg, delegate.TakeReceivedData()); | |
| 369 | |
| 370 EXPECT_THAT(push_delegate.WaitForClose(), IsOk()); | |
| 371 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
| 372 EXPECT_EQ(pushed_msg, push_delegate.TakeReceivedData()); | |
| 373 } | |
| 374 | |
| 375 TEST_F(SpdyStreamTest, StreamError) { | |
| 376 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
| 377 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
| 378 AddWrite(req); | |
| 379 | |
| 380 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
| 381 AddRead(resp); | |
| 382 | |
| 383 SpdySerializedFrame msg( | |
| 384 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
| 385 AddWrite(msg); | |
| 386 | |
| 387 SpdySerializedFrame echo( | |
| 388 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
| 389 AddRead(echo); | |
| 390 | |
| 391 AddReadEOF(); | |
| 392 | |
| 393 BoundTestNetLog log; | |
| 394 | |
| 395 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 396 GetNumWrites()); | |
| 397 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 398 data.set_connect_data(connect_data); | |
| 399 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 400 | |
| 401 AddSSLSocketData(); | |
| 402 | |
| 403 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 404 | |
| 405 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 406 SPDY_BIDIRECTIONAL_STREAM, session, url_, LOWEST, log.bound()); | |
| 407 ASSERT_TRUE(stream); | |
| 408 | |
| 409 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); | |
| 410 stream->SetDelegate(&delegate); | |
| 411 | |
| 412 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 413 | |
| 414 SpdyHeaderBlock headers( | |
| 415 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
| 416 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
| 417 IsError(ERR_IO_PENDING)); | |
| 418 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 419 | |
| 420 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
| 421 | |
| 422 const SpdyStreamId stream_id = delegate.stream_id(); | |
| 423 | |
| 424 EXPECT_TRUE(delegate.send_headers_completed()); | |
| 425 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
| 426 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
| 427 delegate.TakeReceivedData()); | |
| 428 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 429 | |
| 430 // Check that the NetLog was filled reasonably. | |
| 431 TestNetLogEntry::List entries; | |
| 432 log.GetEntries(&entries); | |
| 433 EXPECT_LT(0u, entries.size()); | |
| 434 | |
| 435 // Check that we logged SPDY_STREAM_ERROR correctly. | |
| 436 int pos = ExpectLogContainsSomewhere( | |
| 437 entries, 0, NetLogEventType::HTTP2_STREAM_ERROR, NetLogEventPhase::NONE); | |
| 438 | |
| 439 int stream_id2; | |
| 440 ASSERT_TRUE(entries[pos].GetIntegerValue("stream_id", &stream_id2)); | |
| 441 EXPECT_EQ(static_cast<int>(stream_id), stream_id2); | |
| 442 } | |
| 443 | |
| 444 // Make sure that large blocks of data are properly split up into frame-sized | |
| 445 // chunks for a request/response (i.e., an HTTP-like) stream. | |
| 446 TEST_F(SpdyStreamTest, SendLargeDataAfterOpenRequestResponse) { | |
| 447 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
| 448 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
| 449 AddWrite(req); | |
| 450 | |
| 451 SpdyString chunk_data(kMaxSpdyFrameChunkSize, 'x'); | |
| 452 SpdySerializedFrame chunk(spdy_util_.ConstructSpdyDataFrame( | |
| 453 1, chunk_data.data(), chunk_data.length(), false)); | |
| 454 AddWrite(chunk); | |
| 455 AddWrite(chunk); | |
| 456 | |
| 457 SpdySerializedFrame last_chunk(spdy_util_.ConstructSpdyDataFrame( | |
| 458 1, chunk_data.data(), chunk_data.length(), true)); | |
| 459 AddWrite(last_chunk); | |
| 460 | |
| 461 SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0)); | |
| 462 AddRead(resp); | |
| 463 | |
| 464 AddReadEOF(); | |
| 465 | |
| 466 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 467 GetNumWrites()); | |
| 468 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 469 data.set_connect_data(connect_data); | |
| 470 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 471 | |
| 472 AddSSLSocketData(); | |
| 473 | |
| 474 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 475 | |
| 476 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 477 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 478 ASSERT_TRUE(stream); | |
| 479 | |
| 480 SpdyString body_data(3 * kMaxSpdyFrameChunkSize, 'x'); | |
| 481 StreamDelegateWithBody delegate(stream, body_data); | |
| 482 stream->SetDelegate(&delegate); | |
| 483 | |
| 484 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 485 | |
| 486 SpdyHeaderBlock headers( | |
| 487 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
| 488 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
| 489 IsError(ERR_IO_PENDING)); | |
| 490 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 491 | |
| 492 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
| 493 | |
| 494 EXPECT_TRUE(delegate.send_headers_completed()); | |
| 495 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
| 496 EXPECT_EQ(SpdyString(), delegate.TakeReceivedData()); | |
| 497 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 498 } | |
| 499 | |
| 500 // Make sure that large blocks of data are properly split up into frame-sized | |
| 501 // chunks for a bidirectional (i.e., non-HTTP-like) stream. | |
| 502 TEST_F(SpdyStreamTest, SendLargeDataAfterOpenBidirectional) { | |
| 503 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
| 504 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
| 505 AddWrite(req); | |
| 506 | |
| 507 SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0)); | |
| 508 AddRead(resp); | |
| 509 | |
| 510 SpdyString chunk_data(kMaxSpdyFrameChunkSize, 'x'); | |
| 511 SpdySerializedFrame chunk(spdy_util_.ConstructSpdyDataFrame( | |
| 512 1, chunk_data.data(), chunk_data.length(), false)); | |
| 513 AddWrite(chunk); | |
| 514 AddWrite(chunk); | |
| 515 AddWrite(chunk); | |
| 516 | |
| 517 AddReadEOF(); | |
| 518 | |
| 519 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 520 GetNumWrites()); | |
| 521 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 522 data.set_connect_data(connect_data); | |
| 523 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 524 | |
| 525 AddSSLSocketData(); | |
| 526 | |
| 527 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 528 | |
| 529 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 530 SPDY_BIDIRECTIONAL_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 531 ASSERT_TRUE(stream); | |
| 532 | |
| 533 SpdyString body_data(3 * kMaxSpdyFrameChunkSize, 'x'); | |
| 534 StreamDelegateSendImmediate delegate(stream, body_data); | |
| 535 stream->SetDelegate(&delegate); | |
| 536 | |
| 537 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 538 | |
| 539 SpdyHeaderBlock headers( | |
| 540 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
| 541 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
| 542 IsError(ERR_IO_PENDING)); | |
| 543 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 544 | |
| 545 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
| 546 | |
| 547 EXPECT_TRUE(delegate.send_headers_completed()); | |
| 548 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
| 549 EXPECT_EQ(SpdyString(), delegate.TakeReceivedData()); | |
| 550 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 551 } | |
| 552 | |
| 553 // Receiving a header with uppercase ASCII should result in a protocol error. | |
| 554 TEST_F(SpdyStreamTest, UpperCaseHeaders) { | |
| 555 SpdySerializedFrame req( | |
| 556 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 557 AddWrite(req); | |
| 558 | |
| 559 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"}; | |
| 560 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply( | |
| 561 kExtraHeaders, arraysize(kExtraHeaders) / 2, 1)); | |
| 562 AddRead(reply); | |
| 563 | |
| 564 SpdySerializedFrame rst( | |
| 565 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
| 566 AddWrite(rst); | |
| 567 | |
| 568 AddReadEOF(); | |
| 569 | |
| 570 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 571 GetNumWrites()); | |
| 572 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 573 data.set_connect_data(connect_data); | |
| 574 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 575 | |
| 576 AddSSLSocketData(); | |
| 577 | |
| 578 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 579 | |
| 580 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 581 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 582 ASSERT_TRUE(stream); | |
| 583 | |
| 584 StreamDelegateDoNothing delegate(stream); | |
| 585 stream->SetDelegate(&delegate); | |
| 586 | |
| 587 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 588 | |
| 589 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 590 EXPECT_THAT( | |
| 591 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
| 592 IsError(ERR_IO_PENDING)); | |
| 593 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 594 | |
| 595 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
| 596 | |
| 597 // Finish async network reads and writes. | |
| 598 base::RunLoop().RunUntilIdle(); | |
| 599 | |
| 600 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 601 EXPECT_TRUE(data.AllReadDataConsumed()); | |
| 602 } | |
| 603 | |
| 604 // Receiving a header with uppercase ASCII should result in a protocol error | |
| 605 // even for a push stream. | |
| 606 TEST_F(SpdyStreamTest, UpperCaseHeadersOnPush) { | |
| 607 SpdySerializedFrame req( | |
| 608 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 609 AddWrite(req); | |
| 610 | |
| 611 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
| 612 AddRead(reply); | |
| 613 | |
| 614 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"}; | |
| 615 SpdySerializedFrame push(spdy_util_.ConstructSpdyPush( | |
| 616 kExtraHeaders, arraysize(kExtraHeaders) / 2, 2, 1, kPushUrl)); | |
| 617 AddRead(push); | |
| 618 | |
| 619 SpdySerializedFrame priority( | |
| 620 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
| 621 AddWrite(priority); | |
| 622 | |
| 623 SpdySerializedFrame rst( | |
| 624 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_PROTOCOL_ERROR)); | |
| 625 AddWrite(rst); | |
| 626 | |
| 627 AddReadPause(); | |
| 628 | |
| 629 AddReadEOF(); | |
| 630 | |
| 631 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 632 GetNumWrites()); | |
| 633 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 634 data.set_connect_data(connect_data); | |
| 635 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 636 | |
| 637 AddSSLSocketData(); | |
| 638 | |
| 639 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 640 | |
| 641 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 642 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 643 ASSERT_TRUE(stream); | |
| 644 | |
| 645 StreamDelegateDoNothing delegate(stream); | |
| 646 stream->SetDelegate(&delegate); | |
| 647 | |
| 648 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 649 | |
| 650 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 651 EXPECT_THAT( | |
| 652 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
| 653 IsError(ERR_IO_PENDING)); | |
| 654 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 655 | |
| 656 data.RunUntilPaused(); | |
| 657 | |
| 658 SpdyStream* push_stream; | |
| 659 EXPECT_THAT(session->GetPushStream(GURL(kPushUrl), IDLE, &push_stream, | |
| 660 NetLogWithSource()), | |
| 661 IsOk()); | |
| 662 EXPECT_FALSE(push_stream); | |
| 663 | |
| 664 data.Resume(); | |
| 665 | |
| 666 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
| 667 | |
| 668 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 669 EXPECT_TRUE(data.AllReadDataConsumed()); | |
| 670 } | |
| 671 | |
| 672 TEST_F(SpdyStreamTest, HeadersMustHaveStatus) { | |
| 673 SpdySerializedFrame req( | |
| 674 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 675 AddWrite(req); | |
| 676 | |
| 677 // Response headers without ":status" header field: protocol error. | |
| 678 SpdyHeaderBlock header_block_without_status; | |
| 679 header_block_without_status[spdy_util_.GetMethodKey()] = "GET"; | |
| 680 header_block_without_status[spdy_util_.GetHostKey()] = "www.example.org"; | |
| 681 header_block_without_status[spdy_util_.GetSchemeKey()] = "https"; | |
| 682 header_block_without_status[spdy_util_.GetPathKey()] = "/"; | |
| 683 SpdySerializedFrame reply( | |
| 684 spdy_util_.ConstructSpdyReply(1, std::move(header_block_without_status))); | |
| 685 AddRead(reply); | |
| 686 | |
| 687 SpdySerializedFrame rst( | |
| 688 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
| 689 AddWrite(rst); | |
| 690 | |
| 691 AddReadEOF(); | |
| 692 | |
| 693 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 694 GetNumWrites()); | |
| 695 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 696 data.set_connect_data(connect_data); | |
| 697 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 698 | |
| 699 AddSSLSocketData(); | |
| 700 | |
| 701 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 702 | |
| 703 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 704 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 705 ASSERT_TRUE(stream); | |
| 706 | |
| 707 StreamDelegateDoNothing delegate(stream); | |
| 708 stream->SetDelegate(&delegate); | |
| 709 | |
| 710 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 711 | |
| 712 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 713 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
| 714 NO_MORE_DATA_TO_SEND)); | |
| 715 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 716 | |
| 717 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
| 718 | |
| 719 // Finish async network reads and writes. | |
| 720 base::RunLoop().RunUntilIdle(); | |
| 721 | |
| 722 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 723 EXPECT_TRUE(data.AllReadDataConsumed()); | |
| 724 } | |
| 725 | |
| 726 TEST_F(SpdyStreamTest, HeadersMustHaveStatusOnPushedStream) { | |
| 727 SpdySerializedFrame req( | |
| 728 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 729 AddWrite(req); | |
| 730 | |
| 731 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
| 732 AddRead(reply); | |
| 733 | |
| 734 SpdySerializedFrame push_promise(spdy_util_.ConstructInitialSpdyPushFrame( | |
| 735 spdy_util_.ConstructGetHeaderBlock(kPushUrl), 2, 1)); | |
| 736 AddRead(push_promise); | |
| 737 | |
| 738 SpdySerializedFrame priority( | |
| 739 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
| 740 AddWrite(priority); | |
| 741 | |
| 742 // Response headers without ":status" header field: protocol error. | |
| 743 SpdyHeaderBlock header_block_without_status; | |
| 744 header_block_without_status[spdy_util_.GetMethodKey()] = "GET"; | |
| 745 header_block_without_status[spdy_util_.GetHostKey()] = "www.example.org"; | |
| 746 header_block_without_status[spdy_util_.GetSchemeKey()] = "https"; | |
| 747 header_block_without_status[spdy_util_.GetPathKey()] = "/"; | |
| 748 SpdySerializedFrame pushed_reply( | |
| 749 spdy_util_.ConstructSpdyReply(2, std::move(header_block_without_status))); | |
| 750 AddRead(pushed_reply); | |
| 751 | |
| 752 SpdySerializedFrame rst( | |
| 753 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_PROTOCOL_ERROR)); | |
| 754 AddWrite(rst); | |
| 755 | |
| 756 SpdySerializedFrame body( | |
| 757 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
| 758 AddRead(body); | |
| 759 | |
| 760 AddReadEOF(); | |
| 761 | |
| 762 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 763 GetNumWrites()); | |
| 764 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 765 data.set_connect_data(connect_data); | |
| 766 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 767 | |
| 768 AddSSLSocketData(); | |
| 769 | |
| 770 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 771 | |
| 772 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 773 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 774 ASSERT_TRUE(stream); | |
| 775 | |
| 776 StreamDelegateDoNothing delegate(stream); | |
| 777 stream->SetDelegate(&delegate); | |
| 778 | |
| 779 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 780 | |
| 781 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 782 EXPECT_THAT( | |
| 783 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
| 784 IsError(ERR_IO_PENDING)); | |
| 785 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 786 | |
| 787 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
| 788 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
| 789 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
| 790 delegate.TakeReceivedData()); | |
| 791 | |
| 792 // Finish async network reads and writes. | |
| 793 base::RunLoop().RunUntilIdle(); | |
| 794 | |
| 795 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 796 EXPECT_TRUE(data.AllReadDataConsumed()); | |
| 797 } | |
| 798 | |
| 799 TEST_F(SpdyStreamTest, HeadersMustPreceedData) { | |
| 800 SpdySerializedFrame req( | |
| 801 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 802 AddWrite(req); | |
| 803 | |
| 804 // Response body not preceeded by headers: protocol error. | |
| 805 SpdySerializedFrame body( | |
| 806 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
| 807 AddRead(body); | |
| 808 | |
| 809 SpdySerializedFrame rst( | |
| 810 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
| 811 AddWrite(rst); | |
| 812 | |
| 813 AddReadEOF(); | |
| 814 | |
| 815 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 816 GetNumWrites()); | |
| 817 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 818 data.set_connect_data(connect_data); | |
| 819 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 820 | |
| 821 AddSSLSocketData(); | |
| 822 | |
| 823 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 824 | |
| 825 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 826 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 827 ASSERT_TRUE(stream); | |
| 828 | |
| 829 StreamDelegateDoNothing delegate(stream); | |
| 830 stream->SetDelegate(&delegate); | |
| 831 | |
| 832 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 833 | |
| 834 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 835 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
| 836 NO_MORE_DATA_TO_SEND)); | |
| 837 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 838 | |
| 839 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
| 840 } | |
| 841 | |
| 842 TEST_F(SpdyStreamTest, HeadersMustPreceedDataOnPushedStream) { | |
| 843 SpdySerializedFrame req( | |
| 844 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 845 AddWrite(req); | |
| 846 | |
| 847 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
| 848 AddRead(reply); | |
| 849 | |
| 850 SpdySerializedFrame push_promise(spdy_util_.ConstructInitialSpdyPushFrame( | |
| 851 spdy_util_.ConstructGetHeaderBlock(kPushUrl), 2, 1)); | |
| 852 AddRead(push_promise); | |
| 853 | |
| 854 SpdySerializedFrame priority( | |
| 855 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); | |
| 856 AddWrite(priority); | |
| 857 | |
| 858 SpdySerializedFrame pushed_body( | |
| 859 spdy_util_.ConstructSpdyDataFrame(2, kPostBody, kPostBodyLength, true)); | |
| 860 AddRead(pushed_body); | |
| 861 | |
| 862 SpdySerializedFrame rst( | |
| 863 spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_PROTOCOL_ERROR)); | |
| 864 AddWrite(rst); | |
| 865 | |
| 866 SpdySerializedFrame body( | |
| 867 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
| 868 AddRead(body); | |
| 869 | |
| 870 AddReadEOF(); | |
| 871 | |
| 872 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 873 GetNumWrites()); | |
| 874 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 875 data.set_connect_data(connect_data); | |
| 876 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 877 | |
| 878 AddSSLSocketData(); | |
| 879 | |
| 880 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 881 | |
| 882 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 883 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 884 ASSERT_TRUE(stream); | |
| 885 | |
| 886 StreamDelegateDoNothing delegate(stream); | |
| 887 stream->SetDelegate(&delegate); | |
| 888 | |
| 889 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 890 | |
| 891 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 892 EXPECT_THAT( | |
| 893 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
| 894 IsError(ERR_IO_PENDING)); | |
| 895 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 896 | |
| 897 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
| 898 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
| 899 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
| 900 delegate.TakeReceivedData()); | |
| 901 | |
| 902 // Finish async network reads and writes. | |
| 903 base::RunLoop().RunUntilIdle(); | |
| 904 | |
| 905 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 906 EXPECT_TRUE(data.AllReadDataConsumed()); | |
| 907 } | |
| 908 | |
| 909 TEST_F(SpdyStreamTest, TrailersMustNotFollowTrailers) { | |
| 910 SpdySerializedFrame req( | |
| 911 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 912 AddWrite(req); | |
| 913 | |
| 914 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
| 915 AddRead(reply); | |
| 916 | |
| 917 SpdySerializedFrame body( | |
| 918 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
| 919 AddRead(body); | |
| 920 | |
| 921 SpdyHeaderBlock trailers_block; | |
| 922 trailers_block["foo"] = "bar"; | |
| 923 SpdySerializedFrame first_trailers(spdy_util_.ConstructSpdyResponseHeaders( | |
| 924 1, std::move(trailers_block), false)); | |
| 925 AddRead(first_trailers); | |
| 926 | |
| 927 // Trailers following trailers: procotol error. | |
| 928 SpdySerializedFrame second_trailers(spdy_util_.ConstructSpdyResponseHeaders( | |
| 929 1, std::move(trailers_block), true)); | |
| 930 AddRead(second_trailers); | |
| 931 | |
| 932 SpdySerializedFrame rst( | |
| 933 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
| 934 AddWrite(rst); | |
| 935 | |
| 936 AddReadEOF(); | |
| 937 | |
| 938 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 939 GetNumWrites()); | |
| 940 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 941 data.set_connect_data(connect_data); | |
| 942 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 943 | |
| 944 AddSSLSocketData(); | |
| 945 | |
| 946 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 947 | |
| 948 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 949 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 950 ASSERT_TRUE(stream); | |
| 951 | |
| 952 StreamDelegateDoNothing delegate(stream); | |
| 953 stream->SetDelegate(&delegate); | |
| 954 | |
| 955 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 956 | |
| 957 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 958 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
| 959 NO_MORE_DATA_TO_SEND)); | |
| 960 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 961 | |
| 962 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
| 963 | |
| 964 // Finish async network reads and writes. | |
| 965 base::RunLoop().RunUntilIdle(); | |
| 966 | |
| 967 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 968 EXPECT_TRUE(data.AllReadDataConsumed()); | |
| 969 } | |
| 970 | |
| 971 TEST_F(SpdyStreamTest, DataMustNotFollowTrailers) { | |
| 972 SpdySerializedFrame req( | |
| 973 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 974 AddWrite(req); | |
| 975 | |
| 976 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
| 977 AddRead(reply); | |
| 978 | |
| 979 SpdySerializedFrame body( | |
| 980 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
| 981 AddRead(body); | |
| 982 | |
| 983 SpdyHeaderBlock trailers_block; | |
| 984 trailers_block["foo"] = "bar"; | |
| 985 SpdySerializedFrame trailers(spdy_util_.ConstructSpdyResponseHeaders( | |
| 986 1, std::move(trailers_block), false)); | |
| 987 AddRead(trailers); | |
| 988 | |
| 989 // DATA frame following trailers: protocol error. | |
| 990 AddRead(body); | |
| 991 | |
| 992 SpdySerializedFrame rst( | |
| 993 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
| 994 AddWrite(rst); | |
| 995 | |
| 996 AddReadEOF(); | |
| 997 | |
| 998 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 999 GetNumWrites()); | |
| 1000 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 1001 data.set_connect_data(connect_data); | |
| 1002 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1003 | |
| 1004 AddSSLSocketData(); | |
| 1005 | |
| 1006 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 1007 | |
| 1008 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 1009 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 1010 ASSERT_TRUE(stream); | |
| 1011 | |
| 1012 StreamDelegateDoNothing delegate(stream); | |
| 1013 stream->SetDelegate(&delegate); | |
| 1014 | |
| 1015 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 1016 | |
| 1017 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 1018 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
| 1019 NO_MORE_DATA_TO_SEND)); | |
| 1020 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 1021 | |
| 1022 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
| 1023 | |
| 1024 // Finish async network reads and writes. | |
| 1025 base::RunLoop().RunUntilIdle(); | |
| 1026 | |
| 1027 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 1028 EXPECT_TRUE(data.AllReadDataConsumed()); | |
| 1029 } | |
| 1030 | |
| 1031 TEST_F(SpdyStreamTest, InformationalHeaders) { | |
| 1032 SpdySerializedFrame req( | |
| 1033 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 1034 AddWrite(req); | |
| 1035 | |
| 1036 SpdyHeaderBlock informational_headers; | |
| 1037 informational_headers[":status"] = "100"; | |
| 1038 SpdySerializedFrame informational_response( | |
| 1039 spdy_util_.ConstructSpdyResponseHeaders( | |
| 1040 1, std::move(informational_headers), false)); | |
| 1041 AddRead(informational_response); | |
| 1042 | |
| 1043 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
| 1044 AddRead(reply); | |
| 1045 | |
| 1046 SpdySerializedFrame body( | |
| 1047 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
| 1048 AddRead(body); | |
| 1049 | |
| 1050 AddReadEOF(); | |
| 1051 | |
| 1052 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 1053 GetNumWrites()); | |
| 1054 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 1055 data.set_connect_data(connect_data); | |
| 1056 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1057 | |
| 1058 AddSSLSocketData(); | |
| 1059 | |
| 1060 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 1061 | |
| 1062 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 1063 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 1064 ASSERT_TRUE(stream); | |
| 1065 | |
| 1066 StreamDelegateDoNothing delegate(stream); | |
| 1067 stream->SetDelegate(&delegate); | |
| 1068 | |
| 1069 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 1070 | |
| 1071 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 1072 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
| 1073 NO_MORE_DATA_TO_SEND)); | |
| 1074 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 1075 | |
| 1076 EXPECT_THAT(delegate.WaitForClose(), IsOk()); | |
| 1077 EXPECT_EQ("200", delegate.GetResponseHeaderValue(spdy_util_.GetStatusKey())); | |
| 1078 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
| 1079 delegate.TakeReceivedData()); | |
| 1080 | |
| 1081 // Finish async network reads and writes. | |
| 1082 base::RunLoop().RunUntilIdle(); | |
| 1083 | |
| 1084 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 1085 EXPECT_TRUE(data.AllReadDataConsumed()); | |
| 1086 } | |
| 1087 | |
| 1088 TEST_F(SpdyStreamTest, StatusMustBeNumber) { | |
| 1089 SpdySerializedFrame req( | |
| 1090 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 1091 AddWrite(req); | |
| 1092 | |
| 1093 SpdyHeaderBlock incorrect_headers; | |
| 1094 incorrect_headers[":status"] = "nan"; | |
| 1095 SpdySerializedFrame reply(spdy_util_.ConstructSpdyResponseHeaders( | |
| 1096 1, std::move(incorrect_headers), false)); | |
| 1097 AddRead(reply); | |
| 1098 | |
| 1099 SpdySerializedFrame rst( | |
| 1100 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
| 1101 AddWrite(rst); | |
| 1102 | |
| 1103 AddReadEOF(); | |
| 1104 | |
| 1105 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 1106 GetNumWrites()); | |
| 1107 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 1108 data.set_connect_data(connect_data); | |
| 1109 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1110 | |
| 1111 AddSSLSocketData(); | |
| 1112 | |
| 1113 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 1114 | |
| 1115 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 1116 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 1117 ASSERT_TRUE(stream); | |
| 1118 | |
| 1119 StreamDelegateDoNothing delegate(stream); | |
| 1120 stream->SetDelegate(&delegate); | |
| 1121 | |
| 1122 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 1123 | |
| 1124 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 1125 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
| 1126 NO_MORE_DATA_TO_SEND)); | |
| 1127 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 1128 | |
| 1129 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
| 1130 | |
| 1131 // Finish async network reads and writes. | |
| 1132 base::RunLoop().RunUntilIdle(); | |
| 1133 | |
| 1134 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 1135 EXPECT_TRUE(data.AllReadDataConsumed()); | |
| 1136 } | |
| 1137 | |
| 1138 TEST_F(SpdyStreamTest, StatusCannotHaveExtraText) { | |
| 1139 SpdySerializedFrame req( | |
| 1140 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 1141 AddWrite(req); | |
| 1142 | |
| 1143 SpdyHeaderBlock headers_with_status_text; | |
| 1144 headers_with_status_text[":status"] = | |
| 1145 "200 Some random extra text describing status"; | |
| 1146 SpdySerializedFrame reply(spdy_util_.ConstructSpdyResponseHeaders( | |
| 1147 1, std::move(headers_with_status_text), false)); | |
| 1148 AddRead(reply); | |
| 1149 | |
| 1150 SpdySerializedFrame body( | |
| 1151 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
| 1152 AddRead(body); | |
| 1153 | |
| 1154 SpdySerializedFrame rst( | |
| 1155 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
| 1156 AddWrite(rst); | |
| 1157 | |
| 1158 AddReadEOF(); | |
| 1159 | |
| 1160 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 1161 GetNumWrites()); | |
| 1162 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 1163 data.set_connect_data(connect_data); | |
| 1164 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1165 | |
| 1166 AddSSLSocketData(); | |
| 1167 | |
| 1168 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 1169 | |
| 1170 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 1171 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 1172 ASSERT_TRUE(stream); | |
| 1173 | |
| 1174 StreamDelegateDoNothing delegate(stream); | |
| 1175 stream->SetDelegate(&delegate); | |
| 1176 | |
| 1177 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 1178 | |
| 1179 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 1180 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
| 1181 NO_MORE_DATA_TO_SEND)); | |
| 1182 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 1183 | |
| 1184 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
| 1185 | |
| 1186 // Finish async network reads and writes. | |
| 1187 base::RunLoop().RunUntilIdle(); | |
| 1188 | |
| 1189 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 1190 EXPECT_TRUE(data.AllReadDataConsumed()); | |
| 1191 } | |
| 1192 | |
| 1193 TEST_F(SpdyStreamTest, StatusMustBePresent) { | |
| 1194 SpdySerializedFrame req( | |
| 1195 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 1196 AddWrite(req); | |
| 1197 | |
| 1198 SpdyHeaderBlock headers_without_status; | |
| 1199 SpdySerializedFrame reply(spdy_util_.ConstructSpdyResponseHeaders( | |
| 1200 1, std::move(headers_without_status), false)); | |
| 1201 AddRead(reply); | |
| 1202 | |
| 1203 SpdySerializedFrame body( | |
| 1204 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
| 1205 AddRead(body); | |
| 1206 | |
| 1207 SpdySerializedFrame rst( | |
| 1208 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_PROTOCOL_ERROR)); | |
| 1209 AddWrite(rst); | |
| 1210 | |
| 1211 AddReadEOF(); | |
| 1212 | |
| 1213 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 1214 GetNumWrites()); | |
| 1215 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 1216 data.set_connect_data(connect_data); | |
| 1217 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1218 | |
| 1219 AddSSLSocketData(); | |
| 1220 | |
| 1221 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 1222 | |
| 1223 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 1224 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 1225 ASSERT_TRUE(stream); | |
| 1226 | |
| 1227 StreamDelegateDoNothing delegate(stream); | |
| 1228 stream->SetDelegate(&delegate); | |
| 1229 | |
| 1230 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 1231 | |
| 1232 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 1233 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequestHeaders(std::move(headers), | |
| 1234 NO_MORE_DATA_TO_SEND)); | |
| 1235 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 1236 | |
| 1237 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
| 1238 | |
| 1239 // Finish async network reads and writes. | |
| 1240 base::RunLoop().RunUntilIdle(); | |
| 1241 | |
| 1242 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 1243 EXPECT_TRUE(data.AllReadDataConsumed()); | |
| 1244 } | |
| 1245 | |
| 1246 // Call IncreaseSendWindowSize on a stream with a large enough delta to overflow | |
| 1247 // an int32_t. The SpdyStream should handle that case gracefully. | |
| 1248 TEST_F(SpdyStreamTest, IncreaseSendWindowSizeOverflow) { | |
| 1249 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
| 1250 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
| 1251 AddWrite(req); | |
| 1252 | |
| 1253 AddReadPause(); | |
| 1254 | |
| 1255 // Triggered by the overflowing call to IncreaseSendWindowSize | |
| 1256 // below. | |
| 1257 SpdySerializedFrame rst( | |
| 1258 spdy_util_.ConstructSpdyRstStream(1, ERROR_CODE_FLOW_CONTROL_ERROR)); | |
| 1259 AddWrite(rst); | |
| 1260 | |
| 1261 AddReadEOF(); | |
| 1262 | |
| 1263 BoundTestNetLog log; | |
| 1264 | |
| 1265 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 1266 GetNumWrites()); | |
| 1267 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 1268 data.set_connect_data(connect_data); | |
| 1269 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1270 | |
| 1271 AddSSLSocketData(); | |
| 1272 | |
| 1273 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 1274 | |
| 1275 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 1276 SPDY_BIDIRECTIONAL_STREAM, session, url_, LOWEST, log.bound()); | |
| 1277 ASSERT_TRUE(stream); | |
| 1278 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); | |
| 1279 stream->SetDelegate(&delegate); | |
| 1280 | |
| 1281 SpdyHeaderBlock headers( | |
| 1282 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
| 1283 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
| 1284 IsError(ERR_IO_PENDING)); | |
| 1285 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 1286 | |
| 1287 data.RunUntilPaused(); | |
| 1288 | |
| 1289 int32_t old_send_window_size = stream->send_window_size(); | |
| 1290 ASSERT_GT(old_send_window_size, 0); | |
| 1291 int32_t delta_window_size = | |
| 1292 std::numeric_limits<int32_t>::max() - old_send_window_size + 1; | |
| 1293 stream->IncreaseSendWindowSize(delta_window_size); | |
| 1294 EXPECT_FALSE(stream); | |
| 1295 | |
| 1296 data.Resume(); | |
| 1297 base::RunLoop().RunUntilIdle(); | |
| 1298 | |
| 1299 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_SPDY_PROTOCOL_ERROR)); | |
| 1300 } | |
| 1301 | |
| 1302 // Functions used with | |
| 1303 // RunResumeAfterUnstall{RequestResponse,Bidirectional}Test(). | |
| 1304 | |
| 1305 void StallStream(const base::WeakPtr<SpdyStream>& stream) { | |
| 1306 // Reduce the send window size to 0 to stall. | |
| 1307 while (stream->send_window_size() > 0) { | |
| 1308 stream->DecreaseSendWindowSize( | |
| 1309 std::min(kMaxSpdyFrameChunkSize, stream->send_window_size())); | |
| 1310 } | |
| 1311 } | |
| 1312 | |
| 1313 void IncreaseStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream, | |
| 1314 int32_t delta_window_size) { | |
| 1315 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
| 1316 stream->IncreaseSendWindowSize(delta_window_size); | |
| 1317 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
| 1318 } | |
| 1319 | |
| 1320 void AdjustStreamSendWindowSize(const base::WeakPtr<SpdyStream>& stream, | |
| 1321 int32_t delta_window_size) { | |
| 1322 // Make sure that negative adjustments are handled properly. | |
| 1323 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
| 1324 stream->AdjustSendWindowSize(-delta_window_size); | |
| 1325 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
| 1326 stream->AdjustSendWindowSize(+delta_window_size); | |
| 1327 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
| 1328 stream->AdjustSendWindowSize(+delta_window_size); | |
| 1329 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
| 1330 } | |
| 1331 | |
| 1332 // Given an unstall function, runs a test to make sure that a | |
| 1333 // request/response (i.e., an HTTP-like) stream resumes after a stall | |
| 1334 // and unstall. | |
| 1335 void SpdyStreamTest::RunResumeAfterUnstallRequestResponseTest( | |
| 1336 const UnstallFunction& unstall_function) { | |
| 1337 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
| 1338 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
| 1339 AddWrite(req); | |
| 1340 | |
| 1341 SpdySerializedFrame body( | |
| 1342 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, true)); | |
| 1343 AddWrite(body); | |
| 1344 | |
| 1345 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
| 1346 AddRead(resp); | |
| 1347 | |
| 1348 AddReadEOF(); | |
| 1349 | |
| 1350 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 1351 GetNumWrites()); | |
| 1352 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 1353 data.set_connect_data(connect_data); | |
| 1354 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1355 | |
| 1356 AddSSLSocketData(); | |
| 1357 | |
| 1358 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 1359 | |
| 1360 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 1361 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 1362 ASSERT_TRUE(stream); | |
| 1363 | |
| 1364 StreamDelegateWithBody delegate(stream, kPostBodyStringPiece); | |
| 1365 stream->SetDelegate(&delegate); | |
| 1366 | |
| 1367 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 1368 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
| 1369 | |
| 1370 SpdyHeaderBlock headers( | |
| 1371 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
| 1372 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
| 1373 IsError(ERR_IO_PENDING)); | |
| 1374 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 1375 | |
| 1376 StallStream(stream); | |
| 1377 | |
| 1378 base::RunLoop().RunUntilIdle(); | |
| 1379 | |
| 1380 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
| 1381 | |
| 1382 unstall_function.Run(stream, kPostBodyLength); | |
| 1383 | |
| 1384 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
| 1385 | |
| 1386 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
| 1387 | |
| 1388 EXPECT_TRUE(delegate.send_headers_completed()); | |
| 1389 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status")); | |
| 1390 EXPECT_EQ(SpdyString(), delegate.TakeReceivedData()); | |
| 1391 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 1392 } | |
| 1393 | |
| 1394 TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) { | |
| 1395 RunResumeAfterUnstallRequestResponseTest( | |
| 1396 base::Bind(&IncreaseStreamSendWindowSize)); | |
| 1397 } | |
| 1398 | |
| 1399 TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) { | |
| 1400 RunResumeAfterUnstallRequestResponseTest( | |
| 1401 base::Bind(&AdjustStreamSendWindowSize)); | |
| 1402 } | |
| 1403 | |
| 1404 // Given an unstall function, runs a test to make sure that a bidirectional | |
| 1405 // (i.e., non-HTTP-like) stream resumes after a stall and unstall. | |
| 1406 void SpdyStreamTest::RunResumeAfterUnstallBidirectionalTest( | |
| 1407 const UnstallFunction& unstall_function) { | |
| 1408 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost( | |
| 1409 kDefaultUrl, 1, kPostBodyLength, LOWEST, nullptr, 0)); | |
| 1410 AddWrite(req); | |
| 1411 | |
| 1412 AddReadPause(); | |
| 1413 | |
| 1414 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
| 1415 AddRead(resp); | |
| 1416 | |
| 1417 SpdySerializedFrame msg( | |
| 1418 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
| 1419 AddWrite(msg); | |
| 1420 | |
| 1421 SpdySerializedFrame echo( | |
| 1422 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
| 1423 AddRead(echo); | |
| 1424 | |
| 1425 AddReadEOF(); | |
| 1426 | |
| 1427 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 1428 GetNumWrites()); | |
| 1429 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 1430 data.set_connect_data(connect_data); | |
| 1431 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1432 | |
| 1433 AddSSLSocketData(); | |
| 1434 | |
| 1435 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 1436 | |
| 1437 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 1438 SPDY_BIDIRECTIONAL_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 1439 ASSERT_TRUE(stream); | |
| 1440 | |
| 1441 StreamDelegateSendImmediate delegate(stream, kPostBodyStringPiece); | |
| 1442 stream->SetDelegate(&delegate); | |
| 1443 | |
| 1444 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 1445 | |
| 1446 SpdyHeaderBlock headers( | |
| 1447 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kPostBodyLength)); | |
| 1448 EXPECT_THAT(stream->SendRequestHeaders(std::move(headers), MORE_DATA_TO_SEND), | |
| 1449 IsError(ERR_IO_PENDING)); | |
| 1450 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 1451 | |
| 1452 data.RunUntilPaused(); | |
| 1453 | |
| 1454 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
| 1455 | |
| 1456 StallStream(stream); | |
| 1457 | |
| 1458 data.Resume(); | |
| 1459 base::RunLoop().RunUntilIdle(); | |
| 1460 | |
| 1461 EXPECT_TRUE(stream->send_stalled_by_flow_control()); | |
| 1462 | |
| 1463 unstall_function.Run(stream, kPostBodyLength); | |
| 1464 | |
| 1465 EXPECT_FALSE(stream->send_stalled_by_flow_control()); | |
| 1466 | |
| 1467 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
| 1468 | |
| 1469 EXPECT_TRUE(delegate.send_headers_completed()); | |
| 1470 EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status")); | |
| 1471 EXPECT_EQ(SpdyString(kPostBody, kPostBodyLength), | |
| 1472 delegate.TakeReceivedData()); | |
| 1473 EXPECT_TRUE(data.AllWriteDataConsumed()); | |
| 1474 } | |
| 1475 | |
| 1476 TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) { | |
| 1477 RunResumeAfterUnstallBidirectionalTest( | |
| 1478 base::Bind(&IncreaseStreamSendWindowSize)); | |
| 1479 } | |
| 1480 | |
| 1481 TEST_F(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) { | |
| 1482 RunResumeAfterUnstallBidirectionalTest( | |
| 1483 base::Bind(&AdjustStreamSendWindowSize)); | |
| 1484 } | |
| 1485 | |
| 1486 // Test calculation of amount of bytes received from network. | |
| 1487 TEST_F(SpdyStreamTest, ReceivedBytes) { | |
| 1488 SpdySerializedFrame req( | |
| 1489 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); | |
| 1490 AddWrite(req); | |
| 1491 | |
| 1492 AddReadPause(); | |
| 1493 | |
| 1494 SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); | |
| 1495 AddRead(reply); | |
| 1496 | |
| 1497 AddReadPause(); | |
| 1498 | |
| 1499 SpdySerializedFrame msg( | |
| 1500 spdy_util_.ConstructSpdyDataFrame(1, kPostBody, kPostBodyLength, false)); | |
| 1501 AddRead(msg); | |
| 1502 | |
| 1503 AddReadPause(); | |
| 1504 | |
| 1505 AddReadEOF(); | |
| 1506 | |
| 1507 SequencedSocketData data(GetReads(), GetNumReads(), GetWrites(), | |
| 1508 GetNumWrites()); | |
| 1509 MockConnect connect_data(SYNCHRONOUS, OK); | |
| 1510 data.set_connect_data(connect_data); | |
| 1511 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1512 | |
| 1513 AddSSLSocketData(); | |
| 1514 | |
| 1515 base::WeakPtr<SpdySession> session(CreateDefaultSpdySession()); | |
| 1516 | |
| 1517 base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously( | |
| 1518 SPDY_REQUEST_RESPONSE_STREAM, session, url_, LOWEST, NetLogWithSource()); | |
| 1519 ASSERT_TRUE(stream); | |
| 1520 | |
| 1521 StreamDelegateDoNothing delegate(stream); | |
| 1522 stream->SetDelegate(&delegate); | |
| 1523 | |
| 1524 EXPECT_TRUE(stream->GetUrlFromHeaders().is_empty()); | |
| 1525 | |
| 1526 SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); | |
| 1527 EXPECT_THAT( | |
| 1528 stream->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND), | |
| 1529 IsError(ERR_IO_PENDING)); | |
| 1530 EXPECT_EQ(kDefaultUrl, stream->GetUrlFromHeaders().spec()); | |
| 1531 | |
| 1532 int64_t reply_frame_len = reply.size(); | |
| 1533 int64_t data_header_len = kDataFrameMinimumSize; | |
| 1534 int64_t data_frame_len = data_header_len + kPostBodyLength; | |
| 1535 int64_t response_len = reply_frame_len + data_frame_len; | |
| 1536 | |
| 1537 EXPECT_EQ(0, stream->raw_received_bytes()); | |
| 1538 | |
| 1539 // REQUEST | |
| 1540 data.RunUntilPaused(); | |
| 1541 EXPECT_EQ(0, stream->raw_received_bytes()); | |
| 1542 | |
| 1543 // REPLY | |
| 1544 data.Resume(); | |
| 1545 data.RunUntilPaused(); | |
| 1546 EXPECT_EQ(reply_frame_len, stream->raw_received_bytes()); | |
| 1547 | |
| 1548 // DATA | |
| 1549 data.Resume(); | |
| 1550 data.RunUntilPaused(); | |
| 1551 EXPECT_EQ(response_len, stream->raw_received_bytes()); | |
| 1552 | |
| 1553 // FIN | |
| 1554 data.Resume(); | |
| 1555 EXPECT_THAT(delegate.WaitForClose(), IsError(ERR_CONNECTION_CLOSED)); | |
| 1556 } | |
| 1557 | |
| 1558 } // namespace test | |
| 1559 | |
| 1560 } // namespace net | |
| OLD | NEW |