| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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/http/http_pipelined_connection_impl.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/memory/ref_counted.h" | |
| 10 #include "base/memory/scoped_ptr.h" | |
| 11 #include "base/memory/scoped_vector.h" | |
| 12 #include "net/base/capturing_net_log.h" | |
| 13 #include "net/base/io_buffer.h" | |
| 14 #include "net/base/load_timing_info.h" | |
| 15 #include "net/base/load_timing_info_test_util.h" | |
| 16 #include "net/base/net_errors.h" | |
| 17 #include "net/base/request_priority.h" | |
| 18 #include "net/http/http_pipelined_stream.h" | |
| 19 #include "net/socket/client_socket_handle.h" | |
| 20 #include "net/socket/client_socket_pool_histograms.h" | |
| 21 #include "net/socket/socket_test_util.h" | |
| 22 #include "testing/gmock/include/gmock/gmock.h" | |
| 23 #include "testing/gtest/include/gtest/gtest.h" | |
| 24 | |
| 25 using testing::_; | |
| 26 using testing::NiceMock; | |
| 27 using testing::StrEq; | |
| 28 | |
| 29 namespace net { | |
| 30 | |
| 31 namespace { | |
| 32 | |
| 33 // Tests the load timing of a stream that's connected and is not the first | |
| 34 // request sent on a connection. | |
| 35 void TestLoadTimingReused(const HttpStream& stream) { | |
| 36 LoadTimingInfo load_timing_info; | |
| 37 EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info)); | |
| 38 | |
| 39 EXPECT_TRUE(load_timing_info.socket_reused); | |
| 40 EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id); | |
| 41 | |
| 42 ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); | |
| 43 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info); | |
| 44 } | |
| 45 | |
| 46 // Tests the load timing of a stream that's connected and using a fresh | |
| 47 // connection. | |
| 48 void TestLoadTimingNotReused(const HttpStream& stream) { | |
| 49 LoadTimingInfo load_timing_info; | |
| 50 EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info)); | |
| 51 | |
| 52 EXPECT_FALSE(load_timing_info.socket_reused); | |
| 53 EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id); | |
| 54 | |
| 55 ExpectConnectTimingHasTimes(load_timing_info.connect_timing, | |
| 56 CONNECT_TIMING_HAS_DNS_TIMES); | |
| 57 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info); | |
| 58 } | |
| 59 | |
| 60 class MockPipelineDelegate : public HttpPipelinedConnection::Delegate { | |
| 61 public: | |
| 62 MOCK_METHOD1(OnPipelineHasCapacity, void(HttpPipelinedConnection* pipeline)); | |
| 63 MOCK_METHOD2(OnPipelineFeedback, void( | |
| 64 HttpPipelinedConnection* pipeline, | |
| 65 HttpPipelinedConnection::Feedback feedback)); | |
| 66 }; | |
| 67 | |
| 68 class SuddenCloseObserver : public base::MessageLoop::TaskObserver { | |
| 69 public: | |
| 70 SuddenCloseObserver(HttpStream* stream, int close_before_task) | |
| 71 : stream_(stream), | |
| 72 close_before_task_(close_before_task), | |
| 73 current_task_(0) { } | |
| 74 | |
| 75 virtual void WillProcessTask(const base::PendingTask& pending_task) OVERRIDE { | |
| 76 ++current_task_; | |
| 77 if (current_task_ == close_before_task_) { | |
| 78 stream_->Close(false); | |
| 79 base::MessageLoop::current()->RemoveTaskObserver(this); | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 virtual void DidProcessTask(const base::PendingTask& pending_task) OVERRIDE {} | |
| 84 | |
| 85 private: | |
| 86 HttpStream* stream_; | |
| 87 int close_before_task_; | |
| 88 int current_task_; | |
| 89 }; | |
| 90 | |
| 91 class HttpPipelinedConnectionImplTest : public testing::Test { | |
| 92 public: | |
| 93 HttpPipelinedConnectionImplTest() | |
| 94 : histograms_("a"), | |
| 95 pool_(1, 1, &histograms_, &factory_), | |
| 96 origin_("host", 123) { | |
| 97 } | |
| 98 | |
| 99 void TearDown() { | |
| 100 base::MessageLoop::current()->RunUntilIdle(); | |
| 101 } | |
| 102 | |
| 103 void Initialize(MockRead* reads, size_t reads_count, | |
| 104 MockWrite* writes, size_t writes_count) { | |
| 105 data_.reset(new DeterministicSocketData(reads, reads_count, | |
| 106 writes, writes_count)); | |
| 107 data_->set_connect_data(MockConnect(SYNCHRONOUS, OK)); | |
| 108 if (reads_count || writes_count) { | |
| 109 data_->StopAfter(reads_count + writes_count); | |
| 110 } | |
| 111 factory_.AddSocketDataProvider(data_.get()); | |
| 112 scoped_refptr<MockTransportSocketParams> params; | |
| 113 ClientSocketHandle* connection = new ClientSocketHandle; | |
| 114 // Only give the connection a real NetLog to make sure that LoadTiming uses | |
| 115 // the connection's ID, rather than the pipeline's. Since pipelines are | |
| 116 // destroyed when they've responded to all requests, but the connection | |
| 117 // lives on, this is an important behavior. | |
| 118 connection->Init("a", params, MEDIUM, CompletionCallback(), &pool_, | |
| 119 net_log_.bound()); | |
| 120 pipeline_.reset(new HttpPipelinedConnectionImpl( | |
| 121 connection, &delegate_, origin_, ssl_config_, proxy_info_, | |
| 122 BoundNetLog(), false, kProtoUnknown)); | |
| 123 } | |
| 124 | |
| 125 HttpRequestInfo* GetRequestInfo(const std::string& filename) { | |
| 126 HttpRequestInfo* request_info = new HttpRequestInfo; | |
| 127 request_info->url = GURL("http://localhost/" + filename); | |
| 128 request_info->method = "GET"; | |
| 129 request_info_vector_.push_back(request_info); | |
| 130 return request_info; | |
| 131 } | |
| 132 | |
| 133 HttpStream* NewTestStream(const std::string& filename) { | |
| 134 HttpStream* stream = pipeline_->CreateNewStream(); | |
| 135 HttpRequestInfo* request_info = GetRequestInfo(filename); | |
| 136 int rv = stream->InitializeStream( | |
| 137 request_info, DEFAULT_PRIORITY, BoundNetLog(), CompletionCallback()); | |
| 138 DCHECK_EQ(OK, rv); | |
| 139 return stream; | |
| 140 } | |
| 141 | |
| 142 void ExpectResponse(const std::string& expected, | |
| 143 scoped_ptr<HttpStream>& stream, bool async) { | |
| 144 scoped_refptr<IOBuffer> buffer(new IOBuffer(expected.size())); | |
| 145 | |
| 146 if (async) { | |
| 147 EXPECT_EQ(ERR_IO_PENDING, | |
| 148 stream->ReadResponseBody(buffer.get(), expected.size(), | |
| 149 callback_.callback())); | |
| 150 data_->RunFor(1); | |
| 151 EXPECT_EQ(static_cast<int>(expected.size()), callback_.WaitForResult()); | |
| 152 } else { | |
| 153 EXPECT_EQ(static_cast<int>(expected.size()), | |
| 154 stream->ReadResponseBody(buffer.get(), expected.size(), | |
| 155 callback_.callback())); | |
| 156 } | |
| 157 std::string actual(buffer->data(), expected.size()); | |
| 158 EXPECT_THAT(actual, StrEq(expected)); | |
| 159 } | |
| 160 | |
| 161 void TestSyncRequest(scoped_ptr<HttpStream>& stream, | |
| 162 const std::string& filename) { | |
| 163 HttpRequestHeaders headers; | |
| 164 HttpResponseInfo response; | |
| 165 EXPECT_EQ(OK, stream->SendRequest(headers, &response, | |
| 166 callback_.callback())); | |
| 167 EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback())); | |
| 168 ExpectResponse(filename, stream, false); | |
| 169 | |
| 170 stream->Close(false); | |
| 171 } | |
| 172 | |
| 173 CapturingBoundNetLog net_log_; | |
| 174 DeterministicMockClientSocketFactory factory_; | |
| 175 ClientSocketPoolHistograms histograms_; | |
| 176 MockTransportClientSocketPool pool_; | |
| 177 scoped_ptr<DeterministicSocketData> data_; | |
| 178 | |
| 179 HostPortPair origin_; | |
| 180 SSLConfig ssl_config_; | |
| 181 ProxyInfo proxy_info_; | |
| 182 NiceMock<MockPipelineDelegate> delegate_; | |
| 183 TestCompletionCallback callback_; | |
| 184 scoped_ptr<HttpPipelinedConnectionImpl> pipeline_; | |
| 185 ScopedVector<HttpRequestInfo> request_info_vector_; | |
| 186 }; | |
| 187 | |
| 188 TEST_F(HttpPipelinedConnectionImplTest, PipelineNotUsed) { | |
| 189 Initialize(NULL, 0, NULL, 0); | |
| 190 } | |
| 191 | |
| 192 TEST_F(HttpPipelinedConnectionImplTest, StreamNotUsed) { | |
| 193 Initialize(NULL, 0, NULL, 0); | |
| 194 | |
| 195 scoped_ptr<HttpStream> stream(pipeline_->CreateNewStream()); | |
| 196 | |
| 197 stream->Close(false); | |
| 198 } | |
| 199 | |
| 200 TEST_F(HttpPipelinedConnectionImplTest, StreamBoundButNotUsed) { | |
| 201 Initialize(NULL, 0, NULL, 0); | |
| 202 | |
| 203 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 204 | |
| 205 TestLoadTimingNotReused(*stream); | |
| 206 stream->Close(false); | |
| 207 TestLoadTimingNotReused(*stream); | |
| 208 } | |
| 209 | |
| 210 TEST_F(HttpPipelinedConnectionImplTest, SyncSingleRequest) { | |
| 211 MockWrite writes[] = { | |
| 212 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 213 }; | |
| 214 MockRead reads[] = { | |
| 215 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
| 216 MockRead(SYNCHRONOUS, 2, "Content-Length: 7\r\n\r\n"), | |
| 217 MockRead(SYNCHRONOUS, 3, "ok.html"), | |
| 218 }; | |
| 219 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 220 | |
| 221 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 222 TestLoadTimingNotReused(*stream); | |
| 223 TestSyncRequest(stream, "ok.html"); | |
| 224 TestLoadTimingNotReused(*stream); | |
| 225 } | |
| 226 | |
| 227 TEST_F(HttpPipelinedConnectionImplTest, AsyncSingleRequest) { | |
| 228 MockWrite writes[] = { | |
| 229 MockWrite(ASYNC, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 230 }; | |
| 231 MockRead reads[] = { | |
| 232 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"), | |
| 233 MockRead(ASYNC, 2, "Content-Length: 7\r\n\r\n"), | |
| 234 MockRead(ASYNC, 3, "ok.html"), | |
| 235 }; | |
| 236 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 237 | |
| 238 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 239 | |
| 240 HttpRequestHeaders headers; | |
| 241 HttpResponseInfo response; | |
| 242 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(headers, &response, | |
| 243 callback_.callback())); | |
| 244 data_->RunFor(1); | |
| 245 EXPECT_LE(OK, callback_.WaitForResult()); | |
| 246 TestLoadTimingNotReused(*stream); | |
| 247 | |
| 248 EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | |
| 249 data_->RunFor(2); | |
| 250 EXPECT_LE(OK, callback_.WaitForResult()); | |
| 251 TestLoadTimingNotReused(*stream); | |
| 252 | |
| 253 ExpectResponse("ok.html", stream, true); | |
| 254 TestLoadTimingNotReused(*stream); | |
| 255 | |
| 256 stream->Close(false); | |
| 257 } | |
| 258 | |
| 259 TEST_F(HttpPipelinedConnectionImplTest, LockStepAsyncRequests) { | |
| 260 MockWrite writes[] = { | |
| 261 MockWrite(ASYNC, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 262 MockWrite(ASYNC, 1, "GET /ko.html HTTP/1.1\r\n\r\n"), | |
| 263 }; | |
| 264 MockRead reads[] = { | |
| 265 MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n"), | |
| 266 MockRead(ASYNC, 3, "Content-Length: 7\r\n\r\n"), | |
| 267 MockRead(ASYNC, 4, "ok.html"), | |
| 268 MockRead(ASYNC, 5, "HTTP/1.1 200 OK\r\n"), | |
| 269 MockRead(ASYNC, 6, "Content-Length: 7\r\n\r\n"), | |
| 270 MockRead(ASYNC, 7, "ko.html"), | |
| 271 }; | |
| 272 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 273 | |
| 274 scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); | |
| 275 scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); | |
| 276 | |
| 277 HttpRequestHeaders headers1; | |
| 278 HttpResponseInfo response1; | |
| 279 EXPECT_EQ(ERR_IO_PENDING, stream1->SendRequest(headers1, &response1, | |
| 280 callback_.callback())); | |
| 281 TestLoadTimingNotReused(*stream1); | |
| 282 | |
| 283 HttpRequestHeaders headers2; | |
| 284 HttpResponseInfo response2; | |
| 285 EXPECT_EQ(ERR_IO_PENDING, stream2->SendRequest(headers2, &response2, | |
| 286 callback_.callback())); | |
| 287 TestLoadTimingReused(*stream2); | |
| 288 | |
| 289 data_->RunFor(1); | |
| 290 EXPECT_LE(OK, callback_.WaitForResult()); | |
| 291 data_->RunFor(1); | |
| 292 EXPECT_LE(OK, callback_.WaitForResult()); | |
| 293 | |
| 294 EXPECT_EQ(ERR_IO_PENDING, stream1->ReadResponseHeaders(callback_.callback())); | |
| 295 EXPECT_EQ(ERR_IO_PENDING, stream2->ReadResponseHeaders(callback_.callback())); | |
| 296 | |
| 297 data_->RunFor(2); | |
| 298 EXPECT_LE(OK, callback_.WaitForResult()); | |
| 299 | |
| 300 ExpectResponse("ok.html", stream1, true); | |
| 301 | |
| 302 TestLoadTimingNotReused(*stream1); | |
| 303 LoadTimingInfo load_timing_info1; | |
| 304 EXPECT_TRUE(stream1->GetLoadTimingInfo(&load_timing_info1)); | |
| 305 stream1->Close(false); | |
| 306 | |
| 307 data_->RunFor(2); | |
| 308 EXPECT_LE(OK, callback_.WaitForResult()); | |
| 309 | |
| 310 ExpectResponse("ko.html", stream2, true); | |
| 311 | |
| 312 TestLoadTimingReused(*stream2); | |
| 313 LoadTimingInfo load_timing_info2; | |
| 314 EXPECT_TRUE(stream2->GetLoadTimingInfo(&load_timing_info2)); | |
| 315 EXPECT_EQ(load_timing_info1.socket_log_id, | |
| 316 load_timing_info2.socket_log_id); | |
| 317 stream2->Close(false); | |
| 318 } | |
| 319 | |
| 320 TEST_F(HttpPipelinedConnectionImplTest, TwoResponsesInOnePacket) { | |
| 321 MockWrite writes[] = { | |
| 322 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 323 MockWrite(SYNCHRONOUS, 1, "GET /ko.html HTTP/1.1\r\n\r\n"), | |
| 324 }; | |
| 325 MockRead reads[] = { | |
| 326 MockRead(SYNCHRONOUS, 2, | |
| 327 "HTTP/1.1 200 OK\r\n" | |
| 328 "Content-Length: 7\r\n\r\n" | |
| 329 "ok.html" | |
| 330 "HTTP/1.1 200 OK\r\n" | |
| 331 "Content-Length: 7\r\n\r\n" | |
| 332 "ko.html"), | |
| 333 }; | |
| 334 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 335 | |
| 336 scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); | |
| 337 scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); | |
| 338 | |
| 339 HttpRequestHeaders headers1; | |
| 340 HttpResponseInfo response1; | |
| 341 EXPECT_EQ(OK, stream1->SendRequest(headers1, | |
| 342 &response1, callback_.callback())); | |
| 343 HttpRequestHeaders headers2; | |
| 344 HttpResponseInfo response2; | |
| 345 EXPECT_EQ(OK, stream2->SendRequest(headers2, | |
| 346 &response2, callback_.callback())); | |
| 347 | |
| 348 EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | |
| 349 ExpectResponse("ok.html", stream1, false); | |
| 350 stream1->Close(false); | |
| 351 | |
| 352 EXPECT_EQ(OK, stream2->ReadResponseHeaders(callback_.callback())); | |
| 353 ExpectResponse("ko.html", stream2, false); | |
| 354 stream2->Close(false); | |
| 355 } | |
| 356 | |
| 357 TEST_F(HttpPipelinedConnectionImplTest, SendOrderSwapped) { | |
| 358 MockWrite writes[] = { | |
| 359 MockWrite(SYNCHRONOUS, 0, "GET /ko.html HTTP/1.1\r\n\r\n"), | |
| 360 MockWrite(SYNCHRONOUS, 4, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 361 }; | |
| 362 MockRead reads[] = { | |
| 363 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
| 364 MockRead(SYNCHRONOUS, 2, "Content-Length: 7\r\n\r\n"), | |
| 365 MockRead(SYNCHRONOUS, 3, "ko.html"), | |
| 366 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"), | |
| 367 MockRead(SYNCHRONOUS, 6, "Content-Length: 7\r\n\r\n"), | |
| 368 MockRead(SYNCHRONOUS, 7, "ok.html"), | |
| 369 }; | |
| 370 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 371 | |
| 372 scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); | |
| 373 scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); | |
| 374 | |
| 375 TestSyncRequest(stream2, "ko.html"); | |
| 376 TestSyncRequest(stream1, "ok.html"); | |
| 377 TestLoadTimingNotReused(*stream1); | |
| 378 TestLoadTimingReused(*stream2); | |
| 379 } | |
| 380 | |
| 381 TEST_F(HttpPipelinedConnectionImplTest, ReadOrderSwapped) { | |
| 382 MockWrite writes[] = { | |
| 383 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 384 MockWrite(SYNCHRONOUS, 1, "GET /ko.html HTTP/1.1\r\n\r\n"), | |
| 385 }; | |
| 386 MockRead reads[] = { | |
| 387 MockRead(SYNCHRONOUS, 2, "HTTP/1.1 200 OK\r\n"), | |
| 388 MockRead(SYNCHRONOUS, 3, "Content-Length: 7\r\n\r\n"), | |
| 389 MockRead(SYNCHRONOUS, 4, "ok.html"), | |
| 390 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"), | |
| 391 MockRead(SYNCHRONOUS, 6, "Content-Length: 7\r\n\r\n"), | |
| 392 MockRead(SYNCHRONOUS, 7, "ko.html"), | |
| 393 }; | |
| 394 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 395 | |
| 396 scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); | |
| 397 scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); | |
| 398 | |
| 399 HttpRequestHeaders headers1; | |
| 400 HttpResponseInfo response1; | |
| 401 EXPECT_EQ(OK, stream1->SendRequest(headers1, | |
| 402 &response1, callback_.callback())); | |
| 403 | |
| 404 HttpRequestHeaders headers2; | |
| 405 HttpResponseInfo response2; | |
| 406 EXPECT_EQ(OK, stream2->SendRequest(headers2, | |
| 407 &response2, callback_.callback())); | |
| 408 | |
| 409 EXPECT_EQ(ERR_IO_PENDING, stream2->ReadResponseHeaders(callback_.callback())); | |
| 410 | |
| 411 EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | |
| 412 ExpectResponse("ok.html", stream1, false); | |
| 413 | |
| 414 stream1->Close(false); | |
| 415 | |
| 416 EXPECT_LE(OK, callback_.WaitForResult()); | |
| 417 ExpectResponse("ko.html", stream2, false); | |
| 418 | |
| 419 stream2->Close(false); | |
| 420 } | |
| 421 | |
| 422 TEST_F(HttpPipelinedConnectionImplTest, SendWhileReading) { | |
| 423 MockWrite writes[] = { | |
| 424 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 425 MockWrite(SYNCHRONOUS, 3, "GET /ko.html HTTP/1.1\r\n\r\n"), | |
| 426 }; | |
| 427 MockRead reads[] = { | |
| 428 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
| 429 MockRead(SYNCHRONOUS, 2, "Content-Length: 7\r\n\r\n"), | |
| 430 MockRead(SYNCHRONOUS, 4, "ok.html"), | |
| 431 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"), | |
| 432 MockRead(SYNCHRONOUS, 6, "Content-Length: 7\r\n\r\n"), | |
| 433 MockRead(SYNCHRONOUS, 7, "ko.html"), | |
| 434 }; | |
| 435 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 436 | |
| 437 scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); | |
| 438 scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); | |
| 439 | |
| 440 HttpRequestHeaders headers1; | |
| 441 HttpResponseInfo response1; | |
| 442 EXPECT_EQ(OK, stream1->SendRequest(headers1, | |
| 443 &response1, callback_.callback())); | |
| 444 EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | |
| 445 | |
| 446 HttpRequestHeaders headers2; | |
| 447 HttpResponseInfo response2; | |
| 448 EXPECT_EQ(OK, stream2->SendRequest(headers2, | |
| 449 &response2, callback_.callback())); | |
| 450 | |
| 451 ExpectResponse("ok.html", stream1, false); | |
| 452 stream1->Close(false); | |
| 453 | |
| 454 EXPECT_EQ(OK, stream2->ReadResponseHeaders(callback_.callback())); | |
| 455 ExpectResponse("ko.html", stream2, false); | |
| 456 stream2->Close(false); | |
| 457 } | |
| 458 | |
| 459 TEST_F(HttpPipelinedConnectionImplTest, AsyncSendWhileAsyncReadBlocked) { | |
| 460 MockWrite writes[] = { | |
| 461 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 462 MockWrite(ASYNC, 3, "GET /ko.html HTTP/1.1\r\n\r\n"), | |
| 463 }; | |
| 464 MockRead reads[] = { | |
| 465 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
| 466 MockRead(SYNCHRONOUS, 2, "Content-Length: 7\r\n\r\n"), | |
| 467 MockRead(ASYNC, 4, "ok.html"), | |
| 468 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"), | |
| 469 MockRead(SYNCHRONOUS, 6, "Content-Length: 7\r\n\r\n"), | |
| 470 MockRead(SYNCHRONOUS, 7, "ko.html"), | |
| 471 }; | |
| 472 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 473 | |
| 474 scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); | |
| 475 scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); | |
| 476 | |
| 477 HttpRequestHeaders headers1; | |
| 478 HttpResponseInfo response1; | |
| 479 EXPECT_EQ(OK, stream1->SendRequest(headers1, | |
| 480 &response1, callback_.callback())); | |
| 481 EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | |
| 482 TestCompletionCallback callback1; | |
| 483 std::string expected = "ok.html"; | |
| 484 scoped_refptr<IOBuffer> buffer(new IOBuffer(expected.size())); | |
| 485 EXPECT_EQ(ERR_IO_PENDING, | |
| 486 stream1->ReadResponseBody(buffer.get(), expected.size(), | |
| 487 callback1.callback())); | |
| 488 | |
| 489 HttpRequestHeaders headers2; | |
| 490 HttpResponseInfo response2; | |
| 491 TestCompletionCallback callback2; | |
| 492 EXPECT_EQ(ERR_IO_PENDING, stream2->SendRequest(headers2, &response2, | |
| 493 callback2.callback())); | |
| 494 | |
| 495 data_->RunFor(1); | |
| 496 EXPECT_LE(OK, callback2.WaitForResult()); | |
| 497 EXPECT_EQ(ERR_IO_PENDING, stream2->ReadResponseHeaders(callback2.callback())); | |
| 498 | |
| 499 data_->RunFor(1); | |
| 500 EXPECT_EQ(static_cast<int>(expected.size()), callback1.WaitForResult()); | |
| 501 std::string actual(buffer->data(), expected.size()); | |
| 502 EXPECT_THAT(actual, StrEq(expected)); | |
| 503 stream1->Close(false); | |
| 504 | |
| 505 data_->StopAfter(8); | |
| 506 EXPECT_LE(OK, callback2.WaitForResult()); | |
| 507 ExpectResponse("ko.html", stream2, false); | |
| 508 stream2->Close(false); | |
| 509 } | |
| 510 | |
| 511 TEST_F(HttpPipelinedConnectionImplTest, UnusedStreamAllowsLaterUse) { | |
| 512 MockWrite writes[] = { | |
| 513 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 514 }; | |
| 515 MockRead reads[] = { | |
| 516 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
| 517 MockRead(SYNCHRONOUS, 2, "Content-Length: 7\r\n\r\n"), | |
| 518 MockRead(SYNCHRONOUS, 3, "ok.html"), | |
| 519 }; | |
| 520 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 521 | |
| 522 scoped_ptr<HttpStream> unused_stream(NewTestStream("unused.html")); | |
| 523 unused_stream->Close(false); | |
| 524 | |
| 525 scoped_ptr<HttpStream> later_stream(NewTestStream("ok.html")); | |
| 526 TestSyncRequest(later_stream, "ok.html"); | |
| 527 } | |
| 528 | |
| 529 TEST_F(HttpPipelinedConnectionImplTest, UnsentStreamAllowsLaterUse) { | |
| 530 MockWrite writes[] = { | |
| 531 MockWrite(ASYNC, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 532 MockWrite(SYNCHRONOUS, 4, "GET /ko.html HTTP/1.1\r\n\r\n"), | |
| 533 }; | |
| 534 MockRead reads[] = { | |
| 535 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"), | |
| 536 MockRead(ASYNC, 2, "Content-Length: 7\r\n\r\n"), | |
| 537 MockRead(ASYNC, 3, "ok.html"), | |
| 538 MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"), | |
| 539 MockRead(SYNCHRONOUS, 6, "Content-Length: 7\r\n\r\n"), | |
| 540 MockRead(SYNCHRONOUS, 7, "ko.html"), | |
| 541 }; | |
| 542 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 543 | |
| 544 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 545 | |
| 546 HttpRequestHeaders headers; | |
| 547 HttpResponseInfo response; | |
| 548 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(headers, &response, | |
| 549 callback_.callback())); | |
| 550 | |
| 551 scoped_ptr<HttpStream> unsent_stream(NewTestStream("unsent.html")); | |
| 552 HttpRequestHeaders unsent_headers; | |
| 553 HttpResponseInfo unsent_response; | |
| 554 EXPECT_EQ(ERR_IO_PENDING, unsent_stream->SendRequest(unsent_headers, | |
| 555 &unsent_response, | |
| 556 callback_.callback())); | |
| 557 unsent_stream->Close(false); | |
| 558 | |
| 559 data_->RunFor(1); | |
| 560 EXPECT_LE(OK, callback_.WaitForResult()); | |
| 561 | |
| 562 EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); | |
| 563 data_->RunFor(2); | |
| 564 EXPECT_LE(OK, callback_.WaitForResult()); | |
| 565 | |
| 566 ExpectResponse("ok.html", stream, true); | |
| 567 | |
| 568 stream->Close(false); | |
| 569 | |
| 570 data_->StopAfter(8); | |
| 571 scoped_ptr<HttpStream> later_stream(NewTestStream("ko.html")); | |
| 572 TestSyncRequest(later_stream, "ko.html"); | |
| 573 } | |
| 574 | |
| 575 TEST_F(HttpPipelinedConnectionImplTest, FailedSend) { | |
| 576 MockWrite writes[] = { | |
| 577 MockWrite(ASYNC, ERR_FAILED), | |
| 578 }; | |
| 579 Initialize(NULL, 0, writes, arraysize(writes)); | |
| 580 | |
| 581 scoped_ptr<HttpStream> failed_stream(NewTestStream("ok.html")); | |
| 582 scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); | |
| 583 scoped_ptr<HttpStream> closed_stream(NewTestStream("closed.html")); | |
| 584 scoped_ptr<HttpStream> rejected_stream(NewTestStream("rejected.html")); | |
| 585 | |
| 586 HttpRequestHeaders headers; | |
| 587 HttpResponseInfo response; | |
| 588 TestCompletionCallback failed_callback; | |
| 589 EXPECT_EQ(ERR_IO_PENDING, | |
| 590 failed_stream->SendRequest(headers, &response, | |
| 591 failed_callback.callback())); | |
| 592 TestCompletionCallback evicted_callback; | |
| 593 EXPECT_EQ(ERR_IO_PENDING, | |
| 594 evicted_stream->SendRequest(headers, &response, | |
| 595 evicted_callback.callback())); | |
| 596 EXPECT_EQ(ERR_IO_PENDING, closed_stream->SendRequest(headers, &response, | |
| 597 callback_.callback())); | |
| 598 closed_stream->Close(false); | |
| 599 | |
| 600 data_->RunFor(1); | |
| 601 EXPECT_EQ(ERR_FAILED, failed_callback.WaitForResult()); | |
| 602 EXPECT_EQ(ERR_PIPELINE_EVICTION, evicted_callback.WaitForResult()); | |
| 603 EXPECT_EQ(ERR_PIPELINE_EVICTION, | |
| 604 rejected_stream->SendRequest(headers, &response, | |
| 605 callback_.callback())); | |
| 606 | |
| 607 failed_stream->Close(true); | |
| 608 evicted_stream->Close(true); | |
| 609 rejected_stream->Close(true); | |
| 610 } | |
| 611 | |
| 612 TEST_F(HttpPipelinedConnectionImplTest, ConnectionSuddenlyClosedAfterResponse) { | |
| 613 MockWrite writes[] = { | |
| 614 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 615 MockWrite(SYNCHRONOUS, 1, "GET /read_evicted.html HTTP/1.1\r\n\r\n"), | |
| 616 MockWrite(SYNCHRONOUS, 2, "GET /read_rejected.html HTTP/1.1\r\n\r\n"), | |
| 617 MockWrite(ASYNC, ERR_SOCKET_NOT_CONNECTED, 5), | |
| 618 }; | |
| 619 MockRead reads[] = { | |
| 620 MockRead(SYNCHRONOUS, 3, "HTTP/1.1 200 OK\r\n\r\n"), | |
| 621 MockRead(SYNCHRONOUS, 4, "ok.html"), | |
| 622 MockRead(ASYNC, OK, 6), // Connection closed message. Not read before the | |
| 623 // ERR_SOCKET_NOT_CONNECTED. | |
| 624 }; | |
| 625 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 626 | |
| 627 scoped_ptr<HttpStream> closed_stream(NewTestStream("ok.html")); | |
| 628 scoped_ptr<HttpStream> read_evicted_stream( | |
| 629 NewTestStream("read_evicted.html")); | |
| 630 scoped_ptr<HttpStream> read_rejected_stream( | |
| 631 NewTestStream("read_rejected.html")); | |
| 632 scoped_ptr<HttpStream> send_closed_stream( | |
| 633 NewTestStream("send_closed.html")); | |
| 634 scoped_ptr<HttpStream> send_evicted_stream( | |
| 635 NewTestStream("send_evicted.html")); | |
| 636 scoped_ptr<HttpStream> send_rejected_stream( | |
| 637 NewTestStream("send_rejected.html")); | |
| 638 | |
| 639 HttpRequestHeaders headers; | |
| 640 HttpResponseInfo response; | |
| 641 EXPECT_EQ(OK, closed_stream->SendRequest(headers, | |
| 642 &response, callback_.callback())); | |
| 643 EXPECT_EQ(OK, read_evicted_stream->SendRequest(headers, &response, | |
| 644 callback_.callback())); | |
| 645 EXPECT_EQ(OK, read_rejected_stream->SendRequest(headers, &response, | |
| 646 callback_.callback())); | |
| 647 TestCompletionCallback send_closed_callback; | |
| 648 EXPECT_EQ(ERR_IO_PENDING, | |
| 649 send_closed_stream->SendRequest(headers, &response, | |
| 650 send_closed_callback.callback())); | |
| 651 TestCompletionCallback send_evicted_callback; | |
| 652 EXPECT_EQ(ERR_IO_PENDING, | |
| 653 send_evicted_stream->SendRequest(headers, &response, | |
| 654 send_evicted_callback.callback())); | |
| 655 | |
| 656 TestCompletionCallback read_evicted_callback; | |
| 657 EXPECT_EQ(ERR_IO_PENDING, | |
| 658 read_evicted_stream->ReadResponseHeaders( | |
| 659 read_evicted_callback.callback())); | |
| 660 | |
| 661 EXPECT_EQ(OK, closed_stream->ReadResponseHeaders(callback_.callback())); | |
| 662 ExpectResponse("ok.html", closed_stream, false); | |
| 663 closed_stream->Close(true); | |
| 664 | |
| 665 EXPECT_EQ(ERR_PIPELINE_EVICTION, read_evicted_callback.WaitForResult()); | |
| 666 read_evicted_stream->Close(true); | |
| 667 | |
| 668 EXPECT_EQ(ERR_PIPELINE_EVICTION, | |
| 669 read_rejected_stream->ReadResponseHeaders(callback_.callback())); | |
| 670 read_rejected_stream->Close(true); | |
| 671 | |
| 672 data_->RunFor(1); | |
| 673 EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, send_closed_callback.WaitForResult()); | |
| 674 send_closed_stream->Close(true); | |
| 675 | |
| 676 EXPECT_EQ(ERR_PIPELINE_EVICTION, send_evicted_callback.WaitForResult()); | |
| 677 send_evicted_stream->Close(true); | |
| 678 | |
| 679 EXPECT_EQ(ERR_PIPELINE_EVICTION, | |
| 680 send_rejected_stream->SendRequest(headers, &response, | |
| 681 callback_.callback())); | |
| 682 send_rejected_stream->Close(true); | |
| 683 } | |
| 684 | |
| 685 TEST_F(HttpPipelinedConnectionImplTest, AbortWhileSending) { | |
| 686 MockWrite writes[] = { | |
| 687 MockWrite(ASYNC, 0, "GET /aborts.html HTTP/1.1\r\n\r\n"), | |
| 688 }; | |
| 689 Initialize(NULL, 0, writes, arraysize(writes)); | |
| 690 | |
| 691 scoped_ptr<HttpStream> aborted_stream(NewTestStream("aborts.html")); | |
| 692 scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); | |
| 693 | |
| 694 HttpRequestHeaders headers; | |
| 695 HttpResponseInfo response; | |
| 696 TestCompletionCallback aborted_callback; | |
| 697 EXPECT_EQ(ERR_IO_PENDING, | |
| 698 aborted_stream->SendRequest(headers, &response, | |
| 699 aborted_callback.callback())); | |
| 700 TestCompletionCallback evicted_callback; | |
| 701 EXPECT_EQ(ERR_IO_PENDING, | |
| 702 evicted_stream->SendRequest(headers, &response, | |
| 703 evicted_callback.callback())); | |
| 704 | |
| 705 aborted_stream->Close(true); | |
| 706 EXPECT_EQ(ERR_PIPELINE_EVICTION, evicted_callback.WaitForResult()); | |
| 707 evicted_stream->Close(true); | |
| 708 EXPECT_FALSE(aborted_callback.have_result()); | |
| 709 } | |
| 710 | |
| 711 TEST_F(HttpPipelinedConnectionImplTest, AbortWhileSendingSecondRequest) { | |
| 712 MockWrite writes[] = { | |
| 713 MockWrite(ASYNC, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 714 MockWrite(ASYNC, 1, "GET /aborts.html HTTP/1.1\r\n\r\n"), | |
| 715 }; | |
| 716 Initialize(NULL, 0, writes, arraysize(writes)); | |
| 717 | |
| 718 scoped_ptr<HttpStream> ok_stream(NewTestStream("ok.html")); | |
| 719 scoped_ptr<HttpStream> aborted_stream(NewTestStream("aborts.html")); | |
| 720 scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); | |
| 721 | |
| 722 HttpRequestHeaders headers; | |
| 723 HttpResponseInfo response; | |
| 724 TestCompletionCallback ok_callback; | |
| 725 EXPECT_EQ(ERR_IO_PENDING, ok_stream->SendRequest(headers, &response, | |
| 726 ok_callback.callback())); | |
| 727 TestCompletionCallback aborted_callback; | |
| 728 EXPECT_EQ(ERR_IO_PENDING, | |
| 729 aborted_stream->SendRequest(headers, &response, | |
| 730 aborted_callback.callback())); | |
| 731 TestCompletionCallback evicted_callback; | |
| 732 EXPECT_EQ(ERR_IO_PENDING, | |
| 733 evicted_stream->SendRequest(headers, &response, | |
| 734 evicted_callback.callback())); | |
| 735 | |
| 736 data_->RunFor(1); | |
| 737 EXPECT_LE(OK, ok_callback.WaitForResult()); | |
| 738 base::MessageLoop::current()->RunUntilIdle(); | |
| 739 aborted_stream->Close(true); | |
| 740 EXPECT_EQ(ERR_PIPELINE_EVICTION, evicted_callback.WaitForResult()); | |
| 741 evicted_stream->Close(true); | |
| 742 EXPECT_FALSE(aborted_callback.have_result()); | |
| 743 ok_stream->Close(true); | |
| 744 } | |
| 745 | |
| 746 TEST_F(HttpPipelinedConnectionImplTest, AbortWhileReadingHeaders) { | |
| 747 MockWrite writes[] = { | |
| 748 MockWrite(SYNCHRONOUS, 0, "GET /aborts.html HTTP/1.1\r\n\r\n"), | |
| 749 MockWrite(SYNCHRONOUS, 1, "GET /evicted.html HTTP/1.1\r\n\r\n"), | |
| 750 }; | |
| 751 MockRead reads[] = { | |
| 752 MockRead(ASYNC, ERR_FAILED, 2), | |
| 753 }; | |
| 754 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 755 | |
| 756 scoped_ptr<HttpStream> aborted_stream(NewTestStream("aborts.html")); | |
| 757 scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); | |
| 758 scoped_ptr<HttpStream> rejected_stream(NewTestStream("rejected.html")); | |
| 759 | |
| 760 HttpRequestHeaders headers; | |
| 761 HttpResponseInfo response; | |
| 762 EXPECT_EQ(OK, | |
| 763 aborted_stream->SendRequest(headers, &response, | |
| 764 callback_.callback())); | |
| 765 EXPECT_EQ(OK, | |
| 766 evicted_stream->SendRequest(headers, &response, | |
| 767 callback_.callback())); | |
| 768 | |
| 769 EXPECT_EQ(ERR_IO_PENDING, | |
| 770 aborted_stream->ReadResponseHeaders(callback_.callback())); | |
| 771 TestCompletionCallback evicted_callback; | |
| 772 EXPECT_EQ(ERR_IO_PENDING, | |
| 773 evicted_stream->ReadResponseHeaders(evicted_callback.callback())); | |
| 774 | |
| 775 aborted_stream->Close(true); | |
| 776 EXPECT_EQ(ERR_PIPELINE_EVICTION, evicted_callback.WaitForResult()); | |
| 777 evicted_stream->Close(true); | |
| 778 | |
| 779 EXPECT_EQ(ERR_PIPELINE_EVICTION, | |
| 780 rejected_stream->SendRequest(headers, &response, | |
| 781 callback_.callback())); | |
| 782 rejected_stream->Close(true); | |
| 783 } | |
| 784 | |
| 785 TEST_F(HttpPipelinedConnectionImplTest, PendingResponseAbandoned) { | |
| 786 MockWrite writes[] = { | |
| 787 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 788 MockWrite(SYNCHRONOUS, 1, "GET /abandoned.html HTTP/1.1\r\n\r\n"), | |
| 789 MockWrite(SYNCHRONOUS, 2, "GET /evicted.html HTTP/1.1\r\n\r\n"), | |
| 790 }; | |
| 791 MockRead reads[] = { | |
| 792 MockRead(SYNCHRONOUS, 3, "HTTP/1.1 200 OK\r\n"), | |
| 793 MockRead(SYNCHRONOUS, 4, "Content-Length: 7\r\n\r\n"), | |
| 794 MockRead(SYNCHRONOUS, 5, "ok.html"), | |
| 795 }; | |
| 796 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 797 | |
| 798 scoped_ptr<HttpStream> ok_stream(NewTestStream("ok.html")); | |
| 799 scoped_ptr<HttpStream> abandoned_stream(NewTestStream("abandoned.html")); | |
| 800 scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); | |
| 801 | |
| 802 HttpRequestHeaders headers; | |
| 803 HttpResponseInfo response; | |
| 804 EXPECT_EQ(OK, ok_stream->SendRequest(headers, &response, | |
| 805 callback_.callback())); | |
| 806 EXPECT_EQ(OK, abandoned_stream->SendRequest(headers, &response, | |
| 807 callback_.callback())); | |
| 808 EXPECT_EQ(OK, evicted_stream->SendRequest(headers, &response, | |
| 809 callback_.callback())); | |
| 810 | |
| 811 EXPECT_EQ(OK, ok_stream->ReadResponseHeaders(callback_.callback())); | |
| 812 TestCompletionCallback abandoned_callback; | |
| 813 EXPECT_EQ(ERR_IO_PENDING, abandoned_stream->ReadResponseHeaders( | |
| 814 abandoned_callback.callback())); | |
| 815 TestCompletionCallback evicted_callback; | |
| 816 EXPECT_EQ(ERR_IO_PENDING, | |
| 817 evicted_stream->ReadResponseHeaders(evicted_callback.callback())); | |
| 818 | |
| 819 abandoned_stream->Close(false); | |
| 820 | |
| 821 ExpectResponse("ok.html", ok_stream, false); | |
| 822 ok_stream->Close(false); | |
| 823 | |
| 824 EXPECT_EQ(ERR_PIPELINE_EVICTION, evicted_callback.WaitForResult()); | |
| 825 evicted_stream->Close(true); | |
| 826 EXPECT_FALSE(evicted_stream->IsConnectionReusable()); | |
| 827 } | |
| 828 | |
| 829 TEST_F(HttpPipelinedConnectionImplTest, DisconnectedAfterOneRequestRecovery) { | |
| 830 MockWrite writes[] = { | |
| 831 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 832 MockWrite(SYNCHRONOUS, 1, "GET /rejected.html HTTP/1.1\r\n\r\n"), | |
| 833 MockWrite(ASYNC, ERR_SOCKET_NOT_CONNECTED, 5), | |
| 834 MockWrite(SYNCHRONOUS, ERR_SOCKET_NOT_CONNECTED, 7), | |
| 835 }; | |
| 836 MockRead reads[] = { | |
| 837 MockRead(SYNCHRONOUS, 2, "HTTP/1.1 200 OK\r\n"), | |
| 838 MockRead(SYNCHRONOUS, 3, "Content-Length: 7\r\n\r\n"), | |
| 839 MockRead(SYNCHRONOUS, 4, "ok.html"), | |
| 840 MockRead(SYNCHRONOUS, ERR_SOCKET_NOT_CONNECTED, 6), | |
| 841 }; | |
| 842 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 843 | |
| 844 scoped_ptr<HttpStream> ok_stream(NewTestStream("ok.html")); | |
| 845 scoped_ptr<HttpStream> rejected_read_stream(NewTestStream("rejected.html")); | |
| 846 scoped_ptr<HttpStream> evicted_send_stream(NewTestStream("evicted.html")); | |
| 847 scoped_ptr<HttpStream> rejected_send_stream(NewTestStream("rejected.html")); | |
| 848 | |
| 849 HttpRequestHeaders headers; | |
| 850 HttpResponseInfo response; | |
| 851 EXPECT_EQ(OK, ok_stream->SendRequest(headers, | |
| 852 &response, callback_.callback())); | |
| 853 EXPECT_EQ(OK, rejected_read_stream->SendRequest(headers, &response, | |
| 854 callback_.callback())); | |
| 855 | |
| 856 EXPECT_EQ(OK, ok_stream->ReadResponseHeaders(callback_.callback())); | |
| 857 ExpectResponse("ok.html", ok_stream, false); | |
| 858 ok_stream->Close(false); | |
| 859 | |
| 860 TestCompletionCallback read_callback; | |
| 861 EXPECT_EQ(ERR_IO_PENDING, | |
| 862 evicted_send_stream->SendRequest(headers, &response, | |
| 863 read_callback.callback())); | |
| 864 data_->RunFor(1); | |
| 865 EXPECT_EQ(ERR_PIPELINE_EVICTION, read_callback.WaitForResult()); | |
| 866 | |
| 867 EXPECT_EQ(ERR_PIPELINE_EVICTION, | |
| 868 rejected_read_stream->ReadResponseHeaders(callback_.callback())); | |
| 869 EXPECT_EQ(ERR_PIPELINE_EVICTION, | |
| 870 rejected_send_stream->SendRequest(headers, &response, | |
| 871 callback_.callback())); | |
| 872 | |
| 873 rejected_read_stream->Close(true); | |
| 874 rejected_send_stream->Close(true); | |
| 875 } | |
| 876 | |
| 877 TEST_F(HttpPipelinedConnectionImplTest, DisconnectedPendingReadRecovery) { | |
| 878 MockWrite writes[] = { | |
| 879 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 880 MockWrite(SYNCHRONOUS, 1, "GET /evicted.html HTTP/1.1\r\n\r\n"), | |
| 881 }; | |
| 882 MockRead reads[] = { | |
| 883 MockRead(SYNCHRONOUS, 2, "HTTP/1.1 200 OK\r\n"), | |
| 884 MockRead(SYNCHRONOUS, 3, "Content-Length: 7\r\n\r\n"), | |
| 885 MockRead(SYNCHRONOUS, 4, "ok.html"), | |
| 886 MockRead(SYNCHRONOUS, ERR_SOCKET_NOT_CONNECTED, 5), | |
| 887 }; | |
| 888 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 889 | |
| 890 scoped_ptr<HttpStream> ok_stream(NewTestStream("ok.html")); | |
| 891 scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); | |
| 892 | |
| 893 HttpRequestHeaders headers; | |
| 894 HttpResponseInfo response; | |
| 895 EXPECT_EQ(OK, ok_stream->SendRequest(headers, | |
| 896 &response, callback_.callback())); | |
| 897 EXPECT_EQ(OK, evicted_stream->SendRequest(headers, &response, | |
| 898 callback_.callback())); | |
| 899 | |
| 900 EXPECT_EQ(OK, ok_stream->ReadResponseHeaders(callback_.callback())); | |
| 901 ExpectResponse("ok.html", ok_stream, false); | |
| 902 | |
| 903 TestCompletionCallback evicted_callback; | |
| 904 EXPECT_EQ(ERR_IO_PENDING, | |
| 905 evicted_stream->ReadResponseHeaders(evicted_callback.callback())); | |
| 906 | |
| 907 ok_stream->Close(false); | |
| 908 | |
| 909 EXPECT_EQ(ERR_PIPELINE_EVICTION, evicted_callback.WaitForResult()); | |
| 910 evicted_stream->Close(false); | |
| 911 } | |
| 912 | |
| 913 TEST_F(HttpPipelinedConnectionImplTest, CloseCalledBeforeNextReadLoop) { | |
| 914 MockWrite writes[] = { | |
| 915 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 916 MockWrite(SYNCHRONOUS, 1, "GET /evicted.html HTTP/1.1\r\n\r\n"), | |
| 917 }; | |
| 918 MockRead reads[] = { | |
| 919 MockRead(SYNCHRONOUS, 2, "HTTP/1.1 200 OK\r\n"), | |
| 920 MockRead(SYNCHRONOUS, 3, "Content-Length: 7\r\n\r\n"), | |
| 921 MockRead(SYNCHRONOUS, 4, "ok.html"), | |
| 922 MockRead(SYNCHRONOUS, ERR_SOCKET_NOT_CONNECTED, 5), | |
| 923 }; | |
| 924 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 925 | |
| 926 scoped_ptr<HttpStream> ok_stream(NewTestStream("ok.html")); | |
| 927 scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); | |
| 928 | |
| 929 HttpRequestHeaders headers; | |
| 930 HttpResponseInfo response; | |
| 931 EXPECT_EQ(OK, ok_stream->SendRequest(headers, | |
| 932 &response, callback_.callback())); | |
| 933 EXPECT_EQ(OK, evicted_stream->SendRequest(headers, &response, | |
| 934 callback_.callback())); | |
| 935 | |
| 936 EXPECT_EQ(OK, ok_stream->ReadResponseHeaders(callback_.callback())); | |
| 937 ExpectResponse("ok.html", ok_stream, false); | |
| 938 | |
| 939 TestCompletionCallback evicted_callback; | |
| 940 EXPECT_EQ(ERR_IO_PENDING, | |
| 941 evicted_stream->ReadResponseHeaders(evicted_callback.callback())); | |
| 942 | |
| 943 ok_stream->Close(false); | |
| 944 evicted_stream->Close(false); | |
| 945 } | |
| 946 | |
| 947 TEST_F(HttpPipelinedConnectionImplTest, CloseCalledBeforeReadCallback) { | |
| 948 MockWrite writes[] = { | |
| 949 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 950 MockWrite(SYNCHRONOUS, 1, "GET /evicted.html HTTP/1.1\r\n\r\n"), | |
| 951 }; | |
| 952 MockRead reads[] = { | |
| 953 MockRead(SYNCHRONOUS, 2, "HTTP/1.1 200 OK\r\n"), | |
| 954 MockRead(SYNCHRONOUS, 3, "Content-Length: 7\r\n\r\n"), | |
| 955 MockRead(SYNCHRONOUS, 4, "ok.html"), | |
| 956 MockRead(SYNCHRONOUS, ERR_SOCKET_NOT_CONNECTED, 5), | |
| 957 }; | |
| 958 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 959 | |
| 960 scoped_ptr<HttpStream> ok_stream(NewTestStream("ok.html")); | |
| 961 scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); | |
| 962 | |
| 963 HttpRequestHeaders headers; | |
| 964 HttpResponseInfo response; | |
| 965 EXPECT_EQ(OK, ok_stream->SendRequest(headers, | |
| 966 &response, callback_.callback())); | |
| 967 EXPECT_EQ(OK, evicted_stream->SendRequest(headers, &response, | |
| 968 callback_.callback())); | |
| 969 | |
| 970 EXPECT_EQ(OK, ok_stream->ReadResponseHeaders(callback_.callback())); | |
| 971 ExpectResponse("ok.html", ok_stream, false); | |
| 972 | |
| 973 TestCompletionCallback evicted_callback; | |
| 974 EXPECT_EQ(ERR_IO_PENDING, | |
| 975 evicted_stream->ReadResponseHeaders(evicted_callback.callback())); | |
| 976 | |
| 977 ok_stream->Close(false); | |
| 978 | |
| 979 // The posted tasks should be: | |
| 980 // 1. DoReadHeadersLoop, which will post: | |
| 981 // 2. InvokeUserCallback | |
| 982 SuddenCloseObserver observer(evicted_stream.get(), 2); | |
| 983 base::MessageLoop::current()->AddTaskObserver(&observer); | |
| 984 base::MessageLoop::current()->RunUntilIdle(); | |
| 985 EXPECT_FALSE(evicted_callback.have_result()); | |
| 986 } | |
| 987 | |
| 988 class StreamDeleter { | |
| 989 public: | |
| 990 StreamDeleter(HttpStream* stream) | |
| 991 : stream_(stream), | |
| 992 callback_(base::Bind(&StreamDeleter::OnIOComplete, | |
| 993 base::Unretained(this))) { | |
| 994 } | |
| 995 | |
| 996 ~StreamDeleter() { | |
| 997 EXPECT_FALSE(stream_); | |
| 998 } | |
| 999 | |
| 1000 const CompletionCallback& callback() { return callback_; } | |
| 1001 | |
| 1002 private: | |
| 1003 void OnIOComplete(int result) { | |
| 1004 stream_->Close(true); | |
| 1005 stream_.reset(); | |
| 1006 } | |
| 1007 | |
| 1008 scoped_ptr<HttpStream> stream_; | |
| 1009 CompletionCallback callback_; | |
| 1010 }; | |
| 1011 | |
| 1012 TEST_F(HttpPipelinedConnectionImplTest, CloseCalledDuringSendCallback) { | |
| 1013 MockWrite writes[] = { | |
| 1014 MockWrite(ASYNC, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1015 }; | |
| 1016 Initialize(NULL, 0, writes, arraysize(writes)); | |
| 1017 | |
| 1018 HttpStream* stream(NewTestStream("ok.html")); | |
| 1019 | |
| 1020 StreamDeleter deleter(stream); | |
| 1021 HttpRequestHeaders headers; | |
| 1022 HttpResponseInfo response; | |
| 1023 EXPECT_EQ(ERR_IO_PENDING, stream->SendRequest(headers, &response, | |
| 1024 deleter.callback())); | |
| 1025 data_->RunFor(1); | |
| 1026 } | |
| 1027 | |
| 1028 TEST_F(HttpPipelinedConnectionImplTest, CloseCalledDuringReadCallback) { | |
| 1029 MockWrite writes[] = { | |
| 1030 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1031 }; | |
| 1032 MockRead reads[] = { | |
| 1033 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
| 1034 MockRead(ASYNC, 2, "Content-Length: 7\r\n\r\n"), | |
| 1035 }; | |
| 1036 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1037 | |
| 1038 HttpStream* stream(NewTestStream("ok.html")); | |
| 1039 | |
| 1040 HttpRequestHeaders headers; | |
| 1041 HttpResponseInfo response; | |
| 1042 EXPECT_EQ(OK, stream->SendRequest(headers, | |
| 1043 &response, callback_.callback())); | |
| 1044 | |
| 1045 StreamDeleter deleter(stream); | |
| 1046 EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(deleter.callback())); | |
| 1047 data_->RunFor(1); | |
| 1048 } | |
| 1049 | |
| 1050 TEST_F(HttpPipelinedConnectionImplTest, | |
| 1051 CloseCalledDuringReadCallbackWithPendingRead) { | |
| 1052 MockWrite writes[] = { | |
| 1053 MockWrite(SYNCHRONOUS, 0, "GET /failed.html HTTP/1.1\r\n\r\n"), | |
| 1054 MockWrite(SYNCHRONOUS, 1, "GET /evicted.html HTTP/1.1\r\n\r\n"), | |
| 1055 }; | |
| 1056 MockRead reads[] = { | |
| 1057 MockRead(SYNCHRONOUS, 2, "HTTP/1.1 200 OK\r\n"), | |
| 1058 MockRead(ASYNC, 3, "Content-Length: 7\r\n\r\n"), | |
| 1059 }; | |
| 1060 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1061 | |
| 1062 HttpStream* failed_stream(NewTestStream("failed.html")); | |
| 1063 HttpStream* evicted_stream(NewTestStream("evicted.html")); | |
| 1064 | |
| 1065 HttpRequestHeaders headers; | |
| 1066 HttpResponseInfo response; | |
| 1067 EXPECT_EQ(OK, failed_stream->SendRequest(headers, &response, | |
| 1068 callback_.callback())); | |
| 1069 EXPECT_EQ(OK, evicted_stream->SendRequest(headers, &response, | |
| 1070 callback_.callback())); | |
| 1071 | |
| 1072 StreamDeleter failed_deleter(failed_stream); | |
| 1073 EXPECT_EQ(ERR_IO_PENDING, | |
| 1074 failed_stream->ReadResponseHeaders(failed_deleter.callback())); | |
| 1075 StreamDeleter evicted_deleter(evicted_stream); | |
| 1076 EXPECT_EQ(ERR_IO_PENDING, | |
| 1077 evicted_stream->ReadResponseHeaders(evicted_deleter.callback())); | |
| 1078 data_->RunFor(1); | |
| 1079 } | |
| 1080 | |
| 1081 TEST_F(HttpPipelinedConnectionImplTest, CloseOtherDuringReadCallback) { | |
| 1082 MockWrite writes[] = { | |
| 1083 MockWrite(SYNCHRONOUS, 0, "GET /deleter.html HTTP/1.1\r\n\r\n"), | |
| 1084 MockWrite(SYNCHRONOUS, 1, "GET /deleted.html HTTP/1.1\r\n\r\n"), | |
| 1085 }; | |
| 1086 MockRead reads[] = { | |
| 1087 MockRead(SYNCHRONOUS, 2, "HTTP/1.1 200 OK\r\n"), | |
| 1088 MockRead(ASYNC, 3, "Content-Length: 7\r\n\r\n"), | |
| 1089 }; | |
| 1090 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1091 | |
| 1092 scoped_ptr<HttpStream> deleter_stream(NewTestStream("deleter.html")); | |
| 1093 HttpStream* deleted_stream(NewTestStream("deleted.html")); | |
| 1094 | |
| 1095 HttpRequestHeaders headers; | |
| 1096 HttpResponseInfo response; | |
| 1097 EXPECT_EQ(OK, deleter_stream->SendRequest(headers, | |
| 1098 &response, callback_.callback())); | |
| 1099 EXPECT_EQ(OK, deleted_stream->SendRequest(headers, | |
| 1100 &response, callback_.callback())); | |
| 1101 | |
| 1102 StreamDeleter deleter(deleted_stream); | |
| 1103 EXPECT_EQ(ERR_IO_PENDING, | |
| 1104 deleter_stream->ReadResponseHeaders(deleter.callback())); | |
| 1105 EXPECT_EQ(ERR_IO_PENDING, | |
| 1106 deleted_stream->ReadResponseHeaders(callback_.callback())); | |
| 1107 data_->RunFor(1); | |
| 1108 } | |
| 1109 | |
| 1110 TEST_F(HttpPipelinedConnectionImplTest, CloseBeforeSendCallbackRuns) { | |
| 1111 MockWrite writes[] = { | |
| 1112 MockWrite(ASYNC, 0, "GET /close.html HTTP/1.1\r\n\r\n"), | |
| 1113 MockWrite(ASYNC, 1, "GET /dummy.html HTTP/1.1\r\n\r\n"), | |
| 1114 }; | |
| 1115 Initialize(NULL, 0, writes, arraysize(writes)); | |
| 1116 | |
| 1117 scoped_ptr<HttpStream> close_stream(NewTestStream("close.html")); | |
| 1118 scoped_ptr<HttpStream> dummy_stream(NewTestStream("dummy.html")); | |
| 1119 | |
| 1120 scoped_ptr<TestCompletionCallback> close_callback( | |
| 1121 new TestCompletionCallback); | |
| 1122 HttpRequestHeaders headers; | |
| 1123 HttpResponseInfo response; | |
| 1124 EXPECT_EQ(ERR_IO_PENDING, | |
| 1125 close_stream->SendRequest(headers, | |
| 1126 &response, close_callback->callback())); | |
| 1127 | |
| 1128 data_->RunFor(1); | |
| 1129 EXPECT_FALSE(close_callback->have_result()); | |
| 1130 | |
| 1131 close_stream->Close(false); | |
| 1132 close_stream.reset(); | |
| 1133 close_callback.reset(); | |
| 1134 | |
| 1135 base::MessageLoop::current()->RunUntilIdle(); | |
| 1136 } | |
| 1137 | |
| 1138 TEST_F(HttpPipelinedConnectionImplTest, CloseBeforeReadCallbackRuns) { | |
| 1139 MockWrite writes[] = { | |
| 1140 MockWrite(SYNCHRONOUS, 0, "GET /close.html HTTP/1.1\r\n\r\n"), | |
| 1141 MockWrite(SYNCHRONOUS, 3, "GET /dummy.html HTTP/1.1\r\n\r\n"), | |
| 1142 }; | |
| 1143 MockRead reads[] = { | |
| 1144 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
| 1145 MockRead(ASYNC, 2, "Content-Length: 7\r\n\r\n"), | |
| 1146 }; | |
| 1147 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1148 | |
| 1149 scoped_ptr<HttpStream> close_stream(NewTestStream("close.html")); | |
| 1150 scoped_ptr<HttpStream> dummy_stream(NewTestStream("dummy.html")); | |
| 1151 | |
| 1152 HttpRequestHeaders headers; | |
| 1153 HttpResponseInfo response; | |
| 1154 EXPECT_EQ(OK, close_stream->SendRequest(headers, | |
| 1155 &response, callback_.callback())); | |
| 1156 | |
| 1157 scoped_ptr<TestCompletionCallback> close_callback( | |
| 1158 new TestCompletionCallback); | |
| 1159 EXPECT_EQ(ERR_IO_PENDING, | |
| 1160 close_stream->ReadResponseHeaders(close_callback->callback())); | |
| 1161 | |
| 1162 data_->RunFor(1); | |
| 1163 EXPECT_FALSE(close_callback->have_result()); | |
| 1164 | |
| 1165 close_stream->Close(false); | |
| 1166 close_stream.reset(); | |
| 1167 close_callback.reset(); | |
| 1168 | |
| 1169 base::MessageLoop::current()->RunUntilIdle(); | |
| 1170 } | |
| 1171 | |
| 1172 TEST_F(HttpPipelinedConnectionImplTest, AbortWhileSendQueued) { | |
| 1173 MockWrite writes[] = { | |
| 1174 MockWrite(ASYNC, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1175 MockWrite(ASYNC, 1, "GET /ko.html HTTP/1.1\r\n\r\n"), | |
| 1176 }; | |
| 1177 Initialize(NULL, 0, writes, arraysize(writes)); | |
| 1178 | |
| 1179 scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); | |
| 1180 scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); | |
| 1181 | |
| 1182 HttpRequestHeaders headers1; | |
| 1183 HttpResponseInfo response1; | |
| 1184 TestCompletionCallback callback1; | |
| 1185 EXPECT_EQ(ERR_IO_PENDING, stream1->SendRequest(headers1, &response1, | |
| 1186 callback1.callback())); | |
| 1187 | |
| 1188 HttpRequestHeaders headers2; | |
| 1189 HttpResponseInfo response2; | |
| 1190 TestCompletionCallback callback2; | |
| 1191 EXPECT_EQ(ERR_IO_PENDING, stream2->SendRequest(headers2, &response2, | |
| 1192 callback2.callback())); | |
| 1193 | |
| 1194 stream2.reset(); | |
| 1195 stream1->Close(true); | |
| 1196 | |
| 1197 EXPECT_FALSE(callback2.have_result()); | |
| 1198 } | |
| 1199 | |
| 1200 TEST_F(HttpPipelinedConnectionImplTest, NoGapBetweenCloseAndEviction) { | |
| 1201 MockWrite writes[] = { | |
| 1202 MockWrite(SYNCHRONOUS, 0, "GET /close.html HTTP/1.1\r\n\r\n"), | |
| 1203 MockWrite(SYNCHRONOUS, 2, "GET /dummy.html HTTP/1.1\r\n\r\n"), | |
| 1204 }; | |
| 1205 MockRead reads[] = { | |
| 1206 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
| 1207 MockRead(ASYNC, 3, "Content-Length: 7\r\n\r\n"), | |
| 1208 }; | |
| 1209 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1210 | |
| 1211 scoped_ptr<HttpStream> close_stream(NewTestStream("close.html")); | |
| 1212 scoped_ptr<HttpStream> dummy_stream(NewTestStream("dummy.html")); | |
| 1213 | |
| 1214 HttpRequestHeaders headers; | |
| 1215 HttpResponseInfo response; | |
| 1216 EXPECT_EQ(OK, close_stream->SendRequest(headers, &response, | |
| 1217 callback_.callback())); | |
| 1218 | |
| 1219 TestCompletionCallback close_callback; | |
| 1220 EXPECT_EQ(ERR_IO_PENDING, | |
| 1221 close_stream->ReadResponseHeaders(close_callback.callback())); | |
| 1222 | |
| 1223 EXPECT_EQ(OK, dummy_stream->SendRequest(headers, &response, | |
| 1224 callback_.callback())); | |
| 1225 | |
| 1226 TestCompletionCallback dummy_callback; | |
| 1227 EXPECT_EQ(ERR_IO_PENDING, | |
| 1228 dummy_stream->ReadResponseHeaders(dummy_callback.callback())); | |
| 1229 | |
| 1230 close_stream->Close(true); | |
| 1231 close_stream.reset(); | |
| 1232 | |
| 1233 EXPECT_TRUE(dummy_callback.have_result()); | |
| 1234 EXPECT_EQ(ERR_PIPELINE_EVICTION, dummy_callback.WaitForResult()); | |
| 1235 dummy_stream->Close(true); | |
| 1236 dummy_stream.reset(); | |
| 1237 pipeline_.reset(); | |
| 1238 } | |
| 1239 | |
| 1240 TEST_F(HttpPipelinedConnectionImplTest, RecoverFromDrainOnRedirect) { | |
| 1241 MockWrite writes[] = { | |
| 1242 MockWrite(SYNCHRONOUS, 0, "GET /redirect.html HTTP/1.1\r\n\r\n"), | |
| 1243 MockWrite(SYNCHRONOUS, 1, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1244 }; | |
| 1245 MockRead reads[] = { | |
| 1246 MockRead(SYNCHRONOUS, 2, | |
| 1247 "HTTP/1.1 302 OK\r\n" | |
| 1248 "Content-Length: 8\r\n\r\n" | |
| 1249 "redirect"), | |
| 1250 MockRead(SYNCHRONOUS, 3, | |
| 1251 "HTTP/1.1 200 OK\r\n" | |
| 1252 "Content-Length: 7\r\n\r\n" | |
| 1253 "ok.html"), | |
| 1254 }; | |
| 1255 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1256 | |
| 1257 scoped_ptr<HttpStream> stream1(NewTestStream("redirect.html")); | |
| 1258 scoped_ptr<HttpStream> stream2(NewTestStream("ok.html")); | |
| 1259 | |
| 1260 HttpRequestHeaders headers1; | |
| 1261 HttpResponseInfo response1; | |
| 1262 EXPECT_EQ(OK, stream1->SendRequest(headers1, | |
| 1263 &response1, callback_.callback())); | |
| 1264 HttpRequestHeaders headers2; | |
| 1265 HttpResponseInfo response2; | |
| 1266 EXPECT_EQ(OK, stream2->SendRequest(headers2, | |
| 1267 &response2, callback_.callback())); | |
| 1268 | |
| 1269 EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | |
| 1270 stream1.release()->Drain(NULL); | |
| 1271 | |
| 1272 EXPECT_EQ(OK, stream2->ReadResponseHeaders(callback_.callback())); | |
| 1273 ExpectResponse("ok.html", stream2, false); | |
| 1274 stream2->Close(false); | |
| 1275 } | |
| 1276 | |
| 1277 TEST_F(HttpPipelinedConnectionImplTest, EvictAfterDrainOfUnknownSize) { | |
| 1278 MockWrite writes[] = { | |
| 1279 MockWrite(SYNCHRONOUS, 0, "GET /redirect.html HTTP/1.1\r\n\r\n"), | |
| 1280 MockWrite(SYNCHRONOUS, 1, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1281 }; | |
| 1282 MockRead reads[] = { | |
| 1283 MockRead(SYNCHRONOUS, 2, | |
| 1284 "HTTP/1.1 302 OK\r\n\r\n" | |
| 1285 "redirect"), | |
| 1286 }; | |
| 1287 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1288 | |
| 1289 scoped_ptr<HttpStream> stream1(NewTestStream("redirect.html")); | |
| 1290 scoped_ptr<HttpStream> stream2(NewTestStream("ok.html")); | |
| 1291 | |
| 1292 HttpRequestHeaders headers1; | |
| 1293 HttpResponseInfo response1; | |
| 1294 EXPECT_EQ(OK, stream1->SendRequest(headers1, | |
| 1295 &response1, callback_.callback())); | |
| 1296 HttpRequestHeaders headers2; | |
| 1297 HttpResponseInfo response2; | |
| 1298 EXPECT_EQ(OK, stream2->SendRequest(headers2, | |
| 1299 &response2, callback_.callback())); | |
| 1300 | |
| 1301 EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | |
| 1302 stream1.release()->Drain(NULL); | |
| 1303 | |
| 1304 EXPECT_EQ(ERR_PIPELINE_EVICTION, | |
| 1305 stream2->ReadResponseHeaders(callback_.callback())); | |
| 1306 stream2->Close(false); | |
| 1307 } | |
| 1308 | |
| 1309 TEST_F(HttpPipelinedConnectionImplTest, EvictAfterFailedDrain) { | |
| 1310 MockWrite writes[] = { | |
| 1311 MockWrite(SYNCHRONOUS, 0, "GET /redirect.html HTTP/1.1\r\n\r\n"), | |
| 1312 MockWrite(SYNCHRONOUS, 1, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1313 }; | |
| 1314 MockRead reads[] = { | |
| 1315 MockRead(SYNCHRONOUS, 2, | |
| 1316 "HTTP/1.1 302 OK\r\n" | |
| 1317 "Content-Length: 8\r\n\r\n"), | |
| 1318 MockRead(SYNCHRONOUS, ERR_SOCKET_NOT_CONNECTED, 3), | |
| 1319 }; | |
| 1320 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1321 | |
| 1322 scoped_ptr<HttpStream> stream1(NewTestStream("redirect.html")); | |
| 1323 scoped_ptr<HttpStream> stream2(NewTestStream("ok.html")); | |
| 1324 | |
| 1325 HttpRequestHeaders headers1; | |
| 1326 HttpResponseInfo response1; | |
| 1327 EXPECT_EQ(OK, stream1->SendRequest(headers1, | |
| 1328 &response1, callback_.callback())); | |
| 1329 HttpRequestHeaders headers2; | |
| 1330 HttpResponseInfo response2; | |
| 1331 EXPECT_EQ(OK, stream2->SendRequest(headers2, | |
| 1332 &response2, callback_.callback())); | |
| 1333 | |
| 1334 | |
| 1335 EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | |
| 1336 stream1.release()->Drain(NULL); | |
| 1337 | |
| 1338 EXPECT_EQ(ERR_PIPELINE_EVICTION, | |
| 1339 stream2->ReadResponseHeaders(callback_.callback())); | |
| 1340 stream2->Close(false); | |
| 1341 } | |
| 1342 | |
| 1343 TEST_F(HttpPipelinedConnectionImplTest, EvictIfDrainingChunkedEncoding) { | |
| 1344 MockWrite writes[] = { | |
| 1345 MockWrite(SYNCHRONOUS, 0, "GET /redirect.html HTTP/1.1\r\n\r\n"), | |
| 1346 MockWrite(SYNCHRONOUS, 1, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1347 }; | |
| 1348 MockRead reads[] = { | |
| 1349 MockRead(SYNCHRONOUS, 2, | |
| 1350 "HTTP/1.1 302 OK\r\n" | |
| 1351 "Transfer-Encoding: chunked\r\n\r\n"), | |
| 1352 MockRead(SYNCHRONOUS, 3, | |
| 1353 "jibberish"), | |
| 1354 }; | |
| 1355 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1356 | |
| 1357 scoped_ptr<HttpStream> stream1(NewTestStream("redirect.html")); | |
| 1358 scoped_ptr<HttpStream> stream2(NewTestStream("ok.html")); | |
| 1359 | |
| 1360 HttpRequestHeaders headers1; | |
| 1361 HttpResponseInfo response1; | |
| 1362 EXPECT_EQ(OK, stream1->SendRequest(headers1, | |
| 1363 &response1, callback_.callback())); | |
| 1364 HttpRequestHeaders headers2; | |
| 1365 HttpResponseInfo response2; | |
| 1366 EXPECT_EQ(OK, stream2->SendRequest(headers2, | |
| 1367 &response2, callback_.callback())); | |
| 1368 | |
| 1369 | |
| 1370 EXPECT_EQ(OK, stream1->ReadResponseHeaders(callback_.callback())); | |
| 1371 stream1.release()->Drain(NULL); | |
| 1372 | |
| 1373 EXPECT_EQ(ERR_PIPELINE_EVICTION, | |
| 1374 stream2->ReadResponseHeaders(callback_.callback())); | |
| 1375 stream2->Close(false); | |
| 1376 } | |
| 1377 | |
| 1378 TEST_F(HttpPipelinedConnectionImplTest, EvictionDueToMissingContentLength) { | |
| 1379 MockWrite writes[] = { | |
| 1380 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1381 MockWrite(SYNCHRONOUS, 1, "GET /evicted.html HTTP/1.1\r\n\r\n"), | |
| 1382 MockWrite(SYNCHRONOUS, 2, "GET /rejected.html HTTP/1.1\r\n\r\n"), | |
| 1383 }; | |
| 1384 MockRead reads[] = { | |
| 1385 MockRead(ASYNC, 3, "HTTP/1.1 200 OK\r\n\r\n"), | |
| 1386 MockRead(SYNCHRONOUS, 4, "ok.html"), | |
| 1387 MockRead(SYNCHRONOUS, OK, 5), | |
| 1388 }; | |
| 1389 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1390 | |
| 1391 scoped_ptr<HttpStream> ok_stream(NewTestStream("ok.html")); | |
| 1392 scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); | |
| 1393 scoped_ptr<HttpStream> rejected_stream(NewTestStream("rejected.html")); | |
| 1394 | |
| 1395 HttpRequestHeaders headers; | |
| 1396 HttpResponseInfo response; | |
| 1397 EXPECT_EQ(OK, ok_stream->SendRequest(headers, | |
| 1398 &response, callback_.callback())); | |
| 1399 EXPECT_EQ(OK, evicted_stream->SendRequest(headers, | |
| 1400 &response, callback_.callback())); | |
| 1401 EXPECT_EQ(OK, rejected_stream->SendRequest(headers, | |
| 1402 &response, callback_.callback())); | |
| 1403 | |
| 1404 TestCompletionCallback ok_callback; | |
| 1405 EXPECT_EQ(ERR_IO_PENDING, | |
| 1406 ok_stream->ReadResponseHeaders(ok_callback.callback())); | |
| 1407 | |
| 1408 TestCompletionCallback evicted_callback; | |
| 1409 EXPECT_EQ(ERR_IO_PENDING, | |
| 1410 evicted_stream->ReadResponseHeaders(evicted_callback.callback())); | |
| 1411 | |
| 1412 data_->RunFor(1); | |
| 1413 EXPECT_LE(OK, ok_callback.WaitForResult()); | |
| 1414 data_->StopAfter(10); | |
| 1415 | |
| 1416 ExpectResponse("ok.html", ok_stream, false); | |
| 1417 ok_stream->Close(false); | |
| 1418 | |
| 1419 EXPECT_EQ(ERR_PIPELINE_EVICTION, | |
| 1420 rejected_stream->ReadResponseHeaders(callback_.callback())); | |
| 1421 rejected_stream->Close(true); | |
| 1422 EXPECT_EQ(ERR_PIPELINE_EVICTION, evicted_callback.WaitForResult()); | |
| 1423 evicted_stream->Close(true); | |
| 1424 } | |
| 1425 | |
| 1426 TEST_F(HttpPipelinedConnectionImplTest, FeedbackOnSocketError) { | |
| 1427 MockWrite writes[] = { | |
| 1428 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1429 }; | |
| 1430 MockRead reads[] = { | |
| 1431 MockRead(SYNCHRONOUS, ERR_FAILED, 1), | |
| 1432 }; | |
| 1433 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1434 | |
| 1435 EXPECT_CALL(delegate_, | |
| 1436 OnPipelineFeedback( | |
| 1437 pipeline_.get(), | |
| 1438 HttpPipelinedConnection::PIPELINE_SOCKET_ERROR)) | |
| 1439 .Times(1); | |
| 1440 | |
| 1441 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 1442 HttpRequestHeaders headers; | |
| 1443 HttpResponseInfo response; | |
| 1444 EXPECT_EQ(OK, stream->SendRequest(headers, | |
| 1445 &response, callback_.callback())); | |
| 1446 EXPECT_EQ(ERR_FAILED, stream->ReadResponseHeaders(callback_.callback())); | |
| 1447 } | |
| 1448 | |
| 1449 TEST_F(HttpPipelinedConnectionImplTest, FeedbackOnNoInternetConnection) { | |
| 1450 MockWrite writes[] = { | |
| 1451 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1452 }; | |
| 1453 MockRead reads[] = { | |
| 1454 MockRead(SYNCHRONOUS, ERR_INTERNET_DISCONNECTED, 1), | |
| 1455 }; | |
| 1456 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1457 | |
| 1458 EXPECT_CALL(delegate_, OnPipelineFeedback(_, _)) | |
| 1459 .Times(0); | |
| 1460 | |
| 1461 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 1462 HttpRequestHeaders headers; | |
| 1463 HttpResponseInfo response; | |
| 1464 EXPECT_EQ(OK, stream->SendRequest(headers, | |
| 1465 &response, callback_.callback())); | |
| 1466 EXPECT_EQ(ERR_INTERNET_DISCONNECTED, | |
| 1467 stream->ReadResponseHeaders(callback_.callback())); | |
| 1468 } | |
| 1469 | |
| 1470 TEST_F(HttpPipelinedConnectionImplTest, FeedbackOnHttp10) { | |
| 1471 MockWrite writes[] = { | |
| 1472 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1473 }; | |
| 1474 MockRead reads[] = { | |
| 1475 MockRead(SYNCHRONOUS, 1, "HTTP/1.0 200 OK\r\n"), | |
| 1476 MockRead(SYNCHRONOUS, 2, "Content-Length: 7\r\n"), | |
| 1477 MockRead(SYNCHRONOUS, 3, "Connection: keep-alive\r\n\r\n"), | |
| 1478 MockRead(SYNCHRONOUS, 4, "ok.html"), | |
| 1479 }; | |
| 1480 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1481 | |
| 1482 EXPECT_CALL(delegate_, | |
| 1483 OnPipelineFeedback(pipeline_.get(), | |
| 1484 HttpPipelinedConnection::OLD_HTTP_VERSION)) | |
| 1485 .Times(1); | |
| 1486 | |
| 1487 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 1488 TestSyncRequest(stream, "ok.html"); | |
| 1489 } | |
| 1490 | |
| 1491 TEST_F(HttpPipelinedConnectionImplTest, FeedbackOnMustClose) { | |
| 1492 MockWrite writes[] = { | |
| 1493 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1494 }; | |
| 1495 MockRead reads[] = { | |
| 1496 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"), | |
| 1497 MockRead(SYNCHRONOUS, 2, "Content-Length: 7\r\n"), | |
| 1498 MockRead(SYNCHRONOUS, 3, "Connection: close\r\n\r\n"), | |
| 1499 MockRead(SYNCHRONOUS, 4, "ok.html"), | |
| 1500 }; | |
| 1501 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1502 | |
| 1503 EXPECT_CALL(delegate_, | |
| 1504 OnPipelineFeedback( | |
| 1505 pipeline_.get(), | |
| 1506 HttpPipelinedConnection::MUST_CLOSE_CONNECTION)) | |
| 1507 .Times(1); | |
| 1508 | |
| 1509 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 1510 TestSyncRequest(stream, "ok.html"); | |
| 1511 } | |
| 1512 | |
| 1513 TEST_F(HttpPipelinedConnectionImplTest, FeedbackOnNoContentLength) { | |
| 1514 MockWrite writes[] = { | |
| 1515 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1516 }; | |
| 1517 MockRead reads[] = { | |
| 1518 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"), | |
| 1519 MockRead(SYNCHRONOUS, 2, "ok.html"), | |
| 1520 }; | |
| 1521 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1522 | |
| 1523 EXPECT_CALL(delegate_, | |
| 1524 OnPipelineFeedback( | |
| 1525 pipeline_.get(), | |
| 1526 HttpPipelinedConnection::MUST_CLOSE_CONNECTION)) | |
| 1527 .Times(1); | |
| 1528 | |
| 1529 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 1530 TestSyncRequest(stream, "ok.html"); | |
| 1531 } | |
| 1532 | |
| 1533 TEST_F(HttpPipelinedConnectionImplTest, FeedbackOnAuthenticationRequired) { | |
| 1534 MockWrite writes[] = { | |
| 1535 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1536 }; | |
| 1537 MockRead reads[] = { | |
| 1538 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 401 Unauthorized\r\n"), | |
| 1539 MockRead(SYNCHRONOUS, 2, "WWW-Authenticate: NTLM\r\n"), | |
| 1540 MockRead(SYNCHRONOUS, 3, "Content-Length: 7\r\n\r\n"), | |
| 1541 MockRead(SYNCHRONOUS, 4, "ok.html"), | |
| 1542 }; | |
| 1543 Initialize(reads, arraysize(reads), writes, arraysize(writes)); | |
| 1544 | |
| 1545 EXPECT_CALL(delegate_, | |
| 1546 OnPipelineFeedback( | |
| 1547 pipeline_.get(), | |
| 1548 HttpPipelinedConnection::AUTHENTICATION_REQUIRED)) | |
| 1549 .Times(1); | |
| 1550 | |
| 1551 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 1552 TestSyncRequest(stream, "ok.html"); | |
| 1553 } | |
| 1554 | |
| 1555 TEST_F(HttpPipelinedConnectionImplTest, OnPipelineHasCapacity) { | |
| 1556 MockWrite writes[] = { | |
| 1557 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1558 }; | |
| 1559 Initialize(NULL, 0, writes, arraysize(writes)); | |
| 1560 | |
| 1561 EXPECT_CALL(delegate_, OnPipelineHasCapacity(pipeline_.get())).Times(0); | |
| 1562 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 1563 | |
| 1564 EXPECT_CALL(delegate_, OnPipelineHasCapacity(pipeline_.get())).Times(1); | |
| 1565 HttpRequestHeaders headers; | |
| 1566 HttpResponseInfo response; | |
| 1567 EXPECT_EQ(OK, stream->SendRequest(headers, | |
| 1568 &response, callback_.callback())); | |
| 1569 | |
| 1570 EXPECT_CALL(delegate_, OnPipelineHasCapacity(pipeline_.get())).Times(0); | |
| 1571 base::MessageLoop::current()->RunUntilIdle(); | |
| 1572 | |
| 1573 stream->Close(false); | |
| 1574 EXPECT_CALL(delegate_, OnPipelineHasCapacity(pipeline_.get())).Times(1); | |
| 1575 stream.reset(NULL); | |
| 1576 } | |
| 1577 | |
| 1578 TEST_F(HttpPipelinedConnectionImplTest, OnPipelineHasCapacityWithoutSend) { | |
| 1579 MockWrite writes[] = { | |
| 1580 MockWrite(SYNCHRONOUS, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), | |
| 1581 }; | |
| 1582 Initialize(NULL, 0, writes, arraysize(writes)); | |
| 1583 | |
| 1584 EXPECT_CALL(delegate_, OnPipelineHasCapacity(pipeline_.get())).Times(0); | |
| 1585 scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); | |
| 1586 | |
| 1587 EXPECT_CALL(delegate_, OnPipelineHasCapacity(pipeline_.get())).Times(1); | |
| 1588 base::MessageLoop::current()->RunUntilIdle(); | |
| 1589 | |
| 1590 stream->Close(false); | |
| 1591 EXPECT_CALL(delegate_, OnPipelineHasCapacity(pipeline_.get())).Times(1); | |
| 1592 stream.reset(NULL); | |
| 1593 } | |
| 1594 | |
| 1595 } // anonymous namespace | |
| 1596 | |
| 1597 } // namespace net | |
| OLD | NEW |