| 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/http/http_network_transaction.h" | |
| 6 | |
| 7 #include <math.h> // ceil | |
| 8 #include <stdarg.h> | |
| 9 #include <string> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/basictypes.h" | |
| 13 #include "base/compiler_specific.h" | |
| 14 #include "base/files/file_path.h" | |
| 15 #include "base/files/file_util.h" | |
| 16 #include "base/json/json_writer.h" | |
| 17 #include "base/logging.h" | |
| 18 #include "base/memory/scoped_ptr.h" | |
| 19 #include "base/memory/weak_ptr.h" | |
| 20 #include "base/run_loop.h" | |
| 21 #include "base/strings/string_util.h" | |
| 22 #include "base/strings/utf_string_conversions.h" | |
| 23 #include "base/test/test_file_util.h" | |
| 24 #include "net/base/auth.h" | |
| 25 #include "net/base/capturing_net_log.h" | |
| 26 #include "net/base/chunked_upload_data_stream.h" | |
| 27 #include "net/base/completion_callback.h" | |
| 28 #include "net/base/elements_upload_data_stream.h" | |
| 29 #include "net/base/load_timing_info.h" | |
| 30 #include "net/base/load_timing_info_test_util.h" | |
| 31 #include "net/base/net_errors.h" | |
| 32 #include "net/base/net_log.h" | |
| 33 #include "net/base/net_log_unittest.h" | |
| 34 #include "net/base/request_priority.h" | |
| 35 #include "net/base/test_completion_callback.h" | |
| 36 #include "net/base/test_data_directory.h" | |
| 37 #include "net/base/upload_bytes_element_reader.h" | |
| 38 #include "net/base/upload_file_element_reader.h" | |
| 39 #include "net/cert/mock_cert_verifier.h" | |
| 40 #include "net/dns/host_cache.h" | |
| 41 #include "net/dns/mock_host_resolver.h" | |
| 42 #include "net/http/http_auth_challenge_tokenizer.h" | |
| 43 #include "net/http/http_auth_handler_digest.h" | |
| 44 #include "net/http/http_auth_handler_mock.h" | |
| 45 #include "net/http/http_auth_handler_ntlm.h" | |
| 46 #include "net/http/http_basic_state.h" | |
| 47 #include "net/http/http_basic_stream.h" | |
| 48 #include "net/http/http_network_session.h" | |
| 49 #include "net/http/http_network_session_peer.h" | |
| 50 #include "net/http/http_request_headers.h" | |
| 51 #include "net/http/http_server_properties_impl.h" | |
| 52 #include "net/http/http_stream.h" | |
| 53 #include "net/http/http_stream_factory.h" | |
| 54 #include "net/http/http_stream_parser.h" | |
| 55 #include "net/http/http_transaction_test_util.h" | |
| 56 #include "net/proxy/proxy_config_service_fixed.h" | |
| 57 #include "net/proxy/proxy_info.h" | |
| 58 #include "net/proxy/proxy_resolver.h" | |
| 59 #include "net/proxy/proxy_service.h" | |
| 60 #include "net/socket/client_socket_factory.h" | |
| 61 #include "net/socket/client_socket_pool_manager.h" | |
| 62 #include "net/socket/mock_client_socket_pool_manager.h" | |
| 63 #include "net/socket/next_proto.h" | |
| 64 #include "net/socket/socket_test_util.h" | |
| 65 #include "net/socket/ssl_client_socket.h" | |
| 66 #include "net/spdy/spdy_framer.h" | |
| 67 #include "net/spdy/spdy_session.h" | |
| 68 #include "net/spdy/spdy_session_pool.h" | |
| 69 #include "net/spdy/spdy_test_util_common.h" | |
| 70 #include "net/ssl/ssl_cert_request_info.h" | |
| 71 #include "net/ssl/ssl_config_service.h" | |
| 72 #include "net/ssl/ssl_config_service_defaults.h" | |
| 73 #include "net/ssl/ssl_info.h" | |
| 74 #include "net/test/cert_test_util.h" | |
| 75 #include "net/websockets/websocket_handshake_stream_base.h" | |
| 76 #include "testing/gtest/include/gtest/gtest.h" | |
| 77 #include "testing/platform_test.h" | |
| 78 #include "url/gurl.h" | |
| 79 | |
| 80 using base::ASCIIToUTF16; | |
| 81 | |
| 82 //----------------------------------------------------------------------------- | |
| 83 | |
| 84 namespace { | |
| 85 | |
| 86 const base::string16 kBar(ASCIIToUTF16("bar")); | |
| 87 const base::string16 kBar2(ASCIIToUTF16("bar2")); | |
| 88 const base::string16 kBar3(ASCIIToUTF16("bar3")); | |
| 89 const base::string16 kBaz(ASCIIToUTF16("baz")); | |
| 90 const base::string16 kFirst(ASCIIToUTF16("first")); | |
| 91 const base::string16 kFoo(ASCIIToUTF16("foo")); | |
| 92 const base::string16 kFoo2(ASCIIToUTF16("foo2")); | |
| 93 const base::string16 kFoo3(ASCIIToUTF16("foo3")); | |
| 94 const base::string16 kFou(ASCIIToUTF16("fou")); | |
| 95 const base::string16 kSecond(ASCIIToUTF16("second")); | |
| 96 const base::string16 kTestingNTLM(ASCIIToUTF16("testing-ntlm")); | |
| 97 const base::string16 kWrongPassword(ASCIIToUTF16("wrongpassword")); | |
| 98 | |
| 99 int GetIdleSocketCountInTransportSocketPool(net::HttpNetworkSession* session) { | |
| 100 return session->GetTransportSocketPool( | |
| 101 net::HttpNetworkSession::NORMAL_SOCKET_POOL)->IdleSocketCount(); | |
| 102 } | |
| 103 | |
| 104 int GetIdleSocketCountInSSLSocketPool(net::HttpNetworkSession* session) { | |
| 105 return session->GetSSLSocketPool( | |
| 106 net::HttpNetworkSession::NORMAL_SOCKET_POOL)->IdleSocketCount(); | |
| 107 } | |
| 108 | |
| 109 bool IsTransportSocketPoolStalled(net::HttpNetworkSession* session) { | |
| 110 return session->GetTransportSocketPool( | |
| 111 net::HttpNetworkSession::NORMAL_SOCKET_POOL)->IsStalled(); | |
| 112 } | |
| 113 | |
| 114 // Takes in a Value created from a NetLogHttpResponseParameter, and returns | |
| 115 // a JSONified list of headers as a single string. Uses single quotes instead | |
| 116 // of double quotes for easier comparison. Returns false on failure. | |
| 117 bool GetHeaders(base::DictionaryValue* params, std::string* headers) { | |
| 118 if (!params) | |
| 119 return false; | |
| 120 base::ListValue* header_list; | |
| 121 if (!params->GetList("headers", &header_list)) | |
| 122 return false; | |
| 123 std::string double_quote_headers; | |
| 124 base::JSONWriter::Write(header_list, &double_quote_headers); | |
| 125 base::ReplaceChars(double_quote_headers, "\"", "'", headers); | |
| 126 return true; | |
| 127 } | |
| 128 | |
| 129 // Tests LoadTimingInfo in the case a socket is reused and no PAC script is | |
| 130 // used. | |
| 131 void TestLoadTimingReused(const net::LoadTimingInfo& load_timing_info) { | |
| 132 EXPECT_TRUE(load_timing_info.socket_reused); | |
| 133 EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); | |
| 134 | |
| 135 EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null()); | |
| 136 EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null()); | |
| 137 | |
| 138 net::ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); | |
| 139 EXPECT_FALSE(load_timing_info.send_start.is_null()); | |
| 140 | |
| 141 EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); | |
| 142 | |
| 143 // Set at a higher level. | |
| 144 EXPECT_TRUE(load_timing_info.request_start_time.is_null()); | |
| 145 EXPECT_TRUE(load_timing_info.request_start.is_null()); | |
| 146 EXPECT_TRUE(load_timing_info.receive_headers_end.is_null()); | |
| 147 } | |
| 148 | |
| 149 // Tests LoadTimingInfo in the case a new socket is used and no PAC script is | |
| 150 // used. | |
| 151 void TestLoadTimingNotReused(const net::LoadTimingInfo& load_timing_info, | |
| 152 int connect_timing_flags) { | |
| 153 EXPECT_FALSE(load_timing_info.socket_reused); | |
| 154 EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); | |
| 155 | |
| 156 EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null()); | |
| 157 EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null()); | |
| 158 | |
| 159 net::ExpectConnectTimingHasTimes(load_timing_info.connect_timing, | |
| 160 connect_timing_flags); | |
| 161 EXPECT_LE(load_timing_info.connect_timing.connect_end, | |
| 162 load_timing_info.send_start); | |
| 163 | |
| 164 EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); | |
| 165 | |
| 166 // Set at a higher level. | |
| 167 EXPECT_TRUE(load_timing_info.request_start_time.is_null()); | |
| 168 EXPECT_TRUE(load_timing_info.request_start.is_null()); | |
| 169 EXPECT_TRUE(load_timing_info.receive_headers_end.is_null()); | |
| 170 } | |
| 171 | |
| 172 // Tests LoadTimingInfo in the case a socket is reused and a PAC script is | |
| 173 // used. | |
| 174 void TestLoadTimingReusedWithPac(const net::LoadTimingInfo& load_timing_info) { | |
| 175 EXPECT_TRUE(load_timing_info.socket_reused); | |
| 176 EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); | |
| 177 | |
| 178 net::ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); | |
| 179 | |
| 180 EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null()); | |
| 181 EXPECT_LE(load_timing_info.proxy_resolve_start, | |
| 182 load_timing_info.proxy_resolve_end); | |
| 183 EXPECT_LE(load_timing_info.proxy_resolve_end, | |
| 184 load_timing_info.send_start); | |
| 185 EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); | |
| 186 | |
| 187 // Set at a higher level. | |
| 188 EXPECT_TRUE(load_timing_info.request_start_time.is_null()); | |
| 189 EXPECT_TRUE(load_timing_info.request_start.is_null()); | |
| 190 EXPECT_TRUE(load_timing_info.receive_headers_end.is_null()); | |
| 191 } | |
| 192 | |
| 193 // Tests LoadTimingInfo in the case a new socket is used and a PAC script is | |
| 194 // used. | |
| 195 void TestLoadTimingNotReusedWithPac(const net::LoadTimingInfo& load_timing_info, | |
| 196 int connect_timing_flags) { | |
| 197 EXPECT_FALSE(load_timing_info.socket_reused); | |
| 198 EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); | |
| 199 | |
| 200 EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null()); | |
| 201 EXPECT_LE(load_timing_info.proxy_resolve_start, | |
| 202 load_timing_info.proxy_resolve_end); | |
| 203 EXPECT_LE(load_timing_info.proxy_resolve_end, | |
| 204 load_timing_info.connect_timing.connect_start); | |
| 205 net::ExpectConnectTimingHasTimes(load_timing_info.connect_timing, | |
| 206 connect_timing_flags); | |
| 207 EXPECT_LE(load_timing_info.connect_timing.connect_end, | |
| 208 load_timing_info.send_start); | |
| 209 | |
| 210 EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); | |
| 211 | |
| 212 // Set at a higher level. | |
| 213 EXPECT_TRUE(load_timing_info.request_start_time.is_null()); | |
| 214 EXPECT_TRUE(load_timing_info.request_start.is_null()); | |
| 215 EXPECT_TRUE(load_timing_info.receive_headers_end.is_null()); | |
| 216 } | |
| 217 | |
| 218 void AddWebSocketHeaders(net::HttpRequestHeaders* headers) { | |
| 219 headers->SetHeader("Connection", "Upgrade"); | |
| 220 headers->SetHeader("Upgrade", "websocket"); | |
| 221 headers->SetHeader("Origin", "http://www.google.com"); | |
| 222 headers->SetHeader("Sec-WebSocket-Version", "13"); | |
| 223 headers->SetHeader("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ=="); | |
| 224 } | |
| 225 | |
| 226 } // namespace | |
| 227 | |
| 228 namespace net { | |
| 229 | |
| 230 namespace { | |
| 231 | |
| 232 HttpNetworkSession* CreateSession(SpdySessionDependencies* session_deps) { | |
| 233 return SpdySessionDependencies::SpdyCreateSession(session_deps); | |
| 234 } | |
| 235 | |
| 236 } // namespace | |
| 237 | |
| 238 class HttpNetworkTransactionTest | |
| 239 : public PlatformTest, | |
| 240 public ::testing::WithParamInterface<NextProto> { | |
| 241 public: | |
| 242 virtual ~HttpNetworkTransactionTest() { | |
| 243 // Important to restore the per-pool limit first, since the pool limit must | |
| 244 // always be greater than group limit, and the tests reduce both limits. | |
| 245 ClientSocketPoolManager::set_max_sockets_per_pool( | |
| 246 HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_pool_sockets_); | |
| 247 ClientSocketPoolManager::set_max_sockets_per_group( | |
| 248 HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_group_sockets_); | |
| 249 } | |
| 250 | |
| 251 protected: | |
| 252 HttpNetworkTransactionTest() | |
| 253 : spdy_util_(GetParam()), | |
| 254 session_deps_(GetParam()), | |
| 255 old_max_group_sockets_(ClientSocketPoolManager::max_sockets_per_group( | |
| 256 HttpNetworkSession::NORMAL_SOCKET_POOL)), | |
| 257 old_max_pool_sockets_(ClientSocketPoolManager::max_sockets_per_pool( | |
| 258 HttpNetworkSession::NORMAL_SOCKET_POOL)) { | |
| 259 } | |
| 260 | |
| 261 struct SimpleGetHelperResult { | |
| 262 int rv; | |
| 263 std::string status_line; | |
| 264 std::string response_data; | |
| 265 int64 totalReceivedBytes; | |
| 266 LoadTimingInfo load_timing_info; | |
| 267 }; | |
| 268 | |
| 269 void SetUp() override { | |
| 270 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); | |
| 271 base::MessageLoop::current()->RunUntilIdle(); | |
| 272 } | |
| 273 | |
| 274 void TearDown() override { | |
| 275 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); | |
| 276 base::MessageLoop::current()->RunUntilIdle(); | |
| 277 // Empty the current queue. | |
| 278 base::MessageLoop::current()->RunUntilIdle(); | |
| 279 PlatformTest::TearDown(); | |
| 280 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); | |
| 281 base::MessageLoop::current()->RunUntilIdle(); | |
| 282 } | |
| 283 | |
| 284 const char* GetAlternateProtocolFromParam() { | |
| 285 return | |
| 286 AlternateProtocolToString(AlternateProtocolFromNextProto(GetParam())); | |
| 287 } | |
| 288 | |
| 289 // This is the expected return from a current server advertising SPDY. | |
| 290 std::string GetAlternateProtocolHttpHeader() { | |
| 291 return std::string("Alternate-Protocol: 443:") + | |
| 292 GetAlternateProtocolFromParam() + "\r\n\r\n"; | |
| 293 } | |
| 294 | |
| 295 // Either |write_failure| specifies a write failure or |read_failure| | |
| 296 // specifies a read failure when using a reused socket. In either case, the | |
| 297 // failure should cause the network transaction to resend the request, and the | |
| 298 // other argument should be NULL. | |
| 299 void KeepAliveConnectionResendRequestTest(const MockWrite* write_failure, | |
| 300 const MockRead* read_failure); | |
| 301 | |
| 302 // Either |write_failure| specifies a write failure or |read_failure| | |
| 303 // specifies a read failure when using a reused socket. In either case, the | |
| 304 // failure should cause the network transaction to resend the request, and the | |
| 305 // other argument should be NULL. | |
| 306 void PreconnectErrorResendRequestTest(const MockWrite* write_failure, | |
| 307 const MockRead* read_failure, | |
| 308 bool use_spdy); | |
| 309 | |
| 310 SimpleGetHelperResult SimpleGetHelperForData(StaticSocketDataProvider* data[], | |
| 311 size_t data_count) { | |
| 312 SimpleGetHelperResult out; | |
| 313 | |
| 314 HttpRequestInfo request; | |
| 315 request.method = "GET"; | |
| 316 request.url = GURL("http://www.google.com/"); | |
| 317 request.load_flags = 0; | |
| 318 | |
| 319 CapturingBoundNetLog log; | |
| 320 session_deps_.net_log = log.bound().net_log(); | |
| 321 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 322 scoped_ptr<HttpTransaction> trans( | |
| 323 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 324 | |
| 325 for (size_t i = 0; i < data_count; ++i) { | |
| 326 session_deps_.socket_factory->AddSocketDataProvider(data[i]); | |
| 327 } | |
| 328 | |
| 329 TestCompletionCallback callback; | |
| 330 | |
| 331 EXPECT_TRUE(log.bound().IsLogging()); | |
| 332 int rv = trans->Start(&request, callback.callback(), log.bound()); | |
| 333 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 334 | |
| 335 out.rv = callback.WaitForResult(); | |
| 336 | |
| 337 // Even in the failure cases that use this function, connections are always | |
| 338 // successfully established before the error. | |
| 339 EXPECT_TRUE(trans->GetLoadTimingInfo(&out.load_timing_info)); | |
| 340 TestLoadTimingNotReused(out.load_timing_info, CONNECT_TIMING_HAS_DNS_TIMES); | |
| 341 | |
| 342 if (out.rv != OK) | |
| 343 return out; | |
| 344 | |
| 345 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 346 // Can't use ASSERT_* inside helper functions like this, so | |
| 347 // return an error. | |
| 348 if (response == NULL || response->headers.get() == NULL) { | |
| 349 out.rv = ERR_UNEXPECTED; | |
| 350 return out; | |
| 351 } | |
| 352 out.status_line = response->headers->GetStatusLine(); | |
| 353 | |
| 354 EXPECT_EQ("127.0.0.1", response->socket_address.host()); | |
| 355 EXPECT_EQ(80, response->socket_address.port()); | |
| 356 | |
| 357 rv = ReadTransaction(trans.get(), &out.response_data); | |
| 358 EXPECT_EQ(OK, rv); | |
| 359 | |
| 360 net::CapturingNetLog::CapturedEntryList entries; | |
| 361 log.GetEntries(&entries); | |
| 362 size_t pos = ExpectLogContainsSomewhere( | |
| 363 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS, | |
| 364 NetLog::PHASE_NONE); | |
| 365 ExpectLogContainsSomewhere( | |
| 366 entries, pos, | |
| 367 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS, | |
| 368 NetLog::PHASE_NONE); | |
| 369 | |
| 370 std::string line; | |
| 371 EXPECT_TRUE(entries[pos].GetStringValue("line", &line)); | |
| 372 EXPECT_EQ("GET / HTTP/1.1\r\n", line); | |
| 373 | |
| 374 HttpRequestHeaders request_headers; | |
| 375 EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); | |
| 376 std::string value; | |
| 377 EXPECT_TRUE(request_headers.GetHeader("Host", &value)); | |
| 378 EXPECT_EQ("www.google.com", value); | |
| 379 EXPECT_TRUE(request_headers.GetHeader("Connection", &value)); | |
| 380 EXPECT_EQ("keep-alive", value); | |
| 381 | |
| 382 std::string response_headers; | |
| 383 EXPECT_TRUE(GetHeaders(entries[pos].params.get(), &response_headers)); | |
| 384 EXPECT_EQ("['Host: www.google.com','Connection: keep-alive']", | |
| 385 response_headers); | |
| 386 | |
| 387 out.totalReceivedBytes = trans->GetTotalReceivedBytes(); | |
| 388 return out; | |
| 389 } | |
| 390 | |
| 391 SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[], | |
| 392 size_t reads_count) { | |
| 393 StaticSocketDataProvider reads(data_reads, reads_count, NULL, 0); | |
| 394 StaticSocketDataProvider* data[] = { &reads }; | |
| 395 return SimpleGetHelperForData(data, 1); | |
| 396 } | |
| 397 | |
| 398 int64 ReadsSize(MockRead data_reads[], size_t reads_count) { | |
| 399 int64 size = 0; | |
| 400 for (size_t i = 0; i < reads_count; ++i) | |
| 401 size += data_reads[i].data_len; | |
| 402 return size; | |
| 403 } | |
| 404 | |
| 405 void ConnectStatusHelperWithExpectedStatus(const MockRead& status, | |
| 406 int expected_status); | |
| 407 | |
| 408 void ConnectStatusHelper(const MockRead& status); | |
| 409 | |
| 410 void BypassHostCacheOnRefreshHelper(int load_flags); | |
| 411 | |
| 412 void CheckErrorIsPassedBack(int error, IoMode mode); | |
| 413 | |
| 414 SpdyTestUtil spdy_util_; | |
| 415 SpdySessionDependencies session_deps_; | |
| 416 | |
| 417 // Original socket limits. Some tests set these. Safest to always restore | |
| 418 // them once each test has been run. | |
| 419 int old_max_group_sockets_; | |
| 420 int old_max_pool_sockets_; | |
| 421 }; | |
| 422 | |
| 423 INSTANTIATE_TEST_CASE_P( | |
| 424 NextProto, | |
| 425 HttpNetworkTransactionTest, | |
| 426 testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15)); | |
| 427 | |
| 428 namespace { | |
| 429 | |
| 430 class BeforeNetworkStartHandler { | |
| 431 public: | |
| 432 explicit BeforeNetworkStartHandler(bool defer) | |
| 433 : defer_on_before_network_start_(defer), | |
| 434 observed_before_network_start_(false) {} | |
| 435 | |
| 436 void OnBeforeNetworkStart(bool* defer) { | |
| 437 *defer = defer_on_before_network_start_; | |
| 438 observed_before_network_start_ = true; | |
| 439 } | |
| 440 | |
| 441 bool observed_before_network_start() const { | |
| 442 return observed_before_network_start_; | |
| 443 } | |
| 444 | |
| 445 private: | |
| 446 const bool defer_on_before_network_start_; | |
| 447 bool observed_before_network_start_; | |
| 448 | |
| 449 DISALLOW_COPY_AND_ASSIGN(BeforeNetworkStartHandler); | |
| 450 }; | |
| 451 | |
| 452 class BeforeProxyHeadersSentHandler { | |
| 453 public: | |
| 454 BeforeProxyHeadersSentHandler() | |
| 455 : observed_before_proxy_headers_sent_(false) {} | |
| 456 | |
| 457 void OnBeforeProxyHeadersSent(const ProxyInfo& proxy_info, | |
| 458 HttpRequestHeaders* request_headers) { | |
| 459 observed_before_proxy_headers_sent_ = true; | |
| 460 observed_proxy_server_uri_ = proxy_info.proxy_server().ToURI(); | |
| 461 } | |
| 462 | |
| 463 bool observed_before_proxy_headers_sent() const { | |
| 464 return observed_before_proxy_headers_sent_; | |
| 465 } | |
| 466 | |
| 467 std::string observed_proxy_server_uri() const { | |
| 468 return observed_proxy_server_uri_; | |
| 469 } | |
| 470 | |
| 471 private: | |
| 472 bool observed_before_proxy_headers_sent_; | |
| 473 std::string observed_proxy_server_uri_; | |
| 474 | |
| 475 DISALLOW_COPY_AND_ASSIGN(BeforeProxyHeadersSentHandler); | |
| 476 }; | |
| 477 | |
| 478 // Fill |str| with a long header list that consumes >= |size| bytes. | |
| 479 void FillLargeHeadersString(std::string* str, int size) { | |
| 480 const char row[] = | |
| 481 "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"; | |
| 482 const int sizeof_row = strlen(row); | |
| 483 const int num_rows = static_cast<int>( | |
| 484 ceil(static_cast<float>(size) / sizeof_row)); | |
| 485 const int sizeof_data = num_rows * sizeof_row; | |
| 486 DCHECK(sizeof_data >= size); | |
| 487 str->reserve(sizeof_data); | |
| 488 | |
| 489 for (int i = 0; i < num_rows; ++i) | |
| 490 str->append(row, sizeof_row); | |
| 491 } | |
| 492 | |
| 493 // Alternative functions that eliminate randomness and dependency on the local | |
| 494 // host name so that the generated NTLM messages are reproducible. | |
| 495 void MockGenerateRandom1(uint8* output, size_t n) { | |
| 496 static const uint8 bytes[] = { | |
| 497 0x55, 0x29, 0x66, 0x26, 0x6b, 0x9c, 0x73, 0x54 | |
| 498 }; | |
| 499 static size_t current_byte = 0; | |
| 500 for (size_t i = 0; i < n; ++i) { | |
| 501 output[i] = bytes[current_byte++]; | |
| 502 current_byte %= arraysize(bytes); | |
| 503 } | |
| 504 } | |
| 505 | |
| 506 void MockGenerateRandom2(uint8* output, size_t n) { | |
| 507 static const uint8 bytes[] = { | |
| 508 0x96, 0x79, 0x85, 0xe7, 0x49, 0x93, 0x70, 0xa1, | |
| 509 0x4e, 0xe7, 0x87, 0x45, 0x31, 0x5b, 0xd3, 0x1f | |
| 510 }; | |
| 511 static size_t current_byte = 0; | |
| 512 for (size_t i = 0; i < n; ++i) { | |
| 513 output[i] = bytes[current_byte++]; | |
| 514 current_byte %= arraysize(bytes); | |
| 515 } | |
| 516 } | |
| 517 | |
| 518 std::string MockGetHostName() { | |
| 519 return "WTC-WIN7"; | |
| 520 } | |
| 521 | |
| 522 template<typename ParentPool> | |
| 523 class CaptureGroupNameSocketPool : public ParentPool { | |
| 524 public: | |
| 525 CaptureGroupNameSocketPool(HostResolver* host_resolver, | |
| 526 CertVerifier* cert_verifier); | |
| 527 | |
| 528 const std::string last_group_name_received() const { | |
| 529 return last_group_name_; | |
| 530 } | |
| 531 | |
| 532 int RequestSocket(const std::string& group_name, | |
| 533 const void* socket_params, | |
| 534 RequestPriority priority, | |
| 535 ClientSocketHandle* handle, | |
| 536 const CompletionCallback& callback, | |
| 537 const BoundNetLog& net_log) override { | |
| 538 last_group_name_ = group_name; | |
| 539 return ERR_IO_PENDING; | |
| 540 } | |
| 541 void CancelRequest(const std::string& group_name, | |
| 542 ClientSocketHandle* handle) override {} | |
| 543 void ReleaseSocket(const std::string& group_name, | |
| 544 scoped_ptr<StreamSocket> socket, | |
| 545 int id) override {} | |
| 546 void CloseIdleSockets() override {} | |
| 547 int IdleSocketCount() const override { return 0; } | |
| 548 int IdleSocketCountInGroup(const std::string& group_name) const override { | |
| 549 return 0; | |
| 550 } | |
| 551 LoadState GetLoadState(const std::string& group_name, | |
| 552 const ClientSocketHandle* handle) const override { | |
| 553 return LOAD_STATE_IDLE; | |
| 554 } | |
| 555 base::TimeDelta ConnectionTimeout() const override { | |
| 556 return base::TimeDelta(); | |
| 557 } | |
| 558 | |
| 559 private: | |
| 560 std::string last_group_name_; | |
| 561 }; | |
| 562 | |
| 563 typedef CaptureGroupNameSocketPool<TransportClientSocketPool> | |
| 564 CaptureGroupNameTransportSocketPool; | |
| 565 typedef CaptureGroupNameSocketPool<HttpProxyClientSocketPool> | |
| 566 CaptureGroupNameHttpProxySocketPool; | |
| 567 typedef CaptureGroupNameSocketPool<SOCKSClientSocketPool> | |
| 568 CaptureGroupNameSOCKSSocketPool; | |
| 569 typedef CaptureGroupNameSocketPool<SSLClientSocketPool> | |
| 570 CaptureGroupNameSSLSocketPool; | |
| 571 | |
| 572 template<typename ParentPool> | |
| 573 CaptureGroupNameSocketPool<ParentPool>::CaptureGroupNameSocketPool( | |
| 574 HostResolver* host_resolver, | |
| 575 CertVerifier* /* cert_verifier */) | |
| 576 : ParentPool(0, 0, NULL, host_resolver, NULL, NULL) {} | |
| 577 | |
| 578 template <> | |
| 579 CaptureGroupNameHttpProxySocketPool::CaptureGroupNameSocketPool( | |
| 580 HostResolver* /* host_resolver */, | |
| 581 CertVerifier* /* cert_verifier */) | |
| 582 : HttpProxyClientSocketPool(0, 0, NULL, NULL, NULL, NULL) { | |
| 583 } | |
| 584 | |
| 585 template <> | |
| 586 CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool( | |
| 587 HostResolver* /* host_resolver */, | |
| 588 CertVerifier* cert_verifier) | |
| 589 : SSLClientSocketPool(0, | |
| 590 0, | |
| 591 NULL, | |
| 592 cert_verifier, | |
| 593 NULL, | |
| 594 NULL, | |
| 595 NULL, | |
| 596 NULL, | |
| 597 std::string(), | |
| 598 NULL, | |
| 599 NULL, | |
| 600 NULL, | |
| 601 NULL, | |
| 602 NULL, | |
| 603 false, | |
| 604 NULL) { | |
| 605 } | |
| 606 | |
| 607 //----------------------------------------------------------------------------- | |
| 608 | |
| 609 // Helper functions for validating that AuthChallengeInfo's are correctly | |
| 610 // configured for common cases. | |
| 611 bool CheckBasicServerAuth(const AuthChallengeInfo* auth_challenge) { | |
| 612 if (!auth_challenge) | |
| 613 return false; | |
| 614 EXPECT_FALSE(auth_challenge->is_proxy); | |
| 615 EXPECT_EQ("www.google.com:80", auth_challenge->challenger.ToString()); | |
| 616 EXPECT_EQ("MyRealm1", auth_challenge->realm); | |
| 617 EXPECT_EQ("basic", auth_challenge->scheme); | |
| 618 return true; | |
| 619 } | |
| 620 | |
| 621 bool CheckBasicProxyAuth(const AuthChallengeInfo* auth_challenge) { | |
| 622 if (!auth_challenge) | |
| 623 return false; | |
| 624 EXPECT_TRUE(auth_challenge->is_proxy); | |
| 625 EXPECT_EQ("myproxy:70", auth_challenge->challenger.ToString()); | |
| 626 EXPECT_EQ("MyRealm1", auth_challenge->realm); | |
| 627 EXPECT_EQ("basic", auth_challenge->scheme); | |
| 628 return true; | |
| 629 } | |
| 630 | |
| 631 bool CheckDigestServerAuth(const AuthChallengeInfo* auth_challenge) { | |
| 632 if (!auth_challenge) | |
| 633 return false; | |
| 634 EXPECT_FALSE(auth_challenge->is_proxy); | |
| 635 EXPECT_EQ("www.google.com:80", auth_challenge->challenger.ToString()); | |
| 636 EXPECT_EQ("digestive", auth_challenge->realm); | |
| 637 EXPECT_EQ("digest", auth_challenge->scheme); | |
| 638 return true; | |
| 639 } | |
| 640 | |
| 641 bool CheckNTLMServerAuth(const AuthChallengeInfo* auth_challenge) { | |
| 642 if (!auth_challenge) | |
| 643 return false; | |
| 644 EXPECT_FALSE(auth_challenge->is_proxy); | |
| 645 EXPECT_EQ("172.22.68.17:80", auth_challenge->challenger.ToString()); | |
| 646 EXPECT_EQ(std::string(), auth_challenge->realm); | |
| 647 EXPECT_EQ("ntlm", auth_challenge->scheme); | |
| 648 return true; | |
| 649 } | |
| 650 | |
| 651 } // namespace | |
| 652 | |
| 653 TEST_P(HttpNetworkTransactionTest, Basic) { | |
| 654 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 655 scoped_ptr<HttpTransaction> trans( | |
| 656 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 657 } | |
| 658 | |
| 659 TEST_P(HttpNetworkTransactionTest, SimpleGET) { | |
| 660 MockRead data_reads[] = { | |
| 661 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
| 662 MockRead("hello world"), | |
| 663 MockRead(SYNCHRONOUS, OK), | |
| 664 }; | |
| 665 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 666 arraysize(data_reads)); | |
| 667 EXPECT_EQ(OK, out.rv); | |
| 668 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); | |
| 669 EXPECT_EQ("hello world", out.response_data); | |
| 670 int64 reads_size = ReadsSize(data_reads, arraysize(data_reads)); | |
| 671 EXPECT_EQ(reads_size, out.totalReceivedBytes); | |
| 672 } | |
| 673 | |
| 674 // Response with no status line. | |
| 675 TEST_P(HttpNetworkTransactionTest, SimpleGETNoHeaders) { | |
| 676 MockRead data_reads[] = { | |
| 677 MockRead("hello world"), | |
| 678 MockRead(SYNCHRONOUS, OK), | |
| 679 }; | |
| 680 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 681 arraysize(data_reads)); | |
| 682 EXPECT_EQ(OK, out.rv); | |
| 683 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); | |
| 684 EXPECT_EQ("hello world", out.response_data); | |
| 685 int64 reads_size = ReadsSize(data_reads, arraysize(data_reads)); | |
| 686 EXPECT_EQ(reads_size, out.totalReceivedBytes); | |
| 687 } | |
| 688 | |
| 689 // Allow up to 4 bytes of junk to precede status line. | |
| 690 TEST_P(HttpNetworkTransactionTest, StatusLineJunk3Bytes) { | |
| 691 MockRead data_reads[] = { | |
| 692 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), | |
| 693 MockRead(SYNCHRONOUS, OK), | |
| 694 }; | |
| 695 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 696 arraysize(data_reads)); | |
| 697 EXPECT_EQ(OK, out.rv); | |
| 698 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); | |
| 699 EXPECT_EQ("DATA", out.response_data); | |
| 700 int64 reads_size = ReadsSize(data_reads, arraysize(data_reads)); | |
| 701 EXPECT_EQ(reads_size, out.totalReceivedBytes); | |
| 702 } | |
| 703 | |
| 704 // Allow up to 4 bytes of junk to precede status line. | |
| 705 TEST_P(HttpNetworkTransactionTest, StatusLineJunk4Bytes) { | |
| 706 MockRead data_reads[] = { | |
| 707 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), | |
| 708 MockRead(SYNCHRONOUS, OK), | |
| 709 }; | |
| 710 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 711 arraysize(data_reads)); | |
| 712 EXPECT_EQ(OK, out.rv); | |
| 713 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); | |
| 714 EXPECT_EQ("DATA", out.response_data); | |
| 715 int64 reads_size = ReadsSize(data_reads, arraysize(data_reads)); | |
| 716 EXPECT_EQ(reads_size, out.totalReceivedBytes); | |
| 717 } | |
| 718 | |
| 719 // Beyond 4 bytes of slop and it should fail to find a status line. | |
| 720 TEST_P(HttpNetworkTransactionTest, StatusLineJunk5Bytes) { | |
| 721 MockRead data_reads[] = { | |
| 722 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"), | |
| 723 MockRead(SYNCHRONOUS, OK), | |
| 724 }; | |
| 725 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 726 arraysize(data_reads)); | |
| 727 EXPECT_EQ(OK, out.rv); | |
| 728 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); | |
| 729 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data); | |
| 730 int64 reads_size = ReadsSize(data_reads, arraysize(data_reads)); | |
| 731 EXPECT_EQ(reads_size, out.totalReceivedBytes); | |
| 732 } | |
| 733 | |
| 734 // Same as StatusLineJunk4Bytes, except the read chunks are smaller. | |
| 735 TEST_P(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) { | |
| 736 MockRead data_reads[] = { | |
| 737 MockRead("\n"), | |
| 738 MockRead("\n"), | |
| 739 MockRead("Q"), | |
| 740 MockRead("J"), | |
| 741 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), | |
| 742 MockRead(SYNCHRONOUS, OK), | |
| 743 }; | |
| 744 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 745 arraysize(data_reads)); | |
| 746 EXPECT_EQ(OK, out.rv); | |
| 747 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); | |
| 748 EXPECT_EQ("DATA", out.response_data); | |
| 749 int64 reads_size = ReadsSize(data_reads, arraysize(data_reads)); | |
| 750 EXPECT_EQ(reads_size, out.totalReceivedBytes); | |
| 751 } | |
| 752 | |
| 753 // Close the connection before enough bytes to have a status line. | |
| 754 TEST_P(HttpNetworkTransactionTest, StatusLinePartial) { | |
| 755 MockRead data_reads[] = { | |
| 756 MockRead("HTT"), | |
| 757 MockRead(SYNCHRONOUS, OK), | |
| 758 }; | |
| 759 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 760 arraysize(data_reads)); | |
| 761 EXPECT_EQ(OK, out.rv); | |
| 762 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); | |
| 763 EXPECT_EQ("HTT", out.response_data); | |
| 764 int64 reads_size = ReadsSize(data_reads, arraysize(data_reads)); | |
| 765 EXPECT_EQ(reads_size, out.totalReceivedBytes); | |
| 766 } | |
| 767 | |
| 768 // Simulate a 204 response, lacking a Content-Length header, sent over a | |
| 769 // persistent connection. The response should still terminate since a 204 | |
| 770 // cannot have a response body. | |
| 771 TEST_P(HttpNetworkTransactionTest, StopsReading204) { | |
| 772 char junk[] = "junk"; | |
| 773 MockRead data_reads[] = { | |
| 774 MockRead("HTTP/1.1 204 No Content\r\n\r\n"), | |
| 775 MockRead(junk), // Should not be read!! | |
| 776 MockRead(SYNCHRONOUS, OK), | |
| 777 }; | |
| 778 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 779 arraysize(data_reads)); | |
| 780 EXPECT_EQ(OK, out.rv); | |
| 781 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line); | |
| 782 EXPECT_EQ("", out.response_data); | |
| 783 int64 reads_size = ReadsSize(data_reads, arraysize(data_reads)); | |
| 784 int64 response_size = reads_size - strlen(junk); | |
| 785 EXPECT_EQ(response_size, out.totalReceivedBytes); | |
| 786 } | |
| 787 | |
| 788 // A simple request using chunked encoding with some extra data after. | |
| 789 TEST_P(HttpNetworkTransactionTest, ChunkedEncoding) { | |
| 790 std::string final_chunk = "0\r\n\r\n"; | |
| 791 std::string extra_data = "HTTP/1.1 200 OK\r\n"; | |
| 792 std::string last_read = final_chunk + extra_data; | |
| 793 MockRead data_reads[] = { | |
| 794 MockRead("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"), | |
| 795 MockRead("5\r\nHello\r\n"), | |
| 796 MockRead("1\r\n"), | |
| 797 MockRead(" \r\n"), | |
| 798 MockRead("5\r\nworld\r\n"), | |
| 799 MockRead(last_read.data()), | |
| 800 MockRead(SYNCHRONOUS, OK), | |
| 801 }; | |
| 802 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 803 arraysize(data_reads)); | |
| 804 EXPECT_EQ(OK, out.rv); | |
| 805 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
| 806 EXPECT_EQ("Hello world", out.response_data); | |
| 807 int64 reads_size = ReadsSize(data_reads, arraysize(data_reads)); | |
| 808 int64 response_size = reads_size - extra_data.size(); | |
| 809 EXPECT_EQ(response_size, out.totalReceivedBytes); | |
| 810 } | |
| 811 | |
| 812 // Next tests deal with http://crbug.com/56344. | |
| 813 | |
| 814 TEST_P(HttpNetworkTransactionTest, | |
| 815 MultipleContentLengthHeadersNoTransferEncoding) { | |
| 816 MockRead data_reads[] = { | |
| 817 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 818 MockRead("Content-Length: 10\r\n"), | |
| 819 MockRead("Content-Length: 5\r\n\r\n"), | |
| 820 }; | |
| 821 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 822 arraysize(data_reads)); | |
| 823 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv); | |
| 824 } | |
| 825 | |
| 826 TEST_P(HttpNetworkTransactionTest, | |
| 827 DuplicateContentLengthHeadersNoTransferEncoding) { | |
| 828 MockRead data_reads[] = { | |
| 829 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 830 MockRead("Content-Length: 5\r\n"), | |
| 831 MockRead("Content-Length: 5\r\n\r\n"), | |
| 832 MockRead("Hello"), | |
| 833 }; | |
| 834 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 835 arraysize(data_reads)); | |
| 836 EXPECT_EQ(OK, out.rv); | |
| 837 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
| 838 EXPECT_EQ("Hello", out.response_data); | |
| 839 } | |
| 840 | |
| 841 TEST_P(HttpNetworkTransactionTest, | |
| 842 ComplexContentLengthHeadersNoTransferEncoding) { | |
| 843 // More than 2 dupes. | |
| 844 { | |
| 845 MockRead data_reads[] = { | |
| 846 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 847 MockRead("Content-Length: 5\r\n"), | |
| 848 MockRead("Content-Length: 5\r\n"), | |
| 849 MockRead("Content-Length: 5\r\n\r\n"), | |
| 850 MockRead("Hello"), | |
| 851 }; | |
| 852 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 853 arraysize(data_reads)); | |
| 854 EXPECT_EQ(OK, out.rv); | |
| 855 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
| 856 EXPECT_EQ("Hello", out.response_data); | |
| 857 } | |
| 858 // HTTP/1.0 | |
| 859 { | |
| 860 MockRead data_reads[] = { | |
| 861 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 862 MockRead("Content-Length: 5\r\n"), | |
| 863 MockRead("Content-Length: 5\r\n"), | |
| 864 MockRead("Content-Length: 5\r\n\r\n"), | |
| 865 MockRead("Hello"), | |
| 866 }; | |
| 867 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 868 arraysize(data_reads)); | |
| 869 EXPECT_EQ(OK, out.rv); | |
| 870 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); | |
| 871 EXPECT_EQ("Hello", out.response_data); | |
| 872 } | |
| 873 // 2 dupes and one mismatched. | |
| 874 { | |
| 875 MockRead data_reads[] = { | |
| 876 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 877 MockRead("Content-Length: 10\r\n"), | |
| 878 MockRead("Content-Length: 10\r\n"), | |
| 879 MockRead("Content-Length: 5\r\n\r\n"), | |
| 880 }; | |
| 881 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 882 arraysize(data_reads)); | |
| 883 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv); | |
| 884 } | |
| 885 } | |
| 886 | |
| 887 TEST_P(HttpNetworkTransactionTest, | |
| 888 MultipleContentLengthHeadersTransferEncoding) { | |
| 889 MockRead data_reads[] = { | |
| 890 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 891 MockRead("Content-Length: 666\r\n"), | |
| 892 MockRead("Content-Length: 1337\r\n"), | |
| 893 MockRead("Transfer-Encoding: chunked\r\n\r\n"), | |
| 894 MockRead("5\r\nHello\r\n"), | |
| 895 MockRead("1\r\n"), | |
| 896 MockRead(" \r\n"), | |
| 897 MockRead("5\r\nworld\r\n"), | |
| 898 MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"), | |
| 899 MockRead(SYNCHRONOUS, OK), | |
| 900 }; | |
| 901 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 902 arraysize(data_reads)); | |
| 903 EXPECT_EQ(OK, out.rv); | |
| 904 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
| 905 EXPECT_EQ("Hello world", out.response_data); | |
| 906 } | |
| 907 | |
| 908 // Next tests deal with http://crbug.com/98895. | |
| 909 | |
| 910 // Checks that a single Content-Disposition header results in no error. | |
| 911 TEST_P(HttpNetworkTransactionTest, SingleContentDispositionHeader) { | |
| 912 MockRead data_reads[] = { | |
| 913 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 914 MockRead("Content-Disposition: attachment;filename=\"salutations.txt\"r\n"), | |
| 915 MockRead("Content-Length: 5\r\n\r\n"), | |
| 916 MockRead("Hello"), | |
| 917 }; | |
| 918 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 919 arraysize(data_reads)); | |
| 920 EXPECT_EQ(OK, out.rv); | |
| 921 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
| 922 EXPECT_EQ("Hello", out.response_data); | |
| 923 } | |
| 924 | |
| 925 // Checks that two identical Content-Disposition headers result in no error. | |
| 926 TEST_P(HttpNetworkTransactionTest, | |
| 927 TwoIdenticalContentDispositionHeaders) { | |
| 928 MockRead data_reads[] = { | |
| 929 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 930 MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), | |
| 931 MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), | |
| 932 MockRead("Content-Length: 5\r\n\r\n"), | |
| 933 MockRead("Hello"), | |
| 934 }; | |
| 935 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 936 arraysize(data_reads)); | |
| 937 EXPECT_EQ(OK, out.rv); | |
| 938 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
| 939 EXPECT_EQ("Hello", out.response_data); | |
| 940 } | |
| 941 | |
| 942 // Checks that two distinct Content-Disposition headers result in an error. | |
| 943 TEST_P(HttpNetworkTransactionTest, TwoDistinctContentDispositionHeaders) { | |
| 944 MockRead data_reads[] = { | |
| 945 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 946 MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), | |
| 947 MockRead("Content-Disposition: attachment;filename=\"hi.txt\"r\n"), | |
| 948 MockRead("Content-Length: 5\r\n\r\n"), | |
| 949 MockRead("Hello"), | |
| 950 }; | |
| 951 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 952 arraysize(data_reads)); | |
| 953 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION, out.rv); | |
| 954 } | |
| 955 | |
| 956 // Checks that two identical Location headers result in no error. | |
| 957 // Also tests Location header behavior. | |
| 958 TEST_P(HttpNetworkTransactionTest, TwoIdenticalLocationHeaders) { | |
| 959 MockRead data_reads[] = { | |
| 960 MockRead("HTTP/1.1 302 Redirect\r\n"), | |
| 961 MockRead("Location: http://good.com/\r\n"), | |
| 962 MockRead("Location: http://good.com/\r\n"), | |
| 963 MockRead("Content-Length: 0\r\n\r\n"), | |
| 964 MockRead(SYNCHRONOUS, OK), | |
| 965 }; | |
| 966 | |
| 967 HttpRequestInfo request; | |
| 968 request.method = "GET"; | |
| 969 request.url = GURL("http://redirect.com/"); | |
| 970 request.load_flags = 0; | |
| 971 | |
| 972 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 973 scoped_ptr<HttpTransaction> trans( | |
| 974 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 975 | |
| 976 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 977 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 978 | |
| 979 TestCompletionCallback callback; | |
| 980 | |
| 981 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 982 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 983 | |
| 984 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 985 | |
| 986 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 987 ASSERT_TRUE(response != NULL && response->headers.get() != NULL); | |
| 988 EXPECT_EQ("HTTP/1.1 302 Redirect", response->headers->GetStatusLine()); | |
| 989 std::string url; | |
| 990 EXPECT_TRUE(response->headers->IsRedirect(&url)); | |
| 991 EXPECT_EQ("http://good.com/", url); | |
| 992 EXPECT_TRUE(response->proxy_server.IsEmpty()); | |
| 993 } | |
| 994 | |
| 995 // Checks that two distinct Location headers result in an error. | |
| 996 TEST_P(HttpNetworkTransactionTest, TwoDistinctLocationHeaders) { | |
| 997 MockRead data_reads[] = { | |
| 998 MockRead("HTTP/1.1 302 Redirect\r\n"), | |
| 999 MockRead("Location: http://good.com/\r\n"), | |
| 1000 MockRead("Location: http://evil.com/\r\n"), | |
| 1001 MockRead("Content-Length: 0\r\n\r\n"), | |
| 1002 MockRead(SYNCHRONOUS, OK), | |
| 1003 }; | |
| 1004 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 1005 arraysize(data_reads)); | |
| 1006 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION, out.rv); | |
| 1007 } | |
| 1008 | |
| 1009 // Do a request using the HEAD method. Verify that we don't try to read the | |
| 1010 // message body (since HEAD has none). | |
| 1011 TEST_P(HttpNetworkTransactionTest, Head) { | |
| 1012 HttpRequestInfo request; | |
| 1013 request.method = "HEAD"; | |
| 1014 request.url = GURL("http://www.google.com/"); | |
| 1015 request.load_flags = 0; | |
| 1016 | |
| 1017 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1018 scoped_ptr<HttpTransaction> trans( | |
| 1019 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1020 BeforeProxyHeadersSentHandler proxy_headers_handler; | |
| 1021 trans->SetBeforeProxyHeadersSentCallback( | |
| 1022 base::Bind(&BeforeProxyHeadersSentHandler::OnBeforeProxyHeadersSent, | |
| 1023 base::Unretained(&proxy_headers_handler))); | |
| 1024 | |
| 1025 MockWrite data_writes1[] = { | |
| 1026 MockWrite("HEAD / HTTP/1.1\r\n" | |
| 1027 "Host: www.google.com\r\n" | |
| 1028 "Connection: keep-alive\r\n" | |
| 1029 "Content-Length: 0\r\n\r\n"), | |
| 1030 }; | |
| 1031 MockRead data_reads1[] = { | |
| 1032 MockRead("HTTP/1.1 404 Not Found\r\n"), | |
| 1033 MockRead("Server: Blah\r\n"), | |
| 1034 MockRead("Content-Length: 1234\r\n\r\n"), | |
| 1035 | |
| 1036 // No response body because the test stops reading here. | |
| 1037 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 1038 }; | |
| 1039 | |
| 1040 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 1041 data_writes1, arraysize(data_writes1)); | |
| 1042 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 1043 | |
| 1044 TestCompletionCallback callback1; | |
| 1045 | |
| 1046 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 1047 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1048 | |
| 1049 rv = callback1.WaitForResult(); | |
| 1050 EXPECT_EQ(OK, rv); | |
| 1051 | |
| 1052 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1053 ASSERT_TRUE(response != NULL); | |
| 1054 | |
| 1055 // Check that the headers got parsed. | |
| 1056 EXPECT_TRUE(response->headers.get() != NULL); | |
| 1057 EXPECT_EQ(1234, response->headers->GetContentLength()); | |
| 1058 EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine()); | |
| 1059 EXPECT_TRUE(response->proxy_server.IsEmpty()); | |
| 1060 EXPECT_FALSE(proxy_headers_handler.observed_before_proxy_headers_sent()); | |
| 1061 | |
| 1062 std::string server_header; | |
| 1063 void* iter = NULL; | |
| 1064 bool has_server_header = response->headers->EnumerateHeader( | |
| 1065 &iter, "Server", &server_header); | |
| 1066 EXPECT_TRUE(has_server_header); | |
| 1067 EXPECT_EQ("Blah", server_header); | |
| 1068 | |
| 1069 // Reading should give EOF right away, since there is no message body | |
| 1070 // (despite non-zero content-length). | |
| 1071 std::string response_data; | |
| 1072 rv = ReadTransaction(trans.get(), &response_data); | |
| 1073 EXPECT_EQ(OK, rv); | |
| 1074 EXPECT_EQ("", response_data); | |
| 1075 } | |
| 1076 | |
| 1077 TEST_P(HttpNetworkTransactionTest, ReuseConnection) { | |
| 1078 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1079 | |
| 1080 MockRead data_reads[] = { | |
| 1081 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
| 1082 MockRead("hello"), | |
| 1083 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
| 1084 MockRead("world"), | |
| 1085 MockRead(SYNCHRONOUS, OK), | |
| 1086 }; | |
| 1087 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 1088 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1089 | |
| 1090 const char* const kExpectedResponseData[] = { | |
| 1091 "hello", "world" | |
| 1092 }; | |
| 1093 | |
| 1094 for (int i = 0; i < 2; ++i) { | |
| 1095 HttpRequestInfo request; | |
| 1096 request.method = "GET"; | |
| 1097 request.url = GURL("http://www.google.com/"); | |
| 1098 request.load_flags = 0; | |
| 1099 | |
| 1100 scoped_ptr<HttpTransaction> trans( | |
| 1101 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1102 | |
| 1103 TestCompletionCallback callback; | |
| 1104 | |
| 1105 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1106 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1107 | |
| 1108 rv = callback.WaitForResult(); | |
| 1109 EXPECT_EQ(OK, rv); | |
| 1110 | |
| 1111 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1112 ASSERT_TRUE(response != NULL); | |
| 1113 | |
| 1114 EXPECT_TRUE(response->headers.get() != NULL); | |
| 1115 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 1116 EXPECT_TRUE(response->proxy_server.IsEmpty()); | |
| 1117 | |
| 1118 std::string response_data; | |
| 1119 rv = ReadTransaction(trans.get(), &response_data); | |
| 1120 EXPECT_EQ(OK, rv); | |
| 1121 EXPECT_EQ(kExpectedResponseData[i], response_data); | |
| 1122 } | |
| 1123 } | |
| 1124 | |
| 1125 TEST_P(HttpNetworkTransactionTest, Ignores100) { | |
| 1126 ScopedVector<UploadElementReader> element_readers; | |
| 1127 element_readers.push_back(new UploadBytesElementReader("foo", 3)); | |
| 1128 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 1129 | |
| 1130 HttpRequestInfo request; | |
| 1131 request.method = "POST"; | |
| 1132 request.url = GURL("http://www.foo.com/"); | |
| 1133 request.upload_data_stream = &upload_data_stream; | |
| 1134 request.load_flags = 0; | |
| 1135 | |
| 1136 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1137 scoped_ptr<HttpTransaction> trans( | |
| 1138 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1139 | |
| 1140 MockRead data_reads[] = { | |
| 1141 MockRead("HTTP/1.0 100 Continue\r\n\r\n"), | |
| 1142 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
| 1143 MockRead("hello world"), | |
| 1144 MockRead(SYNCHRONOUS, OK), | |
| 1145 }; | |
| 1146 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 1147 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1148 | |
| 1149 TestCompletionCallback callback; | |
| 1150 | |
| 1151 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1152 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1153 | |
| 1154 rv = callback.WaitForResult(); | |
| 1155 EXPECT_EQ(OK, rv); | |
| 1156 | |
| 1157 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1158 ASSERT_TRUE(response != NULL); | |
| 1159 | |
| 1160 EXPECT_TRUE(response->headers.get() != NULL); | |
| 1161 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
| 1162 | |
| 1163 std::string response_data; | |
| 1164 rv = ReadTransaction(trans.get(), &response_data); | |
| 1165 EXPECT_EQ(OK, rv); | |
| 1166 EXPECT_EQ("hello world", response_data); | |
| 1167 } | |
| 1168 | |
| 1169 // This test is almost the same as Ignores100 above, but the response contains | |
| 1170 // a 102 instead of a 100. Also, instead of HTTP/1.0 the response is | |
| 1171 // HTTP/1.1 and the two status headers are read in one read. | |
| 1172 TEST_P(HttpNetworkTransactionTest, Ignores1xx) { | |
| 1173 HttpRequestInfo request; | |
| 1174 request.method = "GET"; | |
| 1175 request.url = GURL("http://www.foo.com/"); | |
| 1176 request.load_flags = 0; | |
| 1177 | |
| 1178 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1179 scoped_ptr<HttpTransaction> trans( | |
| 1180 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1181 | |
| 1182 MockRead data_reads[] = { | |
| 1183 MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n" | |
| 1184 "HTTP/1.1 200 OK\r\n\r\n"), | |
| 1185 MockRead("hello world"), | |
| 1186 MockRead(SYNCHRONOUS, OK), | |
| 1187 }; | |
| 1188 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 1189 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1190 | |
| 1191 TestCompletionCallback callback; | |
| 1192 | |
| 1193 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1194 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1195 | |
| 1196 rv = callback.WaitForResult(); | |
| 1197 EXPECT_EQ(OK, rv); | |
| 1198 | |
| 1199 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1200 ASSERT_TRUE(response != NULL); | |
| 1201 | |
| 1202 EXPECT_TRUE(response->headers.get() != NULL); | |
| 1203 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 1204 | |
| 1205 std::string response_data; | |
| 1206 rv = ReadTransaction(trans.get(), &response_data); | |
| 1207 EXPECT_EQ(OK, rv); | |
| 1208 EXPECT_EQ("hello world", response_data); | |
| 1209 } | |
| 1210 | |
| 1211 TEST_P(HttpNetworkTransactionTest, Incomplete100ThenEOF) { | |
| 1212 HttpRequestInfo request; | |
| 1213 request.method = "POST"; | |
| 1214 request.url = GURL("http://www.foo.com/"); | |
| 1215 request.load_flags = 0; | |
| 1216 | |
| 1217 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1218 scoped_ptr<HttpTransaction> trans( | |
| 1219 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1220 | |
| 1221 MockRead data_reads[] = { | |
| 1222 MockRead(SYNCHRONOUS, "HTTP/1.0 100 Continue\r\n"), | |
| 1223 MockRead(ASYNC, 0), | |
| 1224 }; | |
| 1225 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 1226 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1227 | |
| 1228 TestCompletionCallback callback; | |
| 1229 | |
| 1230 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1231 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1232 | |
| 1233 rv = callback.WaitForResult(); | |
| 1234 EXPECT_EQ(OK, rv); | |
| 1235 | |
| 1236 std::string response_data; | |
| 1237 rv = ReadTransaction(trans.get(), &response_data); | |
| 1238 EXPECT_EQ(OK, rv); | |
| 1239 EXPECT_EQ("", response_data); | |
| 1240 } | |
| 1241 | |
| 1242 TEST_P(HttpNetworkTransactionTest, EmptyResponse) { | |
| 1243 HttpRequestInfo request; | |
| 1244 request.method = "POST"; | |
| 1245 request.url = GURL("http://www.foo.com/"); | |
| 1246 request.load_flags = 0; | |
| 1247 | |
| 1248 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1249 scoped_ptr<HttpTransaction> trans( | |
| 1250 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1251 | |
| 1252 MockRead data_reads[] = { | |
| 1253 MockRead(ASYNC, 0), | |
| 1254 }; | |
| 1255 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 1256 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1257 | |
| 1258 TestCompletionCallback callback; | |
| 1259 | |
| 1260 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1261 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1262 | |
| 1263 rv = callback.WaitForResult(); | |
| 1264 EXPECT_EQ(ERR_EMPTY_RESPONSE, rv); | |
| 1265 } | |
| 1266 | |
| 1267 void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest( | |
| 1268 const MockWrite* write_failure, | |
| 1269 const MockRead* read_failure) { | |
| 1270 HttpRequestInfo request; | |
| 1271 request.method = "GET"; | |
| 1272 request.url = GURL("http://www.foo.com/"); | |
| 1273 request.load_flags = 0; | |
| 1274 | |
| 1275 CapturingNetLog net_log; | |
| 1276 session_deps_.net_log = &net_log; | |
| 1277 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1278 | |
| 1279 // Written data for successfully sending both requests. | |
| 1280 MockWrite data1_writes[] = { | |
| 1281 MockWrite("GET / HTTP/1.1\r\n" | |
| 1282 "Host: www.foo.com\r\n" | |
| 1283 "Connection: keep-alive\r\n\r\n"), | |
| 1284 MockWrite("GET / HTTP/1.1\r\n" | |
| 1285 "Host: www.foo.com\r\n" | |
| 1286 "Connection: keep-alive\r\n\r\n") | |
| 1287 }; | |
| 1288 | |
| 1289 // Read results for the first request. | |
| 1290 MockRead data1_reads[] = { | |
| 1291 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
| 1292 MockRead("hello"), | |
| 1293 MockRead(ASYNC, OK), | |
| 1294 }; | |
| 1295 | |
| 1296 if (write_failure) { | |
| 1297 ASSERT_FALSE(read_failure); | |
| 1298 data1_writes[1] = *write_failure; | |
| 1299 } else { | |
| 1300 ASSERT_TRUE(read_failure); | |
| 1301 data1_reads[2] = *read_failure; | |
| 1302 } | |
| 1303 | |
| 1304 StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), | |
| 1305 data1_writes, arraysize(data1_writes)); | |
| 1306 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 1307 | |
| 1308 MockRead data2_reads[] = { | |
| 1309 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
| 1310 MockRead("world"), | |
| 1311 MockRead(ASYNC, OK), | |
| 1312 }; | |
| 1313 StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0); | |
| 1314 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 1315 | |
| 1316 const char* const kExpectedResponseData[] = { | |
| 1317 "hello", "world" | |
| 1318 }; | |
| 1319 | |
| 1320 uint32 first_socket_log_id = NetLog::Source::kInvalidId; | |
| 1321 for (int i = 0; i < 2; ++i) { | |
| 1322 TestCompletionCallback callback; | |
| 1323 | |
| 1324 scoped_ptr<HttpTransaction> trans( | |
| 1325 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1326 | |
| 1327 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1328 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1329 | |
| 1330 rv = callback.WaitForResult(); | |
| 1331 EXPECT_EQ(OK, rv); | |
| 1332 | |
| 1333 LoadTimingInfo load_timing_info; | |
| 1334 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 1335 TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_DNS_TIMES); | |
| 1336 if (i == 0) { | |
| 1337 first_socket_log_id = load_timing_info.socket_log_id; | |
| 1338 } else { | |
| 1339 // The second request should be using a new socket. | |
| 1340 EXPECT_NE(first_socket_log_id, load_timing_info.socket_log_id); | |
| 1341 } | |
| 1342 | |
| 1343 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1344 ASSERT_TRUE(response != NULL); | |
| 1345 | |
| 1346 EXPECT_TRUE(response->headers.get() != NULL); | |
| 1347 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 1348 | |
| 1349 std::string response_data; | |
| 1350 rv = ReadTransaction(trans.get(), &response_data); | |
| 1351 EXPECT_EQ(OK, rv); | |
| 1352 EXPECT_EQ(kExpectedResponseData[i], response_data); | |
| 1353 } | |
| 1354 } | |
| 1355 | |
| 1356 void HttpNetworkTransactionTest::PreconnectErrorResendRequestTest( | |
| 1357 const MockWrite* write_failure, | |
| 1358 const MockRead* read_failure, | |
| 1359 bool use_spdy) { | |
| 1360 HttpRequestInfo request; | |
| 1361 request.method = "GET"; | |
| 1362 request.url = GURL("https://www.foo.com/"); | |
| 1363 request.load_flags = 0; | |
| 1364 | |
| 1365 CapturingNetLog net_log; | |
| 1366 session_deps_.net_log = &net_log; | |
| 1367 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1368 | |
| 1369 SSLSocketDataProvider ssl1(ASYNC, OK); | |
| 1370 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 1371 if (use_spdy) { | |
| 1372 ssl1.SetNextProto(GetParam()); | |
| 1373 ssl2.SetNextProto(GetParam()); | |
| 1374 } | |
| 1375 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1); | |
| 1376 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2); | |
| 1377 | |
| 1378 // SPDY versions of the request and response. | |
| 1379 scoped_ptr<SpdyFrame> spdy_request(spdy_util_.ConstructSpdyGet( | |
| 1380 request.url.spec().c_str(), false, 1, DEFAULT_PRIORITY)); | |
| 1381 scoped_ptr<SpdyFrame> spdy_response( | |
| 1382 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 1383 scoped_ptr<SpdyFrame> spdy_data( | |
| 1384 spdy_util_.ConstructSpdyBodyFrame(1, "hello", 5, true)); | |
| 1385 | |
| 1386 // HTTP/1.1 versions of the request and response. | |
| 1387 const char kHttpRequest[] = "GET / HTTP/1.1\r\n" | |
| 1388 "Host: www.foo.com\r\n" | |
| 1389 "Connection: keep-alive\r\n\r\n"; | |
| 1390 const char kHttpResponse[] = "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"; | |
| 1391 const char kHttpData[] = "hello"; | |
| 1392 | |
| 1393 std::vector<MockRead> data1_reads; | |
| 1394 std::vector<MockWrite> data1_writes; | |
| 1395 if (write_failure) { | |
| 1396 ASSERT_FALSE(read_failure); | |
| 1397 data1_writes.push_back(*write_failure); | |
| 1398 data1_reads.push_back(MockRead(ASYNC, OK)); | |
| 1399 } else { | |
| 1400 ASSERT_TRUE(read_failure); | |
| 1401 if (use_spdy) { | |
| 1402 data1_writes.push_back(CreateMockWrite(*spdy_request)); | |
| 1403 } else { | |
| 1404 data1_writes.push_back(MockWrite(kHttpRequest)); | |
| 1405 } | |
| 1406 data1_reads.push_back(*read_failure); | |
| 1407 } | |
| 1408 | |
| 1409 StaticSocketDataProvider data1(&data1_reads[0], data1_reads.size(), | |
| 1410 &data1_writes[0], data1_writes.size()); | |
| 1411 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 1412 | |
| 1413 std::vector<MockRead> data2_reads; | |
| 1414 std::vector<MockWrite> data2_writes; | |
| 1415 | |
| 1416 if (use_spdy) { | |
| 1417 data2_writes.push_back(CreateMockWrite(*spdy_request, 0, ASYNC)); | |
| 1418 | |
| 1419 data2_reads.push_back(CreateMockRead(*spdy_response, 1, ASYNC)); | |
| 1420 data2_reads.push_back(CreateMockRead(*spdy_data, 2, ASYNC)); | |
| 1421 data2_reads.push_back(MockRead(ASYNC, OK, 3)); | |
| 1422 } else { | |
| 1423 data2_writes.push_back( | |
| 1424 MockWrite(ASYNC, kHttpRequest, strlen(kHttpRequest), 0)); | |
| 1425 | |
| 1426 data2_reads.push_back( | |
| 1427 MockRead(ASYNC, kHttpResponse, strlen(kHttpResponse), 1)); | |
| 1428 data2_reads.push_back(MockRead(ASYNC, kHttpData, strlen(kHttpData), 2)); | |
| 1429 data2_reads.push_back(MockRead(ASYNC, OK, 3)); | |
| 1430 } | |
| 1431 OrderedSocketData data2(&data2_reads[0], data2_reads.size(), | |
| 1432 &data2_writes[0], data2_writes.size()); | |
| 1433 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 1434 | |
| 1435 // Preconnect a socket. | |
| 1436 net::SSLConfig ssl_config; | |
| 1437 session->ssl_config_service()->GetSSLConfig(&ssl_config); | |
| 1438 session->GetNextProtos(&ssl_config.next_protos); | |
| 1439 session->http_stream_factory()->PreconnectStreams( | |
| 1440 1, request, DEFAULT_PRIORITY, ssl_config, ssl_config); | |
| 1441 // Wait for the preconnect to complete. | |
| 1442 // TODO(davidben): Some way to wait for an idle socket count might be handy. | |
| 1443 base::RunLoop().RunUntilIdle(); | |
| 1444 EXPECT_EQ(1, GetIdleSocketCountInSSLSocketPool(session.get())); | |
| 1445 | |
| 1446 // Make the request. | |
| 1447 TestCompletionCallback callback; | |
| 1448 | |
| 1449 scoped_ptr<HttpTransaction> trans( | |
| 1450 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1451 | |
| 1452 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1453 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1454 | |
| 1455 rv = callback.WaitForResult(); | |
| 1456 EXPECT_EQ(OK, rv); | |
| 1457 | |
| 1458 LoadTimingInfo load_timing_info; | |
| 1459 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 1460 TestLoadTimingNotReused( | |
| 1461 load_timing_info, | |
| 1462 CONNECT_TIMING_HAS_DNS_TIMES|CONNECT_TIMING_HAS_SSL_TIMES); | |
| 1463 | |
| 1464 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1465 ASSERT_TRUE(response != NULL); | |
| 1466 | |
| 1467 EXPECT_TRUE(response->headers.get() != NULL); | |
| 1468 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 1469 | |
| 1470 std::string response_data; | |
| 1471 rv = ReadTransaction(trans.get(), &response_data); | |
| 1472 EXPECT_EQ(OK, rv); | |
| 1473 EXPECT_EQ(kHttpData, response_data); | |
| 1474 } | |
| 1475 | |
| 1476 TEST_P(HttpNetworkTransactionTest, | |
| 1477 KeepAliveConnectionNotConnectedOnWrite) { | |
| 1478 MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED); | |
| 1479 KeepAliveConnectionResendRequestTest(&write_failure, NULL); | |
| 1480 } | |
| 1481 | |
| 1482 TEST_P(HttpNetworkTransactionTest, KeepAliveConnectionReset) { | |
| 1483 MockRead read_failure(ASYNC, ERR_CONNECTION_RESET); | |
| 1484 KeepAliveConnectionResendRequestTest(NULL, &read_failure); | |
| 1485 } | |
| 1486 | |
| 1487 TEST_P(HttpNetworkTransactionTest, KeepAliveConnectionEOF) { | |
| 1488 MockRead read_failure(SYNCHRONOUS, OK); // EOF | |
| 1489 KeepAliveConnectionResendRequestTest(NULL, &read_failure); | |
| 1490 } | |
| 1491 | |
| 1492 // Make sure that on a 408 response (Request Timeout), the request is retried, | |
| 1493 // if the socket was a reused keep alive socket. | |
| 1494 TEST_P(HttpNetworkTransactionTest, KeepAlive408) { | |
| 1495 MockRead read_failure(SYNCHRONOUS, | |
| 1496 "HTTP/1.1 408 Request Timeout\r\n" | |
| 1497 "Connection: Keep-Alive\r\n" | |
| 1498 "Content-Length: 6\r\n\r\n" | |
| 1499 "Pickle"); | |
| 1500 KeepAliveConnectionResendRequestTest(NULL, &read_failure); | |
| 1501 } | |
| 1502 | |
| 1503 TEST_P(HttpNetworkTransactionTest, | |
| 1504 PreconnectErrorNotConnectedOnWrite) { | |
| 1505 MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED); | |
| 1506 PreconnectErrorResendRequestTest(&write_failure, NULL, false); | |
| 1507 } | |
| 1508 | |
| 1509 TEST_P(HttpNetworkTransactionTest, PreconnectErrorReset) { | |
| 1510 MockRead read_failure(ASYNC, ERR_CONNECTION_RESET); | |
| 1511 PreconnectErrorResendRequestTest(NULL, &read_failure, false); | |
| 1512 } | |
| 1513 | |
| 1514 TEST_P(HttpNetworkTransactionTest, PreconnectErrorEOF) { | |
| 1515 MockRead read_failure(SYNCHRONOUS, OK); // EOF | |
| 1516 PreconnectErrorResendRequestTest(NULL, &read_failure, false); | |
| 1517 } | |
| 1518 | |
| 1519 TEST_P(HttpNetworkTransactionTest, PreconnectErrorAsyncEOF) { | |
| 1520 MockRead read_failure(ASYNC, OK); // EOF | |
| 1521 PreconnectErrorResendRequestTest(NULL, &read_failure, false); | |
| 1522 } | |
| 1523 | |
| 1524 // Make sure that on a 408 response (Request Timeout), the request is retried, | |
| 1525 // if the socket was a preconnected (UNUSED_IDLE) socket. | |
| 1526 TEST_P(HttpNetworkTransactionTest, RetryOnIdle408) { | |
| 1527 MockRead read_failure(SYNCHRONOUS, | |
| 1528 "HTTP/1.1 408 Request Timeout\r\n" | |
| 1529 "Connection: Keep-Alive\r\n" | |
| 1530 "Content-Length: 6\r\n\r\n" | |
| 1531 "Pickle"); | |
| 1532 KeepAliveConnectionResendRequestTest(NULL, &read_failure); | |
| 1533 PreconnectErrorResendRequestTest(NULL, &read_failure, false); | |
| 1534 } | |
| 1535 | |
| 1536 TEST_P(HttpNetworkTransactionTest, | |
| 1537 SpdyPreconnectErrorNotConnectedOnWrite) { | |
| 1538 MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED); | |
| 1539 PreconnectErrorResendRequestTest(&write_failure, NULL, true); | |
| 1540 } | |
| 1541 | |
| 1542 TEST_P(HttpNetworkTransactionTest, SpdyPreconnectErrorReset) { | |
| 1543 MockRead read_failure(ASYNC, ERR_CONNECTION_RESET); | |
| 1544 PreconnectErrorResendRequestTest(NULL, &read_failure, true); | |
| 1545 } | |
| 1546 | |
| 1547 TEST_P(HttpNetworkTransactionTest, SpdyPreconnectErrorEOF) { | |
| 1548 MockRead read_failure(SYNCHRONOUS, OK); // EOF | |
| 1549 PreconnectErrorResendRequestTest(NULL, &read_failure, true); | |
| 1550 } | |
| 1551 | |
| 1552 TEST_P(HttpNetworkTransactionTest, SpdyPreconnectErrorAsyncEOF) { | |
| 1553 MockRead read_failure(ASYNC, OK); // EOF | |
| 1554 PreconnectErrorResendRequestTest(NULL, &read_failure, true); | |
| 1555 } | |
| 1556 | |
| 1557 TEST_P(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) { | |
| 1558 HttpRequestInfo request; | |
| 1559 request.method = "GET"; | |
| 1560 request.url = GURL("http://www.google.com/"); | |
| 1561 request.load_flags = 0; | |
| 1562 | |
| 1563 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1564 scoped_ptr<HttpTransaction> trans( | |
| 1565 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1566 | |
| 1567 MockRead data_reads[] = { | |
| 1568 MockRead(ASYNC, ERR_CONNECTION_RESET), | |
| 1569 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used | |
| 1570 MockRead("hello world"), | |
| 1571 MockRead(SYNCHRONOUS, OK), | |
| 1572 }; | |
| 1573 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 1574 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1575 | |
| 1576 TestCompletionCallback callback; | |
| 1577 | |
| 1578 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1579 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1580 | |
| 1581 rv = callback.WaitForResult(); | |
| 1582 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 1583 | |
| 1584 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1585 EXPECT_TRUE(response == NULL); | |
| 1586 } | |
| 1587 | |
| 1588 // What do various browsers do when the server closes a non-keepalive | |
| 1589 // connection without sending any response header or body? | |
| 1590 // | |
| 1591 // IE7: error page | |
| 1592 // Safari 3.1.2 (Windows): error page | |
| 1593 // Firefox 3.0.1: blank page | |
| 1594 // Opera 9.52: after five attempts, blank page | |
| 1595 // Us with WinHTTP: error page (ERR_INVALID_RESPONSE) | |
| 1596 // Us: error page (EMPTY_RESPONSE) | |
| 1597 TEST_P(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) { | |
| 1598 MockRead data_reads[] = { | |
| 1599 MockRead(SYNCHRONOUS, OK), // EOF | |
| 1600 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used | |
| 1601 MockRead("hello world"), | |
| 1602 MockRead(SYNCHRONOUS, OK), | |
| 1603 }; | |
| 1604 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 1605 arraysize(data_reads)); | |
| 1606 EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv); | |
| 1607 } | |
| 1608 | |
| 1609 // Test that network access can be deferred and resumed. | |
| 1610 TEST_P(HttpNetworkTransactionTest, ThrottleBeforeNetworkStart) { | |
| 1611 HttpRequestInfo request; | |
| 1612 request.method = "GET"; | |
| 1613 request.url = GURL("http://www.google.com/"); | |
| 1614 request.load_flags = 0; | |
| 1615 | |
| 1616 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1617 scoped_ptr<HttpTransaction> trans( | |
| 1618 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1619 | |
| 1620 // Defer on OnBeforeNetworkStart. | |
| 1621 BeforeNetworkStartHandler net_start_handler(true); // defer | |
| 1622 trans->SetBeforeNetworkStartCallback( | |
| 1623 base::Bind(&BeforeNetworkStartHandler::OnBeforeNetworkStart, | |
| 1624 base::Unretained(&net_start_handler))); | |
| 1625 | |
| 1626 MockRead data_reads[] = { | |
| 1627 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 1628 MockRead("Content-Length: 5\r\n\r\n"), | |
| 1629 MockRead("hello"), | |
| 1630 MockRead(SYNCHRONOUS, 0), | |
| 1631 }; | |
| 1632 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 1633 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1634 | |
| 1635 TestCompletionCallback callback; | |
| 1636 | |
| 1637 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1638 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1639 base::MessageLoop::current()->RunUntilIdle(); | |
| 1640 | |
| 1641 // Should have deferred for network start. | |
| 1642 EXPECT_TRUE(net_start_handler.observed_before_network_start()); | |
| 1643 EXPECT_EQ(LOAD_STATE_WAITING_FOR_DELEGATE, trans->GetLoadState()); | |
| 1644 EXPECT_TRUE(trans->GetResponseInfo() == NULL); | |
| 1645 | |
| 1646 trans->ResumeNetworkStart(); | |
| 1647 rv = callback.WaitForResult(); | |
| 1648 EXPECT_EQ(OK, rv); | |
| 1649 EXPECT_TRUE(trans->GetResponseInfo() != NULL); | |
| 1650 | |
| 1651 scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(100)); | |
| 1652 rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback()); | |
| 1653 if (rv == ERR_IO_PENDING) | |
| 1654 rv = callback.WaitForResult(); | |
| 1655 EXPECT_EQ(5, rv); | |
| 1656 trans.reset(); | |
| 1657 } | |
| 1658 | |
| 1659 // Test that network use can be deferred and canceled. | |
| 1660 TEST_P(HttpNetworkTransactionTest, ThrottleAndCancelBeforeNetworkStart) { | |
| 1661 HttpRequestInfo request; | |
| 1662 request.method = "GET"; | |
| 1663 request.url = GURL("http://www.google.com/"); | |
| 1664 request.load_flags = 0; | |
| 1665 | |
| 1666 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1667 scoped_ptr<HttpTransaction> trans( | |
| 1668 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1669 | |
| 1670 // Defer on OnBeforeNetworkStart. | |
| 1671 BeforeNetworkStartHandler net_start_handler(true); // defer | |
| 1672 trans->SetBeforeNetworkStartCallback( | |
| 1673 base::Bind(&BeforeNetworkStartHandler::OnBeforeNetworkStart, | |
| 1674 base::Unretained(&net_start_handler))); | |
| 1675 | |
| 1676 TestCompletionCallback callback; | |
| 1677 | |
| 1678 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1679 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1680 base::MessageLoop::current()->RunUntilIdle(); | |
| 1681 | |
| 1682 // Should have deferred for network start. | |
| 1683 EXPECT_TRUE(net_start_handler.observed_before_network_start()); | |
| 1684 EXPECT_EQ(LOAD_STATE_WAITING_FOR_DELEGATE, trans->GetLoadState()); | |
| 1685 EXPECT_TRUE(trans->GetResponseInfo() == NULL); | |
| 1686 } | |
| 1687 | |
| 1688 // Next 2 cases (KeepAliveEarlyClose and KeepAliveEarlyClose2) are regression | |
| 1689 // tests. There was a bug causing HttpNetworkTransaction to hang in the | |
| 1690 // destructor in such situations. | |
| 1691 // See http://crbug.com/154712 and http://crbug.com/156609. | |
| 1692 TEST_P(HttpNetworkTransactionTest, KeepAliveEarlyClose) { | |
| 1693 HttpRequestInfo request; | |
| 1694 request.method = "GET"; | |
| 1695 request.url = GURL("http://www.google.com/"); | |
| 1696 request.load_flags = 0; | |
| 1697 | |
| 1698 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1699 scoped_ptr<HttpTransaction> trans( | |
| 1700 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1701 | |
| 1702 MockRead data_reads[] = { | |
| 1703 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 1704 MockRead("Connection: keep-alive\r\n"), | |
| 1705 MockRead("Content-Length: 100\r\n\r\n"), | |
| 1706 MockRead("hello"), | |
| 1707 MockRead(SYNCHRONOUS, 0), | |
| 1708 }; | |
| 1709 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 1710 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1711 | |
| 1712 TestCompletionCallback callback; | |
| 1713 | |
| 1714 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1715 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1716 | |
| 1717 rv = callback.WaitForResult(); | |
| 1718 EXPECT_EQ(OK, rv); | |
| 1719 | |
| 1720 scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(100)); | |
| 1721 rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback()); | |
| 1722 if (rv == ERR_IO_PENDING) | |
| 1723 rv = callback.WaitForResult(); | |
| 1724 EXPECT_EQ(5, rv); | |
| 1725 rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback()); | |
| 1726 EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, rv); | |
| 1727 | |
| 1728 trans.reset(); | |
| 1729 base::MessageLoop::current()->RunUntilIdle(); | |
| 1730 EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 1731 } | |
| 1732 | |
| 1733 TEST_P(HttpNetworkTransactionTest, KeepAliveEarlyClose2) { | |
| 1734 HttpRequestInfo request; | |
| 1735 request.method = "GET"; | |
| 1736 request.url = GURL("http://www.google.com/"); | |
| 1737 request.load_flags = 0; | |
| 1738 | |
| 1739 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1740 scoped_ptr<HttpTransaction> trans( | |
| 1741 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1742 | |
| 1743 MockRead data_reads[] = { | |
| 1744 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 1745 MockRead("Connection: keep-alive\r\n"), | |
| 1746 MockRead("Content-Length: 100\r\n\r\n"), | |
| 1747 MockRead(SYNCHRONOUS, 0), | |
| 1748 }; | |
| 1749 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 1750 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 1751 | |
| 1752 TestCompletionCallback callback; | |
| 1753 | |
| 1754 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1755 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1756 | |
| 1757 rv = callback.WaitForResult(); | |
| 1758 EXPECT_EQ(OK, rv); | |
| 1759 | |
| 1760 scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(100)); | |
| 1761 rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback()); | |
| 1762 if (rv == ERR_IO_PENDING) | |
| 1763 rv = callback.WaitForResult(); | |
| 1764 EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, rv); | |
| 1765 | |
| 1766 trans.reset(); | |
| 1767 base::MessageLoop::current()->RunUntilIdle(); | |
| 1768 EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 1769 } | |
| 1770 | |
| 1771 // Test that we correctly reuse a keep-alive connection after not explicitly | |
| 1772 // reading the body. | |
| 1773 TEST_P(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) { | |
| 1774 HttpRequestInfo request; | |
| 1775 request.method = "GET"; | |
| 1776 request.url = GURL("http://www.foo.com/"); | |
| 1777 request.load_flags = 0; | |
| 1778 | |
| 1779 CapturingNetLog net_log; | |
| 1780 session_deps_.net_log = &net_log; | |
| 1781 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1782 | |
| 1783 // Note that because all these reads happen in the same | |
| 1784 // StaticSocketDataProvider, it shows that the same socket is being reused for | |
| 1785 // all transactions. | |
| 1786 MockRead data1_reads[] = { | |
| 1787 MockRead("HTTP/1.1 204 No Content\r\n\r\n"), | |
| 1788 MockRead("HTTP/1.1 205 Reset Content\r\n\r\n"), | |
| 1789 MockRead("HTTP/1.1 304 Not Modified\r\n\r\n"), | |
| 1790 MockRead("HTTP/1.1 302 Found\r\n" | |
| 1791 "Content-Length: 0\r\n\r\n"), | |
| 1792 MockRead("HTTP/1.1 302 Found\r\n" | |
| 1793 "Content-Length: 5\r\n\r\n" | |
| 1794 "hello"), | |
| 1795 MockRead("HTTP/1.1 301 Moved Permanently\r\n" | |
| 1796 "Content-Length: 0\r\n\r\n"), | |
| 1797 MockRead("HTTP/1.1 301 Moved Permanently\r\n" | |
| 1798 "Content-Length: 5\r\n\r\n" | |
| 1799 "hello"), | |
| 1800 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
| 1801 MockRead("hello"), | |
| 1802 }; | |
| 1803 StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), NULL, 0); | |
| 1804 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 1805 | |
| 1806 MockRead data2_reads[] = { | |
| 1807 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 1808 }; | |
| 1809 StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0); | |
| 1810 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 1811 | |
| 1812 const int kNumUnreadBodies = arraysize(data1_reads) - 2; | |
| 1813 std::string response_lines[kNumUnreadBodies]; | |
| 1814 | |
| 1815 uint32 first_socket_log_id = NetLog::Source::kInvalidId; | |
| 1816 for (size_t i = 0; i < arraysize(data1_reads) - 2; ++i) { | |
| 1817 TestCompletionCallback callback; | |
| 1818 | |
| 1819 scoped_ptr<HttpTransaction> trans( | |
| 1820 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1821 | |
| 1822 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1823 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1824 | |
| 1825 rv = callback.WaitForResult(); | |
| 1826 EXPECT_EQ(OK, rv); | |
| 1827 | |
| 1828 LoadTimingInfo load_timing_info; | |
| 1829 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 1830 if (i == 0) { | |
| 1831 TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_DNS_TIMES); | |
| 1832 first_socket_log_id = load_timing_info.socket_log_id; | |
| 1833 } else { | |
| 1834 TestLoadTimingReused(load_timing_info); | |
| 1835 EXPECT_EQ(first_socket_log_id, load_timing_info.socket_log_id); | |
| 1836 } | |
| 1837 | |
| 1838 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1839 ASSERT_TRUE(response != NULL); | |
| 1840 | |
| 1841 ASSERT_TRUE(response->headers.get() != NULL); | |
| 1842 response_lines[i] = response->headers->GetStatusLine(); | |
| 1843 | |
| 1844 // We intentionally don't read the response bodies. | |
| 1845 } | |
| 1846 | |
| 1847 const char* const kStatusLines[] = { | |
| 1848 "HTTP/1.1 204 No Content", | |
| 1849 "HTTP/1.1 205 Reset Content", | |
| 1850 "HTTP/1.1 304 Not Modified", | |
| 1851 "HTTP/1.1 302 Found", | |
| 1852 "HTTP/1.1 302 Found", | |
| 1853 "HTTP/1.1 301 Moved Permanently", | |
| 1854 "HTTP/1.1 301 Moved Permanently", | |
| 1855 }; | |
| 1856 | |
| 1857 static_assert(kNumUnreadBodies == arraysize(kStatusLines), | |
| 1858 "forgot to update kStatusLines"); | |
| 1859 | |
| 1860 for (int i = 0; i < kNumUnreadBodies; ++i) | |
| 1861 EXPECT_EQ(kStatusLines[i], response_lines[i]); | |
| 1862 | |
| 1863 TestCompletionCallback callback; | |
| 1864 scoped_ptr<HttpTransaction> trans( | |
| 1865 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1866 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1867 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1868 rv = callback.WaitForResult(); | |
| 1869 EXPECT_EQ(OK, rv); | |
| 1870 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1871 ASSERT_TRUE(response != NULL); | |
| 1872 ASSERT_TRUE(response->headers.get() != NULL); | |
| 1873 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 1874 std::string response_data; | |
| 1875 rv = ReadTransaction(trans.get(), &response_data); | |
| 1876 EXPECT_EQ(OK, rv); | |
| 1877 EXPECT_EQ("hello", response_data); | |
| 1878 } | |
| 1879 | |
| 1880 // Test the request-challenge-retry sequence for basic auth. | |
| 1881 // (basic auth is the easiest to mock, because it has no randomness). | |
| 1882 TEST_P(HttpNetworkTransactionTest, BasicAuth) { | |
| 1883 HttpRequestInfo request; | |
| 1884 request.method = "GET"; | |
| 1885 request.url = GURL("http://www.google.com/"); | |
| 1886 request.load_flags = 0; | |
| 1887 | |
| 1888 CapturingNetLog log; | |
| 1889 session_deps_.net_log = &log; | |
| 1890 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1891 scoped_ptr<HttpTransaction> trans( | |
| 1892 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1893 | |
| 1894 MockWrite data_writes1[] = { | |
| 1895 MockWrite("GET / HTTP/1.1\r\n" | |
| 1896 "Host: www.google.com\r\n" | |
| 1897 "Connection: keep-alive\r\n\r\n"), | |
| 1898 }; | |
| 1899 | |
| 1900 MockRead data_reads1[] = { | |
| 1901 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 1902 // Give a couple authenticate options (only the middle one is actually | |
| 1903 // supported). | |
| 1904 MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed. | |
| 1905 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1906 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), | |
| 1907 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1908 // Large content-length -- won't matter, as connection will be reset. | |
| 1909 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 1910 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 1911 }; | |
| 1912 | |
| 1913 // After calling trans->RestartWithAuth(), this is the request we should | |
| 1914 // be issuing -- the final header line contains the credentials. | |
| 1915 MockWrite data_writes2[] = { | |
| 1916 MockWrite("GET / HTTP/1.1\r\n" | |
| 1917 "Host: www.google.com\r\n" | |
| 1918 "Connection: keep-alive\r\n" | |
| 1919 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 1920 }; | |
| 1921 | |
| 1922 // Lastly, the server responds with the actual content. | |
| 1923 MockRead data_reads2[] = { | |
| 1924 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 1925 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1926 MockRead("Content-Length: 100\r\n\r\n"), | |
| 1927 MockRead(SYNCHRONOUS, OK), | |
| 1928 }; | |
| 1929 | |
| 1930 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 1931 data_writes1, arraysize(data_writes1)); | |
| 1932 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 1933 data_writes2, arraysize(data_writes2)); | |
| 1934 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 1935 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 1936 | |
| 1937 TestCompletionCallback callback1; | |
| 1938 | |
| 1939 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 1940 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1941 | |
| 1942 rv = callback1.WaitForResult(); | |
| 1943 EXPECT_EQ(OK, rv); | |
| 1944 | |
| 1945 LoadTimingInfo load_timing_info1; | |
| 1946 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info1)); | |
| 1947 TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_DNS_TIMES); | |
| 1948 | |
| 1949 int64 reads_size1 = ReadsSize(data_reads1, arraysize(data_reads1)); | |
| 1950 EXPECT_EQ(reads_size1, trans->GetTotalReceivedBytes()); | |
| 1951 | |
| 1952 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1953 ASSERT_TRUE(response != NULL); | |
| 1954 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 1955 | |
| 1956 TestCompletionCallback callback2; | |
| 1957 | |
| 1958 rv = trans->RestartWithAuth( | |
| 1959 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 1960 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1961 | |
| 1962 rv = callback2.WaitForResult(); | |
| 1963 EXPECT_EQ(OK, rv); | |
| 1964 | |
| 1965 LoadTimingInfo load_timing_info2; | |
| 1966 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info2)); | |
| 1967 TestLoadTimingNotReused(load_timing_info2, CONNECT_TIMING_HAS_DNS_TIMES); | |
| 1968 // The load timing after restart should have a new socket ID, and times after | |
| 1969 // those of the first load timing. | |
| 1970 EXPECT_LE(load_timing_info1.receive_headers_end, | |
| 1971 load_timing_info2.connect_timing.connect_start); | |
| 1972 EXPECT_NE(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id); | |
| 1973 | |
| 1974 int64 reads_size2 = ReadsSize(data_reads2, arraysize(data_reads2)); | |
| 1975 EXPECT_EQ(reads_size1 + reads_size2, trans->GetTotalReceivedBytes()); | |
| 1976 | |
| 1977 response = trans->GetResponseInfo(); | |
| 1978 ASSERT_TRUE(response != NULL); | |
| 1979 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 1980 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 1981 } | |
| 1982 | |
| 1983 TEST_P(HttpNetworkTransactionTest, DoNotSendAuth) { | |
| 1984 HttpRequestInfo request; | |
| 1985 request.method = "GET"; | |
| 1986 request.url = GURL("http://www.google.com/"); | |
| 1987 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
| 1988 | |
| 1989 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 1990 scoped_ptr<HttpTransaction> trans( | |
| 1991 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 1992 | |
| 1993 MockWrite data_writes[] = { | |
| 1994 MockWrite("GET / HTTP/1.1\r\n" | |
| 1995 "Host: www.google.com\r\n" | |
| 1996 "Connection: keep-alive\r\n\r\n"), | |
| 1997 }; | |
| 1998 | |
| 1999 MockRead data_reads[] = { | |
| 2000 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 2001 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2002 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2003 // Large content-length -- won't matter, as connection will be reset. | |
| 2004 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 2005 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 2006 }; | |
| 2007 | |
| 2008 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 2009 data_writes, arraysize(data_writes)); | |
| 2010 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 2011 TestCompletionCallback callback; | |
| 2012 | |
| 2013 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 2014 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2015 | |
| 2016 rv = callback.WaitForResult(); | |
| 2017 EXPECT_EQ(0, rv); | |
| 2018 | |
| 2019 int64 reads_size = ReadsSize(data_reads, arraysize(data_reads)); | |
| 2020 EXPECT_EQ(reads_size, trans->GetTotalReceivedBytes()); | |
| 2021 | |
| 2022 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2023 ASSERT_TRUE(response != NULL); | |
| 2024 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 2025 } | |
| 2026 | |
| 2027 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
| 2028 // connection. | |
| 2029 TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAlive) { | |
| 2030 HttpRequestInfo request; | |
| 2031 request.method = "GET"; | |
| 2032 request.url = GURL("http://www.google.com/"); | |
| 2033 request.load_flags = 0; | |
| 2034 | |
| 2035 CapturingNetLog log; | |
| 2036 session_deps_.net_log = &log; | |
| 2037 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2038 | |
| 2039 MockWrite data_writes1[] = { | |
| 2040 MockWrite("GET / HTTP/1.1\r\n" | |
| 2041 "Host: www.google.com\r\n" | |
| 2042 "Connection: keep-alive\r\n\r\n"), | |
| 2043 | |
| 2044 // After calling trans->RestartWithAuth(), this is the request we should | |
| 2045 // be issuing -- the final header line contains the credentials. | |
| 2046 MockWrite("GET / HTTP/1.1\r\n" | |
| 2047 "Host: www.google.com\r\n" | |
| 2048 "Connection: keep-alive\r\n" | |
| 2049 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 2050 }; | |
| 2051 | |
| 2052 MockRead data_reads1[] = { | |
| 2053 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
| 2054 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2055 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2056 MockRead("Content-Length: 14\r\n\r\n"), | |
| 2057 MockRead("Unauthorized\r\n"), | |
| 2058 | |
| 2059 // Lastly, the server responds with the actual content. | |
| 2060 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 2061 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2062 MockRead("Content-Length: 5\r\n\r\n"), | |
| 2063 MockRead("Hello"), | |
| 2064 }; | |
| 2065 | |
| 2066 // If there is a regression where we disconnect a Keep-Alive | |
| 2067 // connection during an auth roundtrip, we'll end up reading this. | |
| 2068 MockRead data_reads2[] = { | |
| 2069 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 2070 }; | |
| 2071 | |
| 2072 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2073 data_writes1, arraysize(data_writes1)); | |
| 2074 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 2075 NULL, 0); | |
| 2076 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 2077 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 2078 | |
| 2079 TestCompletionCallback callback1; | |
| 2080 | |
| 2081 scoped_ptr<HttpTransaction> trans( | |
| 2082 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2083 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 2084 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2085 | |
| 2086 rv = callback1.WaitForResult(); | |
| 2087 EXPECT_EQ(OK, rv); | |
| 2088 | |
| 2089 LoadTimingInfo load_timing_info1; | |
| 2090 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info1)); | |
| 2091 TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_DNS_TIMES); | |
| 2092 | |
| 2093 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2094 ASSERT_TRUE(response != NULL); | |
| 2095 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 2096 | |
| 2097 TestCompletionCallback callback2; | |
| 2098 | |
| 2099 rv = trans->RestartWithAuth( | |
| 2100 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 2101 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2102 | |
| 2103 rv = callback2.WaitForResult(); | |
| 2104 EXPECT_EQ(OK, rv); | |
| 2105 | |
| 2106 LoadTimingInfo load_timing_info2; | |
| 2107 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info2)); | |
| 2108 TestLoadTimingReused(load_timing_info2); | |
| 2109 // The load timing after restart should have the same socket ID, and times | |
| 2110 // those of the first load timing. | |
| 2111 EXPECT_LE(load_timing_info1.receive_headers_end, | |
| 2112 load_timing_info2.send_start); | |
| 2113 EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id); | |
| 2114 | |
| 2115 response = trans->GetResponseInfo(); | |
| 2116 ASSERT_TRUE(response != NULL); | |
| 2117 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 2118 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 2119 | |
| 2120 std::string response_data; | |
| 2121 rv = ReadTransaction(trans.get(), &response_data); | |
| 2122 EXPECT_EQ(OK, rv); | |
| 2123 int64 reads_size1 = ReadsSize(data_reads1, arraysize(data_reads1)); | |
| 2124 EXPECT_EQ(reads_size1, trans->GetTotalReceivedBytes()); | |
| 2125 } | |
| 2126 | |
| 2127 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
| 2128 // connection and with no response body to drain. | |
| 2129 TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) { | |
| 2130 HttpRequestInfo request; | |
| 2131 request.method = "GET"; | |
| 2132 request.url = GURL("http://www.google.com/"); | |
| 2133 request.load_flags = 0; | |
| 2134 | |
| 2135 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2136 | |
| 2137 MockWrite data_writes1[] = { | |
| 2138 MockWrite("GET / HTTP/1.1\r\n" | |
| 2139 "Host: www.google.com\r\n" | |
| 2140 "Connection: keep-alive\r\n\r\n"), | |
| 2141 | |
| 2142 // After calling trans->RestartWithAuth(), this is the request we should | |
| 2143 // be issuing -- the final header line contains the credentials. | |
| 2144 MockWrite("GET / HTTP/1.1\r\n" | |
| 2145 "Host: www.google.com\r\n" | |
| 2146 "Connection: keep-alive\r\n" | |
| 2147 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 2148 }; | |
| 2149 | |
| 2150 MockRead data_reads1[] = { | |
| 2151 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
| 2152 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2153 MockRead("Content-Length: 0\r\n\r\n"), // No response body. | |
| 2154 | |
| 2155 // Lastly, the server responds with the actual content. | |
| 2156 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 2157 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2158 MockRead("Content-Length: 5\r\n\r\n"), | |
| 2159 MockRead("hello"), | |
| 2160 }; | |
| 2161 | |
| 2162 // An incorrect reconnect would cause this to be read. | |
| 2163 MockRead data_reads2[] = { | |
| 2164 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 2165 }; | |
| 2166 | |
| 2167 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2168 data_writes1, arraysize(data_writes1)); | |
| 2169 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 2170 NULL, 0); | |
| 2171 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 2172 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 2173 | |
| 2174 TestCompletionCallback callback1; | |
| 2175 | |
| 2176 scoped_ptr<HttpTransaction> trans( | |
| 2177 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2178 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 2179 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2180 | |
| 2181 rv = callback1.WaitForResult(); | |
| 2182 EXPECT_EQ(OK, rv); | |
| 2183 | |
| 2184 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2185 ASSERT_TRUE(response != NULL); | |
| 2186 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 2187 | |
| 2188 TestCompletionCallback callback2; | |
| 2189 | |
| 2190 rv = trans->RestartWithAuth( | |
| 2191 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 2192 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2193 | |
| 2194 rv = callback2.WaitForResult(); | |
| 2195 EXPECT_EQ(OK, rv); | |
| 2196 | |
| 2197 response = trans->GetResponseInfo(); | |
| 2198 ASSERT_TRUE(response != NULL); | |
| 2199 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 2200 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 2201 } | |
| 2202 | |
| 2203 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
| 2204 // connection and with a large response body to drain. | |
| 2205 TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) { | |
| 2206 HttpRequestInfo request; | |
| 2207 request.method = "GET"; | |
| 2208 request.url = GURL("http://www.google.com/"); | |
| 2209 request.load_flags = 0; | |
| 2210 | |
| 2211 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2212 | |
| 2213 MockWrite data_writes1[] = { | |
| 2214 MockWrite("GET / HTTP/1.1\r\n" | |
| 2215 "Host: www.google.com\r\n" | |
| 2216 "Connection: keep-alive\r\n\r\n"), | |
| 2217 | |
| 2218 // After calling trans->RestartWithAuth(), this is the request we should | |
| 2219 // be issuing -- the final header line contains the credentials. | |
| 2220 MockWrite("GET / HTTP/1.1\r\n" | |
| 2221 "Host: www.google.com\r\n" | |
| 2222 "Connection: keep-alive\r\n" | |
| 2223 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 2224 }; | |
| 2225 | |
| 2226 // Respond with 5 kb of response body. | |
| 2227 std::string large_body_string("Unauthorized"); | |
| 2228 large_body_string.append(5 * 1024, ' '); | |
| 2229 large_body_string.append("\r\n"); | |
| 2230 | |
| 2231 MockRead data_reads1[] = { | |
| 2232 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
| 2233 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2234 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2235 // 5134 = 12 + 5 * 1024 + 2 | |
| 2236 MockRead("Content-Length: 5134\r\n\r\n"), | |
| 2237 MockRead(ASYNC, large_body_string.data(), large_body_string.size()), | |
| 2238 | |
| 2239 // Lastly, the server responds with the actual content. | |
| 2240 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 2241 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2242 MockRead("Content-Length: 5\r\n\r\n"), | |
| 2243 MockRead("hello"), | |
| 2244 }; | |
| 2245 | |
| 2246 // An incorrect reconnect would cause this to be read. | |
| 2247 MockRead data_reads2[] = { | |
| 2248 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 2249 }; | |
| 2250 | |
| 2251 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2252 data_writes1, arraysize(data_writes1)); | |
| 2253 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 2254 NULL, 0); | |
| 2255 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 2256 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 2257 | |
| 2258 TestCompletionCallback callback1; | |
| 2259 | |
| 2260 scoped_ptr<HttpTransaction> trans( | |
| 2261 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2262 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 2263 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2264 | |
| 2265 rv = callback1.WaitForResult(); | |
| 2266 EXPECT_EQ(OK, rv); | |
| 2267 | |
| 2268 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2269 ASSERT_TRUE(response != NULL); | |
| 2270 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 2271 | |
| 2272 TestCompletionCallback callback2; | |
| 2273 | |
| 2274 rv = trans->RestartWithAuth( | |
| 2275 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 2276 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2277 | |
| 2278 rv = callback2.WaitForResult(); | |
| 2279 EXPECT_EQ(OK, rv); | |
| 2280 | |
| 2281 response = trans->GetResponseInfo(); | |
| 2282 ASSERT_TRUE(response != NULL); | |
| 2283 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 2284 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 2285 } | |
| 2286 | |
| 2287 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
| 2288 // connection, but the server gets impatient and closes the connection. | |
| 2289 TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) { | |
| 2290 HttpRequestInfo request; | |
| 2291 request.method = "GET"; | |
| 2292 request.url = GURL("http://www.google.com/"); | |
| 2293 request.load_flags = 0; | |
| 2294 | |
| 2295 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2296 | |
| 2297 MockWrite data_writes1[] = { | |
| 2298 MockWrite("GET / HTTP/1.1\r\n" | |
| 2299 "Host: www.google.com\r\n" | |
| 2300 "Connection: keep-alive\r\n\r\n"), | |
| 2301 // This simulates the seemingly successful write to a closed connection | |
| 2302 // if the bug is not fixed. | |
| 2303 MockWrite("GET / HTTP/1.1\r\n" | |
| 2304 "Host: www.google.com\r\n" | |
| 2305 "Connection: keep-alive\r\n" | |
| 2306 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 2307 }; | |
| 2308 | |
| 2309 MockRead data_reads1[] = { | |
| 2310 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
| 2311 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2312 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2313 MockRead("Content-Length: 14\r\n\r\n"), | |
| 2314 // Tell MockTCPClientSocket to simulate the server closing the connection. | |
| 2315 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 2316 MockRead("Unauthorized\r\n"), | |
| 2317 MockRead(SYNCHRONOUS, OK), // The server closes the connection. | |
| 2318 }; | |
| 2319 | |
| 2320 // After calling trans->RestartWithAuth(), this is the request we should | |
| 2321 // be issuing -- the final header line contains the credentials. | |
| 2322 MockWrite data_writes2[] = { | |
| 2323 MockWrite("GET / HTTP/1.1\r\n" | |
| 2324 "Host: www.google.com\r\n" | |
| 2325 "Connection: keep-alive\r\n" | |
| 2326 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 2327 }; | |
| 2328 | |
| 2329 // Lastly, the server responds with the actual content. | |
| 2330 MockRead data_reads2[] = { | |
| 2331 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 2332 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2333 MockRead("Content-Length: 5\r\n\r\n"), | |
| 2334 MockRead("hello"), | |
| 2335 }; | |
| 2336 | |
| 2337 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2338 data_writes1, arraysize(data_writes1)); | |
| 2339 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 2340 data_writes2, arraysize(data_writes2)); | |
| 2341 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 2342 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 2343 | |
| 2344 TestCompletionCallback callback1; | |
| 2345 | |
| 2346 scoped_ptr<HttpTransaction> trans( | |
| 2347 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2348 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 2349 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2350 | |
| 2351 rv = callback1.WaitForResult(); | |
| 2352 EXPECT_EQ(OK, rv); | |
| 2353 | |
| 2354 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2355 ASSERT_TRUE(response != NULL); | |
| 2356 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 2357 | |
| 2358 TestCompletionCallback callback2; | |
| 2359 | |
| 2360 rv = trans->RestartWithAuth( | |
| 2361 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 2362 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2363 | |
| 2364 rv = callback2.WaitForResult(); | |
| 2365 EXPECT_EQ(OK, rv); | |
| 2366 | |
| 2367 response = trans->GetResponseInfo(); | |
| 2368 ASSERT_TRUE(response != NULL); | |
| 2369 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 2370 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 2371 } | |
| 2372 | |
| 2373 // Test the request-challenge-retry sequence for basic auth, over a connection | |
| 2374 // that requires a restart when setting up an SSL tunnel. | |
| 2375 TEST_P(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) { | |
| 2376 HttpRequestInfo request; | |
| 2377 request.method = "GET"; | |
| 2378 request.url = GURL("https://www.google.com/"); | |
| 2379 // when the no authentication data flag is set. | |
| 2380 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
| 2381 | |
| 2382 // Configure against proxy server "myproxy:70". | |
| 2383 session_deps_.proxy_service.reset( | |
| 2384 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); | |
| 2385 CapturingBoundNetLog log; | |
| 2386 session_deps_.net_log = log.bound().net_log(); | |
| 2387 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2388 | |
| 2389 // Since we have proxy, should try to establish tunnel. | |
| 2390 MockWrite data_writes1[] = { | |
| 2391 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 2392 "Host: www.google.com\r\n" | |
| 2393 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2394 | |
| 2395 // After calling trans->RestartWithAuth(), this is the request we should | |
| 2396 // be issuing -- the final header line contains the credentials. | |
| 2397 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 2398 "Host: www.google.com\r\n" | |
| 2399 "Proxy-Connection: keep-alive\r\n" | |
| 2400 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 2401 | |
| 2402 MockWrite("GET / HTTP/1.1\r\n" | |
| 2403 "Host: www.google.com\r\n" | |
| 2404 "Connection: keep-alive\r\n\r\n"), | |
| 2405 }; | |
| 2406 | |
| 2407 // The proxy responds to the connect with a 407, using a persistent | |
| 2408 // connection. | |
| 2409 MockRead data_reads1[] = { | |
| 2410 // No credentials. | |
| 2411 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 2412 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2413 MockRead("Proxy-Connection: close\r\n\r\n"), | |
| 2414 | |
| 2415 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 2416 | |
| 2417 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 2418 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2419 MockRead("Content-Length: 5\r\n\r\n"), | |
| 2420 MockRead(SYNCHRONOUS, "hello"), | |
| 2421 }; | |
| 2422 | |
| 2423 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2424 data_writes1, arraysize(data_writes1)); | |
| 2425 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 2426 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2427 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 2428 | |
| 2429 TestCompletionCallback callback1; | |
| 2430 | |
| 2431 scoped_ptr<HttpTransaction> trans( | |
| 2432 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2433 | |
| 2434 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 2435 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2436 | |
| 2437 rv = callback1.WaitForResult(); | |
| 2438 EXPECT_EQ(OK, rv); | |
| 2439 net::CapturingNetLog::CapturedEntryList entries; | |
| 2440 log.GetEntries(&entries); | |
| 2441 size_t pos = ExpectLogContainsSomewhere( | |
| 2442 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 2443 NetLog::PHASE_NONE); | |
| 2444 ExpectLogContainsSomewhere( | |
| 2445 entries, pos, | |
| 2446 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 2447 NetLog::PHASE_NONE); | |
| 2448 | |
| 2449 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2450 ASSERT_TRUE(response != NULL); | |
| 2451 ASSERT_FALSE(response->headers.get() == NULL); | |
| 2452 EXPECT_EQ(407, response->headers->response_code()); | |
| 2453 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 2454 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 2455 | |
| 2456 LoadTimingInfo load_timing_info; | |
| 2457 // CONNECT requests and responses are handled at the connect job level, so | |
| 2458 // the transaction does not yet have a connection. | |
| 2459 EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 2460 | |
| 2461 TestCompletionCallback callback2; | |
| 2462 | |
| 2463 rv = trans->RestartWithAuth( | |
| 2464 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 2465 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2466 | |
| 2467 rv = callback2.WaitForResult(); | |
| 2468 EXPECT_EQ(OK, rv); | |
| 2469 | |
| 2470 response = trans->GetResponseInfo(); | |
| 2471 ASSERT_TRUE(response != NULL); | |
| 2472 | |
| 2473 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 2474 EXPECT_EQ(200, response->headers->response_code()); | |
| 2475 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 2476 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 2477 | |
| 2478 // The password prompt info should not be set. | |
| 2479 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 2480 | |
| 2481 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 2482 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 2483 CONNECT_TIMING_HAS_SSL_TIMES); | |
| 2484 | |
| 2485 trans.reset(); | |
| 2486 session->CloseAllConnections(); | |
| 2487 } | |
| 2488 | |
| 2489 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
| 2490 // proxy connection, when setting up an SSL tunnel. | |
| 2491 TEST_P(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) { | |
| 2492 HttpRequestInfo request; | |
| 2493 request.method = "GET"; | |
| 2494 request.url = GURL("https://www.google.com/"); | |
| 2495 // Ensure that proxy authentication is attempted even | |
| 2496 // when the no authentication data flag is set. | |
| 2497 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
| 2498 | |
| 2499 // Configure against proxy server "myproxy:70". | |
| 2500 session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); | |
| 2501 CapturingBoundNetLog log; | |
| 2502 session_deps_.net_log = log.bound().net_log(); | |
| 2503 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2504 | |
| 2505 scoped_ptr<HttpTransaction> trans( | |
| 2506 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2507 | |
| 2508 // Since we have proxy, should try to establish tunnel. | |
| 2509 MockWrite data_writes1[] = { | |
| 2510 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 2511 "Host: www.google.com\r\n" | |
| 2512 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2513 | |
| 2514 // After calling trans->RestartWithAuth(), this is the request we should | |
| 2515 // be issuing -- the final header line contains the credentials. | |
| 2516 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 2517 "Host: www.google.com\r\n" | |
| 2518 "Proxy-Connection: keep-alive\r\n" | |
| 2519 "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), | |
| 2520 }; | |
| 2521 | |
| 2522 // The proxy responds to the connect with a 407, using a persistent | |
| 2523 // connection. | |
| 2524 MockRead data_reads1[] = { | |
| 2525 // No credentials. | |
| 2526 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 2527 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2528 MockRead("Content-Length: 10\r\n\r\n"), | |
| 2529 MockRead("0123456789"), | |
| 2530 | |
| 2531 // Wrong credentials (wrong password). | |
| 2532 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 2533 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2534 MockRead("Content-Length: 10\r\n\r\n"), | |
| 2535 // No response body because the test stops reading here. | |
| 2536 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 2537 }; | |
| 2538 | |
| 2539 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2540 data_writes1, arraysize(data_writes1)); | |
| 2541 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 2542 | |
| 2543 TestCompletionCallback callback1; | |
| 2544 | |
| 2545 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 2546 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2547 | |
| 2548 rv = callback1.WaitForResult(); | |
| 2549 EXPECT_EQ(OK, rv); | |
| 2550 net::CapturingNetLog::CapturedEntryList entries; | |
| 2551 log.GetEntries(&entries); | |
| 2552 size_t pos = ExpectLogContainsSomewhere( | |
| 2553 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 2554 NetLog::PHASE_NONE); | |
| 2555 ExpectLogContainsSomewhere( | |
| 2556 entries, pos, | |
| 2557 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 2558 NetLog::PHASE_NONE); | |
| 2559 | |
| 2560 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2561 ASSERT_TRUE(response); | |
| 2562 ASSERT_TRUE(response->headers); | |
| 2563 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 2564 EXPECT_EQ(407, response->headers->response_code()); | |
| 2565 EXPECT_EQ(-1, response->headers->GetContentLength()); | |
| 2566 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 2567 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 2568 | |
| 2569 TestCompletionCallback callback2; | |
| 2570 | |
| 2571 // Wrong password (should be "bar"). | |
| 2572 rv = trans->RestartWithAuth( | |
| 2573 AuthCredentials(kFoo, kBaz), callback2.callback()); | |
| 2574 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2575 | |
| 2576 rv = callback2.WaitForResult(); | |
| 2577 EXPECT_EQ(OK, rv); | |
| 2578 | |
| 2579 response = trans->GetResponseInfo(); | |
| 2580 ASSERT_TRUE(response); | |
| 2581 ASSERT_TRUE(response->headers); | |
| 2582 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 2583 EXPECT_EQ(407, response->headers->response_code()); | |
| 2584 EXPECT_EQ(-1, response->headers->GetContentLength()); | |
| 2585 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 2586 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 2587 | |
| 2588 // Flush the idle socket before the NetLog and HttpNetworkTransaction go | |
| 2589 // out of scope. | |
| 2590 session->CloseAllConnections(); | |
| 2591 } | |
| 2592 | |
| 2593 // Test that we don't read the response body when we fail to establish a tunnel, | |
| 2594 // even if the user cancels the proxy's auth attempt. | |
| 2595 TEST_P(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) { | |
| 2596 HttpRequestInfo request; | |
| 2597 request.method = "GET"; | |
| 2598 request.url = GURL("https://www.google.com/"); | |
| 2599 request.load_flags = 0; | |
| 2600 | |
| 2601 // Configure against proxy server "myproxy:70". | |
| 2602 session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); | |
| 2603 | |
| 2604 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2605 | |
| 2606 scoped_ptr<HttpTransaction> trans( | |
| 2607 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2608 | |
| 2609 // Since we have proxy, should try to establish tunnel. | |
| 2610 MockWrite data_writes[] = { | |
| 2611 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 2612 "Host: www.google.com\r\n" | |
| 2613 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2614 }; | |
| 2615 | |
| 2616 // The proxy responds to the connect with a 407. | |
| 2617 MockRead data_reads[] = { | |
| 2618 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 2619 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2620 MockRead("Content-Length: 10\r\n\r\n"), | |
| 2621 MockRead("0123456789"), // Should not be reached. | |
| 2622 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), | |
| 2623 }; | |
| 2624 | |
| 2625 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 2626 data_writes, arraysize(data_writes)); | |
| 2627 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 2628 | |
| 2629 TestCompletionCallback callback; | |
| 2630 | |
| 2631 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 2632 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2633 | |
| 2634 rv = callback.WaitForResult(); | |
| 2635 EXPECT_EQ(OK, rv); | |
| 2636 | |
| 2637 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2638 ASSERT_TRUE(response); | |
| 2639 ASSERT_TRUE(response->headers); | |
| 2640 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 2641 EXPECT_EQ(407, response->headers->response_code()); | |
| 2642 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 2643 | |
| 2644 std::string response_data; | |
| 2645 rv = ReadTransaction(trans.get(), &response_data); | |
| 2646 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
| 2647 | |
| 2648 // Flush the idle socket before the HttpNetworkTransaction goes out of scope. | |
| 2649 session->CloseAllConnections(); | |
| 2650 } | |
| 2651 | |
| 2652 // Test that we don't pass extraneous headers from the proxy's response to the | |
| 2653 // caller when the proxy responds to CONNECT with 407. | |
| 2654 TEST_P(HttpNetworkTransactionTest, SanitizeProxyAuthHeaders) { | |
| 2655 HttpRequestInfo request; | |
| 2656 request.method = "GET"; | |
| 2657 request.url = GURL("https://www.google.com/"); | |
| 2658 request.load_flags = 0; | |
| 2659 | |
| 2660 // Configure against proxy server "myproxy:70". | |
| 2661 session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); | |
| 2662 | |
| 2663 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2664 | |
| 2665 scoped_ptr<HttpTransaction> trans( | |
| 2666 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2667 | |
| 2668 // Since we have proxy, should try to establish tunnel. | |
| 2669 MockWrite data_writes[] = { | |
| 2670 MockWrite( | |
| 2671 "CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 2672 "Host: www.google.com\r\n" | |
| 2673 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2674 }; | |
| 2675 | |
| 2676 // The proxy responds to the connect with a 407. | |
| 2677 MockRead data_reads[] = { | |
| 2678 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 2679 MockRead("X-Foo: bar\r\n"), | |
| 2680 MockRead("Set-Cookie: foo=bar\r\n"), | |
| 2681 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2682 MockRead("Content-Length: 10\r\n\r\n"), | |
| 2683 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 2684 }; | |
| 2685 | |
| 2686 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 2687 arraysize(data_writes)); | |
| 2688 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 2689 | |
| 2690 TestCompletionCallback callback; | |
| 2691 | |
| 2692 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 2693 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2694 | |
| 2695 rv = callback.WaitForResult(); | |
| 2696 EXPECT_EQ(OK, rv); | |
| 2697 | |
| 2698 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2699 ASSERT_TRUE(response); | |
| 2700 ASSERT_TRUE(response->headers); | |
| 2701 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 2702 EXPECT_EQ(407, response->headers->response_code()); | |
| 2703 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 2704 EXPECT_FALSE(response->headers->HasHeader("X-Foo")); | |
| 2705 EXPECT_FALSE(response->headers->HasHeader("Set-Cookie")); | |
| 2706 | |
| 2707 std::string response_data; | |
| 2708 rv = ReadTransaction(trans.get(), &response_data); | |
| 2709 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
| 2710 | |
| 2711 // Flush the idle socket before the HttpNetworkTransaction goes out of scope. | |
| 2712 session->CloseAllConnections(); | |
| 2713 } | |
| 2714 | |
| 2715 // Test when a server (non-proxy) returns a 407 (proxy-authenticate). | |
| 2716 // The request should fail with ERR_UNEXPECTED_PROXY_AUTH. | |
| 2717 TEST_P(HttpNetworkTransactionTest, UnexpectedProxyAuth) { | |
| 2718 HttpRequestInfo request; | |
| 2719 request.method = "GET"; | |
| 2720 request.url = GURL("http://www.google.com/"); | |
| 2721 request.load_flags = 0; | |
| 2722 | |
| 2723 // We are using a DIRECT connection (i.e. no proxy) for this session. | |
| 2724 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2725 scoped_ptr<HttpTransaction> trans( | |
| 2726 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2727 | |
| 2728 MockWrite data_writes1[] = { | |
| 2729 MockWrite("GET / HTTP/1.1\r\n" | |
| 2730 "Host: www.google.com\r\n" | |
| 2731 "Connection: keep-alive\r\n\r\n"), | |
| 2732 }; | |
| 2733 | |
| 2734 MockRead data_reads1[] = { | |
| 2735 MockRead("HTTP/1.0 407 Proxy Auth required\r\n"), | |
| 2736 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2737 // Large content-length -- won't matter, as connection will be reset. | |
| 2738 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 2739 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 2740 }; | |
| 2741 | |
| 2742 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2743 data_writes1, arraysize(data_writes1)); | |
| 2744 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 2745 | |
| 2746 TestCompletionCallback callback; | |
| 2747 | |
| 2748 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 2749 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2750 | |
| 2751 rv = callback.WaitForResult(); | |
| 2752 EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); | |
| 2753 } | |
| 2754 | |
| 2755 // Tests when an HTTPS server (non-proxy) returns a 407 (proxy-authentication) | |
| 2756 // through a non-authenticating proxy. The request should fail with | |
| 2757 // ERR_UNEXPECTED_PROXY_AUTH. | |
| 2758 // Note that it is impossible to detect if an HTTP server returns a 407 through | |
| 2759 // a non-authenticating proxy - there is nothing to indicate whether the | |
| 2760 // response came from the proxy or the server, so it is treated as if the proxy | |
| 2761 // issued the challenge. | |
| 2762 TEST_P(HttpNetworkTransactionTest, | |
| 2763 HttpsServerRequestsProxyAuthThroughProxy) { | |
| 2764 HttpRequestInfo request; | |
| 2765 request.method = "GET"; | |
| 2766 request.url = GURL("https://www.google.com/"); | |
| 2767 | |
| 2768 session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); | |
| 2769 CapturingBoundNetLog log; | |
| 2770 session_deps_.net_log = log.bound().net_log(); | |
| 2771 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2772 | |
| 2773 // Since we have proxy, should try to establish tunnel. | |
| 2774 MockWrite data_writes1[] = { | |
| 2775 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 2776 "Host: www.google.com\r\n" | |
| 2777 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2778 | |
| 2779 MockWrite("GET / HTTP/1.1\r\n" | |
| 2780 "Host: www.google.com\r\n" | |
| 2781 "Connection: keep-alive\r\n\r\n"), | |
| 2782 }; | |
| 2783 | |
| 2784 MockRead data_reads1[] = { | |
| 2785 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 2786 | |
| 2787 MockRead("HTTP/1.1 407 Unauthorized\r\n"), | |
| 2788 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2789 MockRead("\r\n"), | |
| 2790 MockRead(SYNCHRONOUS, OK), | |
| 2791 }; | |
| 2792 | |
| 2793 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2794 data_writes1, arraysize(data_writes1)); | |
| 2795 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 2796 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2797 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 2798 | |
| 2799 TestCompletionCallback callback1; | |
| 2800 | |
| 2801 scoped_ptr<HttpTransaction> trans( | |
| 2802 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2803 | |
| 2804 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 2805 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2806 | |
| 2807 rv = callback1.WaitForResult(); | |
| 2808 EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); | |
| 2809 net::CapturingNetLog::CapturedEntryList entries; | |
| 2810 log.GetEntries(&entries); | |
| 2811 size_t pos = ExpectLogContainsSomewhere( | |
| 2812 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 2813 NetLog::PHASE_NONE); | |
| 2814 ExpectLogContainsSomewhere( | |
| 2815 entries, pos, | |
| 2816 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 2817 NetLog::PHASE_NONE); | |
| 2818 } | |
| 2819 | |
| 2820 // Test the load timing for HTTPS requests with an HTTP proxy. | |
| 2821 TEST_P(HttpNetworkTransactionTest, HttpProxyLoadTimingNoPacTwoRequests) { | |
| 2822 HttpRequestInfo request1; | |
| 2823 request1.method = "GET"; | |
| 2824 request1.url = GURL("https://www.google.com/1"); | |
| 2825 | |
| 2826 HttpRequestInfo request2; | |
| 2827 request2.method = "GET"; | |
| 2828 request2.url = GURL("https://www.google.com/2"); | |
| 2829 | |
| 2830 // Configure against proxy server "myproxy:70". | |
| 2831 session_deps_.proxy_service.reset( | |
| 2832 ProxyService::CreateFixed("PROXY myproxy:70")); | |
| 2833 CapturingBoundNetLog log; | |
| 2834 session_deps_.net_log = log.bound().net_log(); | |
| 2835 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2836 | |
| 2837 // Since we have proxy, should try to establish tunnel. | |
| 2838 MockWrite data_writes1[] = { | |
| 2839 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 2840 "Host: www.google.com\r\n" | |
| 2841 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2842 | |
| 2843 MockWrite("GET /1 HTTP/1.1\r\n" | |
| 2844 "Host: www.google.com\r\n" | |
| 2845 "Connection: keep-alive\r\n\r\n"), | |
| 2846 | |
| 2847 MockWrite("GET /2 HTTP/1.1\r\n" | |
| 2848 "Host: www.google.com\r\n" | |
| 2849 "Connection: keep-alive\r\n\r\n"), | |
| 2850 }; | |
| 2851 | |
| 2852 // The proxy responds to the connect with a 407, using a persistent | |
| 2853 // connection. | |
| 2854 MockRead data_reads1[] = { | |
| 2855 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 2856 | |
| 2857 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 2858 MockRead("Content-Length: 1\r\n\r\n"), | |
| 2859 MockRead(SYNCHRONOUS, "1"), | |
| 2860 | |
| 2861 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 2862 MockRead("Content-Length: 2\r\n\r\n"), | |
| 2863 MockRead(SYNCHRONOUS, "22"), | |
| 2864 }; | |
| 2865 | |
| 2866 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2867 data_writes1, arraysize(data_writes1)); | |
| 2868 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 2869 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2870 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 2871 | |
| 2872 TestCompletionCallback callback1; | |
| 2873 scoped_ptr<HttpTransaction> trans1( | |
| 2874 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2875 | |
| 2876 int rv = trans1->Start(&request1, callback1.callback(), log.bound()); | |
| 2877 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2878 | |
| 2879 rv = callback1.WaitForResult(); | |
| 2880 EXPECT_EQ(OK, rv); | |
| 2881 | |
| 2882 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
| 2883 ASSERT_TRUE(response1 != NULL); | |
| 2884 ASSERT_TRUE(response1->headers.get() != NULL); | |
| 2885 EXPECT_EQ(1, response1->headers->GetContentLength()); | |
| 2886 | |
| 2887 LoadTimingInfo load_timing_info1; | |
| 2888 EXPECT_TRUE(trans1->GetLoadTimingInfo(&load_timing_info1)); | |
| 2889 TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_SSL_TIMES); | |
| 2890 | |
| 2891 trans1.reset(); | |
| 2892 | |
| 2893 TestCompletionCallback callback2; | |
| 2894 scoped_ptr<HttpTransaction> trans2( | |
| 2895 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2896 | |
| 2897 rv = trans2->Start(&request2, callback2.callback(), log.bound()); | |
| 2898 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2899 | |
| 2900 rv = callback2.WaitForResult(); | |
| 2901 EXPECT_EQ(OK, rv); | |
| 2902 | |
| 2903 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
| 2904 ASSERT_TRUE(response2 != NULL); | |
| 2905 ASSERT_TRUE(response2->headers.get() != NULL); | |
| 2906 EXPECT_EQ(2, response2->headers->GetContentLength()); | |
| 2907 | |
| 2908 LoadTimingInfo load_timing_info2; | |
| 2909 EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2)); | |
| 2910 TestLoadTimingReused(load_timing_info2); | |
| 2911 | |
| 2912 EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id); | |
| 2913 | |
| 2914 trans2.reset(); | |
| 2915 session->CloseAllConnections(); | |
| 2916 } | |
| 2917 | |
| 2918 // Test the load timing for HTTPS requests with an HTTP proxy and a PAC script. | |
| 2919 TEST_P(HttpNetworkTransactionTest, HttpProxyLoadTimingWithPacTwoRequests) { | |
| 2920 HttpRequestInfo request1; | |
| 2921 request1.method = "GET"; | |
| 2922 request1.url = GURL("https://www.google.com/1"); | |
| 2923 | |
| 2924 HttpRequestInfo request2; | |
| 2925 request2.method = "GET"; | |
| 2926 request2.url = GURL("https://www.google.com/2"); | |
| 2927 | |
| 2928 // Configure against proxy server "myproxy:70". | |
| 2929 session_deps_.proxy_service.reset( | |
| 2930 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); | |
| 2931 CapturingBoundNetLog log; | |
| 2932 session_deps_.net_log = log.bound().net_log(); | |
| 2933 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 2934 | |
| 2935 // Since we have proxy, should try to establish tunnel. | |
| 2936 MockWrite data_writes1[] = { | |
| 2937 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 2938 "Host: www.google.com\r\n" | |
| 2939 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2940 | |
| 2941 MockWrite("GET /1 HTTP/1.1\r\n" | |
| 2942 "Host: www.google.com\r\n" | |
| 2943 "Connection: keep-alive\r\n\r\n"), | |
| 2944 | |
| 2945 MockWrite("GET /2 HTTP/1.1\r\n" | |
| 2946 "Host: www.google.com\r\n" | |
| 2947 "Connection: keep-alive\r\n\r\n"), | |
| 2948 }; | |
| 2949 | |
| 2950 // The proxy responds to the connect with a 407, using a persistent | |
| 2951 // connection. | |
| 2952 MockRead data_reads1[] = { | |
| 2953 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 2954 | |
| 2955 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 2956 MockRead("Content-Length: 1\r\n\r\n"), | |
| 2957 MockRead(SYNCHRONOUS, "1"), | |
| 2958 | |
| 2959 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 2960 MockRead("Content-Length: 2\r\n\r\n"), | |
| 2961 MockRead(SYNCHRONOUS, "22"), | |
| 2962 }; | |
| 2963 | |
| 2964 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2965 data_writes1, arraysize(data_writes1)); | |
| 2966 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 2967 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2968 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 2969 | |
| 2970 TestCompletionCallback callback1; | |
| 2971 scoped_ptr<HttpTransaction> trans1( | |
| 2972 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2973 | |
| 2974 int rv = trans1->Start(&request1, callback1.callback(), log.bound()); | |
| 2975 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2976 | |
| 2977 rv = callback1.WaitForResult(); | |
| 2978 EXPECT_EQ(OK, rv); | |
| 2979 | |
| 2980 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
| 2981 ASSERT_TRUE(response1 != NULL); | |
| 2982 ASSERT_TRUE(response1->headers.get() != NULL); | |
| 2983 EXPECT_EQ(1, response1->headers->GetContentLength()); | |
| 2984 | |
| 2985 LoadTimingInfo load_timing_info1; | |
| 2986 EXPECT_TRUE(trans1->GetLoadTimingInfo(&load_timing_info1)); | |
| 2987 TestLoadTimingNotReusedWithPac(load_timing_info1, | |
| 2988 CONNECT_TIMING_HAS_SSL_TIMES); | |
| 2989 | |
| 2990 trans1.reset(); | |
| 2991 | |
| 2992 TestCompletionCallback callback2; | |
| 2993 scoped_ptr<HttpTransaction> trans2( | |
| 2994 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 2995 | |
| 2996 rv = trans2->Start(&request2, callback2.callback(), log.bound()); | |
| 2997 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2998 | |
| 2999 rv = callback2.WaitForResult(); | |
| 3000 EXPECT_EQ(OK, rv); | |
| 3001 | |
| 3002 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
| 3003 ASSERT_TRUE(response2 != NULL); | |
| 3004 ASSERT_TRUE(response2->headers.get() != NULL); | |
| 3005 EXPECT_EQ(2, response2->headers->GetContentLength()); | |
| 3006 | |
| 3007 LoadTimingInfo load_timing_info2; | |
| 3008 EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2)); | |
| 3009 TestLoadTimingReusedWithPac(load_timing_info2); | |
| 3010 | |
| 3011 EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id); | |
| 3012 | |
| 3013 trans2.reset(); | |
| 3014 session->CloseAllConnections(); | |
| 3015 } | |
| 3016 | |
| 3017 // Test a simple get through an HTTPS Proxy. | |
| 3018 TEST_P(HttpNetworkTransactionTest, HttpsProxyGet) { | |
| 3019 HttpRequestInfo request; | |
| 3020 request.method = "GET"; | |
| 3021 request.url = GURL("http://www.google.com/"); | |
| 3022 | |
| 3023 // Configure against https proxy server "proxy:70". | |
| 3024 session_deps_.proxy_service.reset(ProxyService::CreateFixed( | |
| 3025 "https://proxy:70")); | |
| 3026 CapturingBoundNetLog log; | |
| 3027 session_deps_.net_log = log.bound().net_log(); | |
| 3028 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 3029 | |
| 3030 // Since we have proxy, should use full url | |
| 3031 MockWrite data_writes1[] = { | |
| 3032 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 3033 "Host: www.google.com\r\n" | |
| 3034 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 3035 }; | |
| 3036 | |
| 3037 MockRead data_reads1[] = { | |
| 3038 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 3039 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 3040 MockRead("Content-Length: 100\r\n\r\n"), | |
| 3041 MockRead(SYNCHRONOUS, OK), | |
| 3042 }; | |
| 3043 | |
| 3044 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 3045 data_writes1, arraysize(data_writes1)); | |
| 3046 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 3047 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3048 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 3049 | |
| 3050 TestCompletionCallback callback1; | |
| 3051 | |
| 3052 scoped_ptr<HttpTransaction> trans( | |
| 3053 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3054 | |
| 3055 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 3056 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3057 | |
| 3058 rv = callback1.WaitForResult(); | |
| 3059 EXPECT_EQ(OK, rv); | |
| 3060 | |
| 3061 LoadTimingInfo load_timing_info; | |
| 3062 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 3063 TestLoadTimingNotReused(load_timing_info, | |
| 3064 CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); | |
| 3065 | |
| 3066 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3067 ASSERT_TRUE(response != NULL); | |
| 3068 | |
| 3069 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 3070 EXPECT_EQ(200, response->headers->response_code()); | |
| 3071 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 3072 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 3073 | |
| 3074 // The password prompt info should not be set. | |
| 3075 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 3076 } | |
| 3077 | |
| 3078 // Test a SPDY get through an HTTPS Proxy. | |
| 3079 TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGet) { | |
| 3080 HttpRequestInfo request; | |
| 3081 request.method = "GET"; | |
| 3082 request.url = GURL("http://www.google.com/"); | |
| 3083 request.load_flags = 0; | |
| 3084 | |
| 3085 // Configure against https proxy server "proxy:70". | |
| 3086 session_deps_.proxy_service.reset(ProxyService::CreateFixed( | |
| 3087 "https://proxy:70")); | |
| 3088 CapturingBoundNetLog log; | |
| 3089 session_deps_.net_log = log.bound().net_log(); | |
| 3090 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 3091 | |
| 3092 // fetch http://www.google.com/ via SPDY | |
| 3093 scoped_ptr<SpdyFrame> req( | |
| 3094 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false)); | |
| 3095 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
| 3096 | |
| 3097 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 3098 scoped_ptr<SpdyFrame> data(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 3099 MockRead spdy_reads[] = { | |
| 3100 CreateMockRead(*resp), | |
| 3101 CreateMockRead(*data), | |
| 3102 MockRead(ASYNC, 0, 0), | |
| 3103 }; | |
| 3104 | |
| 3105 DelayedSocketData spdy_data( | |
| 3106 1, // wait for one write to finish before reading. | |
| 3107 spdy_reads, arraysize(spdy_reads), | |
| 3108 spdy_writes, arraysize(spdy_writes)); | |
| 3109 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 3110 | |
| 3111 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3112 ssl.SetNextProto(GetParam()); | |
| 3113 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 3114 | |
| 3115 TestCompletionCallback callback1; | |
| 3116 | |
| 3117 scoped_ptr<HttpTransaction> trans( | |
| 3118 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3119 | |
| 3120 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 3121 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3122 | |
| 3123 rv = callback1.WaitForResult(); | |
| 3124 EXPECT_EQ(OK, rv); | |
| 3125 | |
| 3126 LoadTimingInfo load_timing_info; | |
| 3127 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 3128 TestLoadTimingNotReused(load_timing_info, | |
| 3129 CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); | |
| 3130 | |
| 3131 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3132 ASSERT_TRUE(response != NULL); | |
| 3133 ASSERT_TRUE(response->headers.get() != NULL); | |
| 3134 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 3135 | |
| 3136 std::string response_data; | |
| 3137 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 3138 EXPECT_EQ(kUploadData, response_data); | |
| 3139 } | |
| 3140 | |
| 3141 // Verifies that a session which races and wins against the owning transaction | |
| 3142 // (completing prior to host resolution), doesn't fail the transaction. | |
| 3143 // Regression test for crbug.com/334413. | |
| 3144 TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithSessionRace) { | |
| 3145 HttpRequestInfo request; | |
| 3146 request.method = "GET"; | |
| 3147 request.url = GURL("http://www.google.com/"); | |
| 3148 request.load_flags = 0; | |
| 3149 | |
| 3150 // Configure SPDY proxy server "proxy:70". | |
| 3151 session_deps_.proxy_service.reset( | |
| 3152 ProxyService::CreateFixed("https://proxy:70")); | |
| 3153 CapturingBoundNetLog log; | |
| 3154 session_deps_.net_log = log.bound().net_log(); | |
| 3155 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 3156 | |
| 3157 // Fetch http://www.google.com/ through the SPDY proxy. | |
| 3158 scoped_ptr<SpdyFrame> req( | |
| 3159 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false)); | |
| 3160 MockWrite spdy_writes[] = {CreateMockWrite(*req)}; | |
| 3161 | |
| 3162 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 3163 scoped_ptr<SpdyFrame> data(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 3164 MockRead spdy_reads[] = { | |
| 3165 CreateMockRead(*resp), CreateMockRead(*data), MockRead(ASYNC, 0, 0), | |
| 3166 }; | |
| 3167 | |
| 3168 DelayedSocketData spdy_data( | |
| 3169 1, // wait for one write to finish before reading. | |
| 3170 spdy_reads, | |
| 3171 arraysize(spdy_reads), | |
| 3172 spdy_writes, | |
| 3173 arraysize(spdy_writes)); | |
| 3174 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 3175 | |
| 3176 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3177 ssl.SetNextProto(GetParam()); | |
| 3178 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 3179 | |
| 3180 TestCompletionCallback callback1; | |
| 3181 | |
| 3182 scoped_ptr<HttpTransaction> trans( | |
| 3183 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3184 | |
| 3185 // Stall the hostname resolution begun by the transaction. | |
| 3186 session_deps_.host_resolver->set_synchronous_mode(false); | |
| 3187 session_deps_.host_resolver->set_ondemand_mode(true); | |
| 3188 | |
| 3189 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 3190 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3191 | |
| 3192 // Race a session to the proxy, which completes first. | |
| 3193 session_deps_.host_resolver->set_ondemand_mode(false); | |
| 3194 SpdySessionKey key( | |
| 3195 HostPortPair("proxy", 70), ProxyServer::Direct(), PRIVACY_MODE_DISABLED); | |
| 3196 base::WeakPtr<SpdySession> spdy_session = | |
| 3197 CreateSecureSpdySession(session, key, log.bound()); | |
| 3198 | |
| 3199 // Unstall the resolution begun by the transaction. | |
| 3200 session_deps_.host_resolver->set_ondemand_mode(true); | |
| 3201 session_deps_.host_resolver->ResolveAllPending(); | |
| 3202 | |
| 3203 EXPECT_FALSE(callback1.have_result()); | |
| 3204 rv = callback1.WaitForResult(); | |
| 3205 EXPECT_EQ(OK, rv); | |
| 3206 | |
| 3207 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3208 ASSERT_TRUE(response != NULL); | |
| 3209 ASSERT_TRUE(response->headers.get() != NULL); | |
| 3210 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 3211 | |
| 3212 std::string response_data; | |
| 3213 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 3214 EXPECT_EQ(kUploadData, response_data); | |
| 3215 } | |
| 3216 | |
| 3217 // Test a SPDY get through an HTTPS Proxy. | |
| 3218 TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) { | |
| 3219 HttpRequestInfo request; | |
| 3220 request.method = "GET"; | |
| 3221 request.url = GURL("http://www.google.com/"); | |
| 3222 request.load_flags = 0; | |
| 3223 | |
| 3224 // Configure against https proxy server "myproxy:70". | |
| 3225 session_deps_.proxy_service.reset( | |
| 3226 ProxyService::CreateFixed("https://myproxy:70")); | |
| 3227 CapturingBoundNetLog log; | |
| 3228 session_deps_.net_log = log.bound().net_log(); | |
| 3229 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 3230 | |
| 3231 // The first request will be a bare GET, the second request will be a | |
| 3232 // GET with a Proxy-Authorization header. | |
| 3233 scoped_ptr<SpdyFrame> req_get( | |
| 3234 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false)); | |
| 3235 const char* const kExtraAuthorizationHeaders[] = { | |
| 3236 "proxy-authorization", "Basic Zm9vOmJhcg==" | |
| 3237 }; | |
| 3238 scoped_ptr<SpdyFrame> req_get_authorization( | |
| 3239 spdy_util_.ConstructSpdyGet(kExtraAuthorizationHeaders, | |
| 3240 arraysize(kExtraAuthorizationHeaders) / 2, | |
| 3241 false, | |
| 3242 3, | |
| 3243 LOWEST, | |
| 3244 false)); | |
| 3245 MockWrite spdy_writes[] = { | |
| 3246 CreateMockWrite(*req_get, 1), | |
| 3247 CreateMockWrite(*req_get_authorization, 4), | |
| 3248 }; | |
| 3249 | |
| 3250 // The first response is a 407 proxy authentication challenge, and the second | |
| 3251 // response will be a 200 response since the second request includes a valid | |
| 3252 // Authorization header. | |
| 3253 const char* const kExtraAuthenticationHeaders[] = { | |
| 3254 "proxy-authenticate", "Basic realm=\"MyRealm1\"" | |
| 3255 }; | |
| 3256 scoped_ptr<SpdyFrame> resp_authentication( | |
| 3257 spdy_util_.ConstructSpdySynReplyError( | |
| 3258 "407 Proxy Authentication Required", | |
| 3259 kExtraAuthenticationHeaders, arraysize(kExtraAuthenticationHeaders)/2, | |
| 3260 1)); | |
| 3261 scoped_ptr<SpdyFrame> body_authentication( | |
| 3262 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 3263 scoped_ptr<SpdyFrame> resp_data( | |
| 3264 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 3265 scoped_ptr<SpdyFrame> body_data(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
| 3266 MockRead spdy_reads[] = { | |
| 3267 CreateMockRead(*resp_authentication, 2), | |
| 3268 CreateMockRead(*body_authentication, 3), | |
| 3269 CreateMockRead(*resp_data, 5), | |
| 3270 CreateMockRead(*body_data, 6), | |
| 3271 MockRead(ASYNC, 0, 7), | |
| 3272 }; | |
| 3273 | |
| 3274 OrderedSocketData data( | |
| 3275 spdy_reads, arraysize(spdy_reads), | |
| 3276 spdy_writes, arraysize(spdy_writes)); | |
| 3277 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 3278 | |
| 3279 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3280 ssl.SetNextProto(GetParam()); | |
| 3281 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 3282 | |
| 3283 TestCompletionCallback callback1; | |
| 3284 | |
| 3285 scoped_ptr<HttpTransaction> trans( | |
| 3286 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3287 | |
| 3288 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 3289 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3290 | |
| 3291 rv = callback1.WaitForResult(); | |
| 3292 EXPECT_EQ(OK, rv); | |
| 3293 | |
| 3294 const HttpResponseInfo* const response = trans->GetResponseInfo(); | |
| 3295 | |
| 3296 ASSERT_TRUE(response != NULL); | |
| 3297 ASSERT_TRUE(response->headers.get() != NULL); | |
| 3298 EXPECT_EQ(407, response->headers->response_code()); | |
| 3299 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 3300 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 3301 | |
| 3302 TestCompletionCallback callback2; | |
| 3303 | |
| 3304 rv = trans->RestartWithAuth( | |
| 3305 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 3306 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3307 | |
| 3308 rv = callback2.WaitForResult(); | |
| 3309 EXPECT_EQ(OK, rv); | |
| 3310 | |
| 3311 const HttpResponseInfo* const response_restart = trans->GetResponseInfo(); | |
| 3312 | |
| 3313 ASSERT_TRUE(response_restart != NULL); | |
| 3314 ASSERT_TRUE(response_restart->headers.get() != NULL); | |
| 3315 EXPECT_EQ(200, response_restart->headers->response_code()); | |
| 3316 // The password prompt info should not be set. | |
| 3317 EXPECT_TRUE(response_restart->auth_challenge.get() == NULL); | |
| 3318 } | |
| 3319 | |
| 3320 // Test a SPDY CONNECT through an HTTPS Proxy to an HTTPS (non-SPDY) Server. | |
| 3321 TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) { | |
| 3322 HttpRequestInfo request; | |
| 3323 request.method = "GET"; | |
| 3324 request.url = GURL("https://www.google.com/"); | |
| 3325 request.load_flags = 0; | |
| 3326 | |
| 3327 // Configure against https proxy server "proxy:70". | |
| 3328 session_deps_.proxy_service.reset(ProxyService::CreateFixed( | |
| 3329 "https://proxy:70")); | |
| 3330 CapturingBoundNetLog log; | |
| 3331 session_deps_.net_log = log.bound().net_log(); | |
| 3332 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 3333 | |
| 3334 scoped_ptr<HttpTransaction> trans( | |
| 3335 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3336 | |
| 3337 // CONNECT to www.google.com:443 via SPDY | |
| 3338 scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect( | |
| 3339 NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); | |
| 3340 // fetch https://www.google.com/ via HTTP | |
| 3341 | |
| 3342 const char get[] = "GET / HTTP/1.1\r\n" | |
| 3343 "Host: www.google.com\r\n" | |
| 3344 "Connection: keep-alive\r\n\r\n"; | |
| 3345 scoped_ptr<SpdyFrame> wrapped_get( | |
| 3346 spdy_util_.ConstructSpdyBodyFrame(1, get, strlen(get), false)); | |
| 3347 scoped_ptr<SpdyFrame> conn_resp( | |
| 3348 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 3349 const char resp[] = "HTTP/1.1 200 OK\r\n" | |
| 3350 "Content-Length: 10\r\n\r\n"; | |
| 3351 scoped_ptr<SpdyFrame> wrapped_get_resp( | |
| 3352 spdy_util_.ConstructSpdyBodyFrame(1, resp, strlen(resp), false)); | |
| 3353 scoped_ptr<SpdyFrame> wrapped_body( | |
| 3354 spdy_util_.ConstructSpdyBodyFrame(1, "1234567890", 10, false)); | |
| 3355 scoped_ptr<SpdyFrame> window_update( | |
| 3356 spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp->size())); | |
| 3357 | |
| 3358 MockWrite spdy_writes[] = { | |
| 3359 CreateMockWrite(*connect, 1), | |
| 3360 CreateMockWrite(*wrapped_get, 3), | |
| 3361 CreateMockWrite(*window_update, 5), | |
| 3362 }; | |
| 3363 | |
| 3364 MockRead spdy_reads[] = { | |
| 3365 CreateMockRead(*conn_resp, 2, ASYNC), | |
| 3366 CreateMockRead(*wrapped_get_resp, 4, ASYNC), | |
| 3367 CreateMockRead(*wrapped_body, 6, ASYNC), | |
| 3368 CreateMockRead(*wrapped_body, 7, ASYNC), | |
| 3369 MockRead(ASYNC, 0, 8), | |
| 3370 }; | |
| 3371 | |
| 3372 OrderedSocketData spdy_data( | |
| 3373 spdy_reads, arraysize(spdy_reads), | |
| 3374 spdy_writes, arraysize(spdy_writes)); | |
| 3375 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 3376 | |
| 3377 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3378 ssl.SetNextProto(GetParam()); | |
| 3379 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 3380 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 3381 ssl2.was_npn_negotiated = false; | |
| 3382 ssl2.protocol_negotiated = kProtoUnknown; | |
| 3383 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2); | |
| 3384 | |
| 3385 TestCompletionCallback callback1; | |
| 3386 | |
| 3387 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 3388 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3389 | |
| 3390 rv = callback1.WaitForResult(); | |
| 3391 EXPECT_EQ(OK, rv); | |
| 3392 | |
| 3393 LoadTimingInfo load_timing_info; | |
| 3394 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 3395 TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_SSL_TIMES); | |
| 3396 | |
| 3397 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3398 ASSERT_TRUE(response != NULL); | |
| 3399 ASSERT_TRUE(response->headers.get() != NULL); | |
| 3400 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 3401 | |
| 3402 std::string response_data; | |
| 3403 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 3404 EXPECT_EQ("1234567890", response_data); | |
| 3405 } | |
| 3406 | |
| 3407 // Test a SPDY CONNECT through an HTTPS Proxy to a SPDY server. | |
| 3408 TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) { | |
| 3409 HttpRequestInfo request; | |
| 3410 request.method = "GET"; | |
| 3411 request.url = GURL("https://www.google.com/"); | |
| 3412 request.load_flags = 0; | |
| 3413 | |
| 3414 // Configure against https proxy server "proxy:70". | |
| 3415 session_deps_.proxy_service.reset(ProxyService::CreateFixed( | |
| 3416 "https://proxy:70")); | |
| 3417 CapturingBoundNetLog log; | |
| 3418 session_deps_.net_log = log.bound().net_log(); | |
| 3419 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 3420 | |
| 3421 scoped_ptr<HttpTransaction> trans( | |
| 3422 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3423 | |
| 3424 // CONNECT to www.google.com:443 via SPDY | |
| 3425 scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect( | |
| 3426 NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); | |
| 3427 // fetch https://www.google.com/ via SPDY | |
| 3428 const char kMyUrl[] = "https://www.google.com/"; | |
| 3429 scoped_ptr<SpdyFrame> get( | |
| 3430 spdy_util_.ConstructSpdyGet(kMyUrl, false, 1, LOWEST)); | |
| 3431 scoped_ptr<SpdyFrame> wrapped_get( | |
| 3432 spdy_util_.ConstructWrappedSpdyFrame(get, 1)); | |
| 3433 scoped_ptr<SpdyFrame> conn_resp( | |
| 3434 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 3435 scoped_ptr<SpdyFrame> get_resp( | |
| 3436 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 3437 scoped_ptr<SpdyFrame> wrapped_get_resp( | |
| 3438 spdy_util_.ConstructWrappedSpdyFrame(get_resp, 1)); | |
| 3439 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 3440 scoped_ptr<SpdyFrame> wrapped_body( | |
| 3441 spdy_util_.ConstructWrappedSpdyFrame(body, 1)); | |
| 3442 scoped_ptr<SpdyFrame> window_update_get_resp( | |
| 3443 spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp->size())); | |
| 3444 scoped_ptr<SpdyFrame> window_update_body( | |
| 3445 spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_body->size())); | |
| 3446 | |
| 3447 MockWrite spdy_writes[] = { | |
| 3448 CreateMockWrite(*connect, 1), | |
| 3449 CreateMockWrite(*wrapped_get, 3), | |
| 3450 CreateMockWrite(*window_update_get_resp, 5), | |
| 3451 CreateMockWrite(*window_update_body, 7), | |
| 3452 }; | |
| 3453 | |
| 3454 MockRead spdy_reads[] = { | |
| 3455 CreateMockRead(*conn_resp, 2, ASYNC), | |
| 3456 CreateMockRead(*wrapped_get_resp, 4, ASYNC), | |
| 3457 CreateMockRead(*wrapped_body, 6, ASYNC), | |
| 3458 MockRead(ASYNC, 0, 8), | |
| 3459 }; | |
| 3460 | |
| 3461 OrderedSocketData spdy_data( | |
| 3462 spdy_reads, arraysize(spdy_reads), | |
| 3463 spdy_writes, arraysize(spdy_writes)); | |
| 3464 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 3465 | |
| 3466 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3467 ssl.SetNextProto(GetParam()); | |
| 3468 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 3469 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 3470 ssl2.SetNextProto(GetParam()); | |
| 3471 ssl2.protocol_negotiated = GetParam(); | |
| 3472 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2); | |
| 3473 | |
| 3474 TestCompletionCallback callback1; | |
| 3475 | |
| 3476 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 3477 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3478 | |
| 3479 rv = callback1.WaitForResult(); | |
| 3480 EXPECT_EQ(OK, rv); | |
| 3481 | |
| 3482 LoadTimingInfo load_timing_info; | |
| 3483 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 3484 TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_SSL_TIMES); | |
| 3485 | |
| 3486 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3487 ASSERT_TRUE(response != NULL); | |
| 3488 ASSERT_TRUE(response->headers.get() != NULL); | |
| 3489 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 3490 | |
| 3491 std::string response_data; | |
| 3492 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 3493 EXPECT_EQ(kUploadData, response_data); | |
| 3494 } | |
| 3495 | |
| 3496 // Test a SPDY CONNECT failure through an HTTPS Proxy. | |
| 3497 TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) { | |
| 3498 HttpRequestInfo request; | |
| 3499 request.method = "GET"; | |
| 3500 request.url = GURL("https://www.google.com/"); | |
| 3501 request.load_flags = 0; | |
| 3502 | |
| 3503 // Configure against https proxy server "proxy:70". | |
| 3504 session_deps_.proxy_service.reset(ProxyService::CreateFixed( | |
| 3505 "https://proxy:70")); | |
| 3506 CapturingBoundNetLog log; | |
| 3507 session_deps_.net_log = log.bound().net_log(); | |
| 3508 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 3509 | |
| 3510 scoped_ptr<HttpTransaction> trans( | |
| 3511 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3512 | |
| 3513 // CONNECT to www.google.com:443 via SPDY | |
| 3514 scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect( | |
| 3515 NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); | |
| 3516 scoped_ptr<SpdyFrame> get( | |
| 3517 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 3518 | |
| 3519 MockWrite spdy_writes[] = { | |
| 3520 CreateMockWrite(*connect, 1), | |
| 3521 CreateMockWrite(*get, 3), | |
| 3522 }; | |
| 3523 | |
| 3524 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdySynReplyError(1)); | |
| 3525 scoped_ptr<SpdyFrame> data(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 3526 MockRead spdy_reads[] = { | |
| 3527 CreateMockRead(*resp, 2, ASYNC), | |
| 3528 MockRead(ASYNC, 0, 4), | |
| 3529 }; | |
| 3530 | |
| 3531 OrderedSocketData spdy_data( | |
| 3532 spdy_reads, arraysize(spdy_reads), | |
| 3533 spdy_writes, arraysize(spdy_writes)); | |
| 3534 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 3535 | |
| 3536 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3537 ssl.SetNextProto(GetParam()); | |
| 3538 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 3539 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 3540 ssl2.SetNextProto(GetParam()); | |
| 3541 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2); | |
| 3542 | |
| 3543 TestCompletionCallback callback1; | |
| 3544 | |
| 3545 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 3546 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3547 | |
| 3548 rv = callback1.WaitForResult(); | |
| 3549 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
| 3550 | |
| 3551 // TODO(ttuttle): Anything else to check here? | |
| 3552 } | |
| 3553 | |
| 3554 // Test load timing in the case of two HTTPS (non-SPDY) requests through a SPDY | |
| 3555 // HTTPS Proxy to different servers. | |
| 3556 TEST_P(HttpNetworkTransactionTest, | |
| 3557 HttpsProxySpdyConnectHttpsLoadTimingTwoRequestsTwoServers) { | |
| 3558 // Configure against https proxy server "proxy:70". | |
| 3559 session_deps_.proxy_service.reset(ProxyService::CreateFixed( | |
| 3560 "https://proxy:70")); | |
| 3561 CapturingBoundNetLog log; | |
| 3562 session_deps_.net_log = log.bound().net_log(); | |
| 3563 scoped_refptr<HttpNetworkSession> session( | |
| 3564 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_)); | |
| 3565 | |
| 3566 HttpRequestInfo request1; | |
| 3567 request1.method = "GET"; | |
| 3568 request1.url = GURL("https://www.google.com/"); | |
| 3569 request1.load_flags = 0; | |
| 3570 | |
| 3571 HttpRequestInfo request2; | |
| 3572 request2.method = "GET"; | |
| 3573 request2.url = GURL("https://news.google.com/"); | |
| 3574 request2.load_flags = 0; | |
| 3575 | |
| 3576 // CONNECT to www.google.com:443 via SPDY. | |
| 3577 scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect( | |
| 3578 NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); | |
| 3579 scoped_ptr<SpdyFrame> conn_resp1( | |
| 3580 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 3581 | |
| 3582 // Fetch https://www.google.com/ via HTTP. | |
| 3583 const char get1[] = "GET / HTTP/1.1\r\n" | |
| 3584 "Host: www.google.com\r\n" | |
| 3585 "Connection: keep-alive\r\n\r\n"; | |
| 3586 scoped_ptr<SpdyFrame> wrapped_get1( | |
| 3587 spdy_util_.ConstructSpdyBodyFrame(1, get1, strlen(get1), false)); | |
| 3588 const char resp1[] = "HTTP/1.1 200 OK\r\n" | |
| 3589 "Content-Length: 1\r\n\r\n"; | |
| 3590 scoped_ptr<SpdyFrame> wrapped_get_resp1( | |
| 3591 spdy_util_.ConstructSpdyBodyFrame(1, resp1, strlen(resp1), false)); | |
| 3592 scoped_ptr<SpdyFrame> wrapped_body1( | |
| 3593 spdy_util_.ConstructSpdyBodyFrame(1, "1", 1, false)); | |
| 3594 scoped_ptr<SpdyFrame> window_update( | |
| 3595 spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp1->size())); | |
| 3596 | |
| 3597 // CONNECT to news.google.com:443 via SPDY. | |
| 3598 SpdyHeaderBlock connect2_block; | |
| 3599 connect2_block[spdy_util_.GetMethodKey()] = "CONNECT"; | |
| 3600 connect2_block[spdy_util_.GetPathKey()] = "news.google.com:443"; | |
| 3601 connect2_block[spdy_util_.GetHostKey()] = "news.google.com"; | |
| 3602 spdy_util_.MaybeAddVersionHeader(&connect2_block); | |
| 3603 scoped_ptr<SpdyFrame> connect2( | |
| 3604 spdy_util_.ConstructSpdySyn(3, connect2_block, LOWEST, false, false)); | |
| 3605 | |
| 3606 scoped_ptr<SpdyFrame> conn_resp2( | |
| 3607 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 3608 | |
| 3609 // Fetch https://news.google.com/ via HTTP. | |
| 3610 const char get2[] = "GET / HTTP/1.1\r\n" | |
| 3611 "Host: news.google.com\r\n" | |
| 3612 "Connection: keep-alive\r\n\r\n"; | |
| 3613 scoped_ptr<SpdyFrame> wrapped_get2( | |
| 3614 spdy_util_.ConstructSpdyBodyFrame(3, get2, strlen(get2), false)); | |
| 3615 const char resp2[] = "HTTP/1.1 200 OK\r\n" | |
| 3616 "Content-Length: 2\r\n\r\n"; | |
| 3617 scoped_ptr<SpdyFrame> wrapped_get_resp2( | |
| 3618 spdy_util_.ConstructSpdyBodyFrame(3, resp2, strlen(resp2), false)); | |
| 3619 scoped_ptr<SpdyFrame> wrapped_body2( | |
| 3620 spdy_util_.ConstructSpdyBodyFrame(3, "22", 2, false)); | |
| 3621 | |
| 3622 MockWrite spdy_writes[] = { | |
| 3623 CreateMockWrite(*connect1, 0), | |
| 3624 CreateMockWrite(*wrapped_get1, 2), | |
| 3625 CreateMockWrite(*connect2, 5), | |
| 3626 CreateMockWrite(*wrapped_get2, 7), | |
| 3627 }; | |
| 3628 | |
| 3629 MockRead spdy_reads[] = { | |
| 3630 CreateMockRead(*conn_resp1, 1, ASYNC), | |
| 3631 CreateMockRead(*wrapped_get_resp1, 3, ASYNC), | |
| 3632 CreateMockRead(*wrapped_body1, 4, ASYNC), | |
| 3633 CreateMockRead(*conn_resp2, 6, ASYNC), | |
| 3634 CreateMockRead(*wrapped_get_resp2, 8, ASYNC), | |
| 3635 CreateMockRead(*wrapped_body2, 9, ASYNC), | |
| 3636 MockRead(ASYNC, 0, 10), | |
| 3637 }; | |
| 3638 | |
| 3639 DeterministicSocketData spdy_data( | |
| 3640 spdy_reads, arraysize(spdy_reads), | |
| 3641 spdy_writes, arraysize(spdy_writes)); | |
| 3642 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&spdy_data); | |
| 3643 | |
| 3644 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3645 ssl.SetNextProto(GetParam()); | |
| 3646 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 3647 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 3648 ssl2.was_npn_negotiated = false; | |
| 3649 ssl2.protocol_negotiated = kProtoUnknown; | |
| 3650 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl2); | |
| 3651 SSLSocketDataProvider ssl3(ASYNC, OK); | |
| 3652 ssl3.was_npn_negotiated = false; | |
| 3653 ssl3.protocol_negotiated = kProtoUnknown; | |
| 3654 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl3); | |
| 3655 | |
| 3656 TestCompletionCallback callback; | |
| 3657 | |
| 3658 scoped_ptr<HttpTransaction> trans( | |
| 3659 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3660 int rv = trans->Start(&request1, callback.callback(), BoundNetLog()); | |
| 3661 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3662 // The first connect and request, each of their responses, and the body. | |
| 3663 spdy_data.RunFor(5); | |
| 3664 | |
| 3665 rv = callback.WaitForResult(); | |
| 3666 EXPECT_EQ(OK, rv); | |
| 3667 | |
| 3668 LoadTimingInfo load_timing_info; | |
| 3669 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 3670 TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_SSL_TIMES); | |
| 3671 | |
| 3672 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3673 ASSERT_TRUE(response != NULL); | |
| 3674 ASSERT_TRUE(response->headers.get() != NULL); | |
| 3675 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 3676 | |
| 3677 std::string response_data; | |
| 3678 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(256)); | |
| 3679 EXPECT_EQ(1, trans->Read(buf.get(), 256, callback.callback())); | |
| 3680 | |
| 3681 scoped_ptr<HttpTransaction> trans2( | |
| 3682 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3683 rv = trans2->Start(&request2, callback.callback(), BoundNetLog()); | |
| 3684 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3685 | |
| 3686 // The second connect and request, each of their responses, and the body. | |
| 3687 spdy_data.RunFor(5); | |
| 3688 rv = callback.WaitForResult(); | |
| 3689 EXPECT_EQ(OK, rv); | |
| 3690 | |
| 3691 LoadTimingInfo load_timing_info2; | |
| 3692 EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2)); | |
| 3693 // Even though the SPDY connection is reused, a new tunnelled connection has | |
| 3694 // to be created, so the socket's load timing looks like a fresh connection. | |
| 3695 TestLoadTimingNotReused(load_timing_info2, CONNECT_TIMING_HAS_SSL_TIMES); | |
| 3696 | |
| 3697 // The requests should have different IDs, since they each are using their own | |
| 3698 // separate stream. | |
| 3699 EXPECT_NE(load_timing_info.socket_log_id, load_timing_info2.socket_log_id); | |
| 3700 | |
| 3701 EXPECT_EQ(2, trans2->Read(buf.get(), 256, callback.callback())); | |
| 3702 } | |
| 3703 | |
| 3704 // Test load timing in the case of two HTTPS (non-SPDY) requests through a SPDY | |
| 3705 // HTTPS Proxy to the same server. | |
| 3706 TEST_P(HttpNetworkTransactionTest, | |
| 3707 HttpsProxySpdyConnectHttpsLoadTimingTwoRequestsSameServer) { | |
| 3708 // Configure against https proxy server "proxy:70". | |
| 3709 session_deps_.proxy_service.reset(ProxyService::CreateFixed( | |
| 3710 "https://proxy:70")); | |
| 3711 CapturingBoundNetLog log; | |
| 3712 session_deps_.net_log = log.bound().net_log(); | |
| 3713 scoped_refptr<HttpNetworkSession> session( | |
| 3714 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_)); | |
| 3715 | |
| 3716 HttpRequestInfo request1; | |
| 3717 request1.method = "GET"; | |
| 3718 request1.url = GURL("https://www.google.com/"); | |
| 3719 request1.load_flags = 0; | |
| 3720 | |
| 3721 HttpRequestInfo request2; | |
| 3722 request2.method = "GET"; | |
| 3723 request2.url = GURL("https://www.google.com/2"); | |
| 3724 request2.load_flags = 0; | |
| 3725 | |
| 3726 // CONNECT to www.google.com:443 via SPDY. | |
| 3727 scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect( | |
| 3728 NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); | |
| 3729 scoped_ptr<SpdyFrame> conn_resp1( | |
| 3730 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 3731 | |
| 3732 // Fetch https://www.google.com/ via HTTP. | |
| 3733 const char get1[] = "GET / HTTP/1.1\r\n" | |
| 3734 "Host: www.google.com\r\n" | |
| 3735 "Connection: keep-alive\r\n\r\n"; | |
| 3736 scoped_ptr<SpdyFrame> wrapped_get1( | |
| 3737 spdy_util_.ConstructSpdyBodyFrame(1, get1, strlen(get1), false)); | |
| 3738 const char resp1[] = "HTTP/1.1 200 OK\r\n" | |
| 3739 "Content-Length: 1\r\n\r\n"; | |
| 3740 scoped_ptr<SpdyFrame> wrapped_get_resp1( | |
| 3741 spdy_util_.ConstructSpdyBodyFrame(1, resp1, strlen(resp1), false)); | |
| 3742 scoped_ptr<SpdyFrame> wrapped_body1( | |
| 3743 spdy_util_.ConstructSpdyBodyFrame(1, "1", 1, false)); | |
| 3744 scoped_ptr<SpdyFrame> window_update( | |
| 3745 spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp1->size())); | |
| 3746 | |
| 3747 // Fetch https://www.google.com/2 via HTTP. | |
| 3748 const char get2[] = "GET /2 HTTP/1.1\r\n" | |
| 3749 "Host: www.google.com\r\n" | |
| 3750 "Connection: keep-alive\r\n\r\n"; | |
| 3751 scoped_ptr<SpdyFrame> wrapped_get2( | |
| 3752 spdy_util_.ConstructSpdyBodyFrame(1, get2, strlen(get2), false)); | |
| 3753 const char resp2[] = "HTTP/1.1 200 OK\r\n" | |
| 3754 "Content-Length: 2\r\n\r\n"; | |
| 3755 scoped_ptr<SpdyFrame> wrapped_get_resp2( | |
| 3756 spdy_util_.ConstructSpdyBodyFrame(1, resp2, strlen(resp2), false)); | |
| 3757 scoped_ptr<SpdyFrame> wrapped_body2( | |
| 3758 spdy_util_.ConstructSpdyBodyFrame(1, "22", 2, false)); | |
| 3759 | |
| 3760 MockWrite spdy_writes[] = { | |
| 3761 CreateMockWrite(*connect1, 0), | |
| 3762 CreateMockWrite(*wrapped_get1, 2), | |
| 3763 CreateMockWrite(*wrapped_get2, 5), | |
| 3764 }; | |
| 3765 | |
| 3766 MockRead spdy_reads[] = { | |
| 3767 CreateMockRead(*conn_resp1, 1, ASYNC), | |
| 3768 CreateMockRead(*wrapped_get_resp1, 3, ASYNC), | |
| 3769 CreateMockRead(*wrapped_body1, 4, ASYNC), | |
| 3770 CreateMockRead(*wrapped_get_resp2, 6, ASYNC), | |
| 3771 CreateMockRead(*wrapped_body2, 7, ASYNC), | |
| 3772 MockRead(ASYNC, 0, 8), | |
| 3773 }; | |
| 3774 | |
| 3775 DeterministicSocketData spdy_data( | |
| 3776 spdy_reads, arraysize(spdy_reads), | |
| 3777 spdy_writes, arraysize(spdy_writes)); | |
| 3778 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&spdy_data); | |
| 3779 | |
| 3780 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3781 ssl.SetNextProto(GetParam()); | |
| 3782 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 3783 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 3784 ssl2.was_npn_negotiated = false; | |
| 3785 ssl2.protocol_negotiated = kProtoUnknown; | |
| 3786 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl2); | |
| 3787 | |
| 3788 TestCompletionCallback callback; | |
| 3789 | |
| 3790 scoped_ptr<HttpTransaction> trans( | |
| 3791 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3792 int rv = trans->Start(&request1, callback.callback(), BoundNetLog()); | |
| 3793 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3794 // The first connect and request, each of their responses, and the body. | |
| 3795 spdy_data.RunFor(5); | |
| 3796 | |
| 3797 rv = callback.WaitForResult(); | |
| 3798 EXPECT_EQ(OK, rv); | |
| 3799 | |
| 3800 LoadTimingInfo load_timing_info; | |
| 3801 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 3802 TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_SSL_TIMES); | |
| 3803 | |
| 3804 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3805 ASSERT_TRUE(response != NULL); | |
| 3806 ASSERT_TRUE(response->headers.get() != NULL); | |
| 3807 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 3808 | |
| 3809 std::string response_data; | |
| 3810 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(256)); | |
| 3811 EXPECT_EQ(1, trans->Read(buf.get(), 256, callback.callback())); | |
| 3812 trans.reset(); | |
| 3813 | |
| 3814 scoped_ptr<HttpTransaction> trans2( | |
| 3815 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3816 rv = trans2->Start(&request2, callback.callback(), BoundNetLog()); | |
| 3817 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3818 | |
| 3819 // The second request, response, and body. There should not be a second | |
| 3820 // connect. | |
| 3821 spdy_data.RunFor(3); | |
| 3822 rv = callback.WaitForResult(); | |
| 3823 EXPECT_EQ(OK, rv); | |
| 3824 | |
| 3825 LoadTimingInfo load_timing_info2; | |
| 3826 EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2)); | |
| 3827 TestLoadTimingReused(load_timing_info2); | |
| 3828 | |
| 3829 // The requests should have the same ID. | |
| 3830 EXPECT_EQ(load_timing_info.socket_log_id, load_timing_info2.socket_log_id); | |
| 3831 | |
| 3832 EXPECT_EQ(2, trans2->Read(buf.get(), 256, callback.callback())); | |
| 3833 } | |
| 3834 | |
| 3835 // Test load timing in the case of of two HTTP requests through a SPDY HTTPS | |
| 3836 // Proxy to different servers. | |
| 3837 TEST_P(HttpNetworkTransactionTest, | |
| 3838 HttpsProxySpdyLoadTimingTwoHttpRequests) { | |
| 3839 // Configure against https proxy server "proxy:70". | |
| 3840 session_deps_.proxy_service.reset(ProxyService::CreateFixed( | |
| 3841 "https://proxy:70")); | |
| 3842 CapturingBoundNetLog log; | |
| 3843 session_deps_.net_log = log.bound().net_log(); | |
| 3844 scoped_refptr<HttpNetworkSession> session( | |
| 3845 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_)); | |
| 3846 | |
| 3847 HttpRequestInfo request1; | |
| 3848 request1.method = "GET"; | |
| 3849 request1.url = GURL("http://www.google.com/"); | |
| 3850 request1.load_flags = 0; | |
| 3851 | |
| 3852 HttpRequestInfo request2; | |
| 3853 request2.method = "GET"; | |
| 3854 request2.url = GURL("http://news.google.com/"); | |
| 3855 request2.load_flags = 0; | |
| 3856 | |
| 3857 // http://www.google.com/ | |
| 3858 scoped_ptr<SpdyHeaderBlock> headers( | |
| 3859 spdy_util_.ConstructGetHeaderBlockForProxy("http://www.google.com/")); | |
| 3860 scoped_ptr<SpdyFrame> get1( | |
| 3861 spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true)); | |
| 3862 scoped_ptr<SpdyFrame> get_resp1( | |
| 3863 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 3864 scoped_ptr<SpdyFrame> body1( | |
| 3865 spdy_util_.ConstructSpdyBodyFrame(1, "1", 1, true)); | |
| 3866 | |
| 3867 // http://news.google.com/ | |
| 3868 scoped_ptr<SpdyHeaderBlock> headers2( | |
| 3869 spdy_util_.ConstructGetHeaderBlockForProxy("http://news.google.com/")); | |
| 3870 scoped_ptr<SpdyFrame> get2( | |
| 3871 spdy_util_.ConstructSpdySyn(3, *headers2, LOWEST, false, true)); | |
| 3872 scoped_ptr<SpdyFrame> get_resp2( | |
| 3873 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 3874 scoped_ptr<SpdyFrame> body2( | |
| 3875 spdy_util_.ConstructSpdyBodyFrame(3, "22", 2, true)); | |
| 3876 | |
| 3877 MockWrite spdy_writes[] = { | |
| 3878 CreateMockWrite(*get1, 0), | |
| 3879 CreateMockWrite(*get2, 3), | |
| 3880 }; | |
| 3881 | |
| 3882 MockRead spdy_reads[] = { | |
| 3883 CreateMockRead(*get_resp1, 1, ASYNC), | |
| 3884 CreateMockRead(*body1, 2, ASYNC), | |
| 3885 CreateMockRead(*get_resp2, 4, ASYNC), | |
| 3886 CreateMockRead(*body2, 5, ASYNC), | |
| 3887 MockRead(ASYNC, 0, 6), | |
| 3888 }; | |
| 3889 | |
| 3890 DeterministicSocketData spdy_data( | |
| 3891 spdy_reads, arraysize(spdy_reads), | |
| 3892 spdy_writes, arraysize(spdy_writes)); | |
| 3893 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&spdy_data); | |
| 3894 | |
| 3895 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3896 ssl.SetNextProto(GetParam()); | |
| 3897 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 3898 | |
| 3899 TestCompletionCallback callback; | |
| 3900 | |
| 3901 scoped_ptr<HttpTransaction> trans( | |
| 3902 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3903 int rv = trans->Start(&request1, callback.callback(), BoundNetLog()); | |
| 3904 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3905 spdy_data.RunFor(2); | |
| 3906 | |
| 3907 rv = callback.WaitForResult(); | |
| 3908 EXPECT_EQ(OK, rv); | |
| 3909 | |
| 3910 LoadTimingInfo load_timing_info; | |
| 3911 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 3912 TestLoadTimingNotReused(load_timing_info, | |
| 3913 CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); | |
| 3914 | |
| 3915 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3916 ASSERT_TRUE(response != NULL); | |
| 3917 ASSERT_TRUE(response->headers.get() != NULL); | |
| 3918 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 3919 | |
| 3920 std::string response_data; | |
| 3921 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(256)); | |
| 3922 EXPECT_EQ(ERR_IO_PENDING, trans->Read(buf.get(), 256, callback.callback())); | |
| 3923 spdy_data.RunFor(1); | |
| 3924 EXPECT_EQ(1, callback.WaitForResult()); | |
| 3925 // Delete the first request, so the second one can reuse the socket. | |
| 3926 trans.reset(); | |
| 3927 | |
| 3928 scoped_ptr<HttpTransaction> trans2( | |
| 3929 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 3930 rv = trans2->Start(&request2, callback.callback(), BoundNetLog()); | |
| 3931 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3932 | |
| 3933 spdy_data.RunFor(2); | |
| 3934 rv = callback.WaitForResult(); | |
| 3935 EXPECT_EQ(OK, rv); | |
| 3936 | |
| 3937 LoadTimingInfo load_timing_info2; | |
| 3938 EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2)); | |
| 3939 TestLoadTimingReused(load_timing_info2); | |
| 3940 | |
| 3941 // The requests should have the same ID. | |
| 3942 EXPECT_EQ(load_timing_info.socket_log_id, load_timing_info2.socket_log_id); | |
| 3943 | |
| 3944 EXPECT_EQ(ERR_IO_PENDING, trans2->Read(buf.get(), 256, callback.callback())); | |
| 3945 spdy_data.RunFor(1); | |
| 3946 EXPECT_EQ(2, callback.WaitForResult()); | |
| 3947 } | |
| 3948 | |
| 3949 // Test the challenge-response-retry sequence through an HTTPS Proxy | |
| 3950 TEST_P(HttpNetworkTransactionTest, HttpsProxyAuthRetry) { | |
| 3951 HttpRequestInfo request; | |
| 3952 request.method = "GET"; | |
| 3953 request.url = GURL("http://www.google.com/"); | |
| 3954 // when the no authentication data flag is set. | |
| 3955 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
| 3956 | |
| 3957 // Configure against https proxy server "myproxy:70". | |
| 3958 session_deps_.proxy_service.reset( | |
| 3959 ProxyService::CreateFixed("https://myproxy:70")); | |
| 3960 CapturingBoundNetLog log; | |
| 3961 session_deps_.net_log = log.bound().net_log(); | |
| 3962 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 3963 | |
| 3964 // Since we have proxy, should use full url | |
| 3965 MockWrite data_writes1[] = { | |
| 3966 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 3967 "Host: www.google.com\r\n" | |
| 3968 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 3969 | |
| 3970 // After calling trans->RestartWithAuth(), this is the request we should | |
| 3971 // be issuing -- the final header line contains the credentials. | |
| 3972 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 3973 "Host: www.google.com\r\n" | |
| 3974 "Proxy-Connection: keep-alive\r\n" | |
| 3975 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 3976 }; | |
| 3977 | |
| 3978 // The proxy responds to the GET with a 407, using a persistent | |
| 3979 // connection. | |
| 3980 MockRead data_reads1[] = { | |
| 3981 // No credentials. | |
| 3982 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 3983 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 3984 MockRead("Proxy-Connection: keep-alive\r\n"), | |
| 3985 MockRead("Content-Length: 0\r\n\r\n"), | |
| 3986 | |
| 3987 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 3988 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 3989 MockRead("Content-Length: 100\r\n\r\n"), | |
| 3990 MockRead(SYNCHRONOUS, OK), | |
| 3991 }; | |
| 3992 | |
| 3993 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 3994 data_writes1, arraysize(data_writes1)); | |
| 3995 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 3996 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3997 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 3998 | |
| 3999 TestCompletionCallback callback1; | |
| 4000 | |
| 4001 scoped_ptr<HttpTransaction> trans( | |
| 4002 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 4003 | |
| 4004 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 4005 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4006 | |
| 4007 rv = callback1.WaitForResult(); | |
| 4008 EXPECT_EQ(OK, rv); | |
| 4009 | |
| 4010 LoadTimingInfo load_timing_info; | |
| 4011 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 4012 TestLoadTimingNotReused(load_timing_info, | |
| 4013 CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); | |
| 4014 | |
| 4015 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4016 ASSERT_TRUE(response != NULL); | |
| 4017 ASSERT_FALSE(response->headers.get() == NULL); | |
| 4018 EXPECT_EQ(407, response->headers->response_code()); | |
| 4019 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 4020 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 4021 | |
| 4022 TestCompletionCallback callback2; | |
| 4023 | |
| 4024 rv = trans->RestartWithAuth( | |
| 4025 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 4026 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4027 | |
| 4028 rv = callback2.WaitForResult(); | |
| 4029 EXPECT_EQ(OK, rv); | |
| 4030 | |
| 4031 load_timing_info = LoadTimingInfo(); | |
| 4032 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 4033 // Retrying with HTTP AUTH is considered to be reusing a socket. | |
| 4034 TestLoadTimingReused(load_timing_info); | |
| 4035 | |
| 4036 response = trans->GetResponseInfo(); | |
| 4037 ASSERT_TRUE(response != NULL); | |
| 4038 | |
| 4039 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 4040 EXPECT_EQ(200, response->headers->response_code()); | |
| 4041 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 4042 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 4043 | |
| 4044 // The password prompt info should not be set. | |
| 4045 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 4046 } | |
| 4047 | |
| 4048 void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus( | |
| 4049 const MockRead& status, int expected_status) { | |
| 4050 HttpRequestInfo request; | |
| 4051 request.method = "GET"; | |
| 4052 request.url = GURL("https://www.google.com/"); | |
| 4053 request.load_flags = 0; | |
| 4054 | |
| 4055 // Configure against proxy server "myproxy:70". | |
| 4056 session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); | |
| 4057 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 4058 | |
| 4059 // Since we have proxy, should try to establish tunnel. | |
| 4060 MockWrite data_writes[] = { | |
| 4061 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 4062 "Host: www.google.com\r\n" | |
| 4063 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 4064 }; | |
| 4065 | |
| 4066 MockRead data_reads[] = { | |
| 4067 status, | |
| 4068 MockRead("Content-Length: 10\r\n\r\n"), | |
| 4069 // No response body because the test stops reading here. | |
| 4070 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 4071 }; | |
| 4072 | |
| 4073 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 4074 data_writes, arraysize(data_writes)); | |
| 4075 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 4076 | |
| 4077 TestCompletionCallback callback; | |
| 4078 | |
| 4079 scoped_ptr<HttpTransaction> trans( | |
| 4080 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 4081 | |
| 4082 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4083 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4084 | |
| 4085 rv = callback.WaitForResult(); | |
| 4086 EXPECT_EQ(expected_status, rv); | |
| 4087 } | |
| 4088 | |
| 4089 void HttpNetworkTransactionTest::ConnectStatusHelper( | |
| 4090 const MockRead& status) { | |
| 4091 ConnectStatusHelperWithExpectedStatus( | |
| 4092 status, ERR_TUNNEL_CONNECTION_FAILED); | |
| 4093 } | |
| 4094 | |
| 4095 TEST_P(HttpNetworkTransactionTest, ConnectStatus100) { | |
| 4096 ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n")); | |
| 4097 } | |
| 4098 | |
| 4099 TEST_P(HttpNetworkTransactionTest, ConnectStatus101) { | |
| 4100 ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n")); | |
| 4101 } | |
| 4102 | |
| 4103 TEST_P(HttpNetworkTransactionTest, ConnectStatus201) { | |
| 4104 ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n")); | |
| 4105 } | |
| 4106 | |
| 4107 TEST_P(HttpNetworkTransactionTest, ConnectStatus202) { | |
| 4108 ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n")); | |
| 4109 } | |
| 4110 | |
| 4111 TEST_P(HttpNetworkTransactionTest, ConnectStatus203) { | |
| 4112 ConnectStatusHelper( | |
| 4113 MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n")); | |
| 4114 } | |
| 4115 | |
| 4116 TEST_P(HttpNetworkTransactionTest, ConnectStatus204) { | |
| 4117 ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n")); | |
| 4118 } | |
| 4119 | |
| 4120 TEST_P(HttpNetworkTransactionTest, ConnectStatus205) { | |
| 4121 ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n")); | |
| 4122 } | |
| 4123 | |
| 4124 TEST_P(HttpNetworkTransactionTest, ConnectStatus206) { | |
| 4125 ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n")); | |
| 4126 } | |
| 4127 | |
| 4128 TEST_P(HttpNetworkTransactionTest, ConnectStatus300) { | |
| 4129 ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n")); | |
| 4130 } | |
| 4131 | |
| 4132 TEST_P(HttpNetworkTransactionTest, ConnectStatus301) { | |
| 4133 ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n")); | |
| 4134 } | |
| 4135 | |
| 4136 TEST_P(HttpNetworkTransactionTest, ConnectStatus302) { | |
| 4137 ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n")); | |
| 4138 } | |
| 4139 | |
| 4140 TEST_P(HttpNetworkTransactionTest, ConnectStatus303) { | |
| 4141 ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n")); | |
| 4142 } | |
| 4143 | |
| 4144 TEST_P(HttpNetworkTransactionTest, ConnectStatus304) { | |
| 4145 ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n")); | |
| 4146 } | |
| 4147 | |
| 4148 TEST_P(HttpNetworkTransactionTest, ConnectStatus305) { | |
| 4149 ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n")); | |
| 4150 } | |
| 4151 | |
| 4152 TEST_P(HttpNetworkTransactionTest, ConnectStatus306) { | |
| 4153 ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n")); | |
| 4154 } | |
| 4155 | |
| 4156 TEST_P(HttpNetworkTransactionTest, ConnectStatus307) { | |
| 4157 ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n")); | |
| 4158 } | |
| 4159 | |
| 4160 TEST_P(HttpNetworkTransactionTest, ConnectStatus308) { | |
| 4161 ConnectStatusHelper(MockRead("HTTP/1.1 308 Permanent Redirect\r\n")); | |
| 4162 } | |
| 4163 | |
| 4164 TEST_P(HttpNetworkTransactionTest, ConnectStatus400) { | |
| 4165 ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n")); | |
| 4166 } | |
| 4167 | |
| 4168 TEST_P(HttpNetworkTransactionTest, ConnectStatus401) { | |
| 4169 ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n")); | |
| 4170 } | |
| 4171 | |
| 4172 TEST_P(HttpNetworkTransactionTest, ConnectStatus402) { | |
| 4173 ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n")); | |
| 4174 } | |
| 4175 | |
| 4176 TEST_P(HttpNetworkTransactionTest, ConnectStatus403) { | |
| 4177 ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n")); | |
| 4178 } | |
| 4179 | |
| 4180 TEST_P(HttpNetworkTransactionTest, ConnectStatus404) { | |
| 4181 ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n")); | |
| 4182 } | |
| 4183 | |
| 4184 TEST_P(HttpNetworkTransactionTest, ConnectStatus405) { | |
| 4185 ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n")); | |
| 4186 } | |
| 4187 | |
| 4188 TEST_P(HttpNetworkTransactionTest, ConnectStatus406) { | |
| 4189 ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n")); | |
| 4190 } | |
| 4191 | |
| 4192 TEST_P(HttpNetworkTransactionTest, ConnectStatus407) { | |
| 4193 ConnectStatusHelperWithExpectedStatus( | |
| 4194 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 4195 ERR_PROXY_AUTH_UNSUPPORTED); | |
| 4196 } | |
| 4197 | |
| 4198 TEST_P(HttpNetworkTransactionTest, ConnectStatus408) { | |
| 4199 ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n")); | |
| 4200 } | |
| 4201 | |
| 4202 TEST_P(HttpNetworkTransactionTest, ConnectStatus409) { | |
| 4203 ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n")); | |
| 4204 } | |
| 4205 | |
| 4206 TEST_P(HttpNetworkTransactionTest, ConnectStatus410) { | |
| 4207 ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n")); | |
| 4208 } | |
| 4209 | |
| 4210 TEST_P(HttpNetworkTransactionTest, ConnectStatus411) { | |
| 4211 ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n")); | |
| 4212 } | |
| 4213 | |
| 4214 TEST_P(HttpNetworkTransactionTest, ConnectStatus412) { | |
| 4215 ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n")); | |
| 4216 } | |
| 4217 | |
| 4218 TEST_P(HttpNetworkTransactionTest, ConnectStatus413) { | |
| 4219 ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n")); | |
| 4220 } | |
| 4221 | |
| 4222 TEST_P(HttpNetworkTransactionTest, ConnectStatus414) { | |
| 4223 ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n")); | |
| 4224 } | |
| 4225 | |
| 4226 TEST_P(HttpNetworkTransactionTest, ConnectStatus415) { | |
| 4227 ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n")); | |
| 4228 } | |
| 4229 | |
| 4230 TEST_P(HttpNetworkTransactionTest, ConnectStatus416) { | |
| 4231 ConnectStatusHelper( | |
| 4232 MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n")); | |
| 4233 } | |
| 4234 | |
| 4235 TEST_P(HttpNetworkTransactionTest, ConnectStatus417) { | |
| 4236 ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n")); | |
| 4237 } | |
| 4238 | |
| 4239 TEST_P(HttpNetworkTransactionTest, ConnectStatus500) { | |
| 4240 ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n")); | |
| 4241 } | |
| 4242 | |
| 4243 TEST_P(HttpNetworkTransactionTest, ConnectStatus501) { | |
| 4244 ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n")); | |
| 4245 } | |
| 4246 | |
| 4247 TEST_P(HttpNetworkTransactionTest, ConnectStatus502) { | |
| 4248 ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n")); | |
| 4249 } | |
| 4250 | |
| 4251 TEST_P(HttpNetworkTransactionTest, ConnectStatus503) { | |
| 4252 ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n")); | |
| 4253 } | |
| 4254 | |
| 4255 TEST_P(HttpNetworkTransactionTest, ConnectStatus504) { | |
| 4256 ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n")); | |
| 4257 } | |
| 4258 | |
| 4259 TEST_P(HttpNetworkTransactionTest, ConnectStatus505) { | |
| 4260 ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n")); | |
| 4261 } | |
| 4262 | |
| 4263 // Test the flow when both the proxy server AND origin server require | |
| 4264 // authentication. Again, this uses basic auth for both since that is | |
| 4265 // the simplest to mock. | |
| 4266 TEST_P(HttpNetworkTransactionTest, BasicAuthProxyThenServer) { | |
| 4267 HttpRequestInfo request; | |
| 4268 request.method = "GET"; | |
| 4269 request.url = GURL("http://www.google.com/"); | |
| 4270 request.load_flags = 0; | |
| 4271 | |
| 4272 // Configure against proxy server "myproxy:70". | |
| 4273 session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); | |
| 4274 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 4275 | |
| 4276 scoped_ptr<HttpTransaction> trans( | |
| 4277 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 4278 | |
| 4279 MockWrite data_writes1[] = { | |
| 4280 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 4281 "Host: www.google.com\r\n" | |
| 4282 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 4283 }; | |
| 4284 | |
| 4285 MockRead data_reads1[] = { | |
| 4286 MockRead("HTTP/1.0 407 Unauthorized\r\n"), | |
| 4287 // Give a couple authenticate options (only the middle one is actually | |
| 4288 // supported). | |
| 4289 MockRead("Proxy-Authenticate: Basic invalid\r\n"), // Malformed. | |
| 4290 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 4291 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), | |
| 4292 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 4293 // Large content-length -- won't matter, as connection will be reset. | |
| 4294 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 4295 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 4296 }; | |
| 4297 | |
| 4298 // After calling trans->RestartWithAuth() the first time, this is the | |
| 4299 // request we should be issuing -- the final header line contains the | |
| 4300 // proxy's credentials. | |
| 4301 MockWrite data_writes2[] = { | |
| 4302 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 4303 "Host: www.google.com\r\n" | |
| 4304 "Proxy-Connection: keep-alive\r\n" | |
| 4305 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 4306 }; | |
| 4307 | |
| 4308 // Now the proxy server lets the request pass through to origin server. | |
| 4309 // The origin server responds with a 401. | |
| 4310 MockRead data_reads2[] = { | |
| 4311 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 4312 // Note: We are using the same realm-name as the proxy server. This is | |
| 4313 // completely valid, as realms are unique across hosts. | |
| 4314 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 4315 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 4316 MockRead("Content-Length: 2000\r\n\r\n"), | |
| 4317 MockRead(SYNCHRONOUS, ERR_FAILED), // Won't be reached. | |
| 4318 }; | |
| 4319 | |
| 4320 // After calling trans->RestartWithAuth() the second time, we should send | |
| 4321 // the credentials for both the proxy and origin server. | |
| 4322 MockWrite data_writes3[] = { | |
| 4323 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 4324 "Host: www.google.com\r\n" | |
| 4325 "Proxy-Connection: keep-alive\r\n" | |
| 4326 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" | |
| 4327 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), | |
| 4328 }; | |
| 4329 | |
| 4330 // Lastly we get the desired content. | |
| 4331 MockRead data_reads3[] = { | |
| 4332 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 4333 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 4334 MockRead("Content-Length: 100\r\n\r\n"), | |
| 4335 MockRead(SYNCHRONOUS, OK), | |
| 4336 }; | |
| 4337 | |
| 4338 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 4339 data_writes1, arraysize(data_writes1)); | |
| 4340 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 4341 data_writes2, arraysize(data_writes2)); | |
| 4342 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
| 4343 data_writes3, arraysize(data_writes3)); | |
| 4344 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 4345 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 4346 session_deps_.socket_factory->AddSocketDataProvider(&data3); | |
| 4347 | |
| 4348 TestCompletionCallback callback1; | |
| 4349 | |
| 4350 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 4351 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4352 | |
| 4353 rv = callback1.WaitForResult(); | |
| 4354 EXPECT_EQ(OK, rv); | |
| 4355 | |
| 4356 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4357 ASSERT_TRUE(response != NULL); | |
| 4358 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 4359 | |
| 4360 TestCompletionCallback callback2; | |
| 4361 | |
| 4362 rv = trans->RestartWithAuth( | |
| 4363 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 4364 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4365 | |
| 4366 rv = callback2.WaitForResult(); | |
| 4367 EXPECT_EQ(OK, rv); | |
| 4368 | |
| 4369 response = trans->GetResponseInfo(); | |
| 4370 ASSERT_TRUE(response != NULL); | |
| 4371 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 4372 | |
| 4373 TestCompletionCallback callback3; | |
| 4374 | |
| 4375 rv = trans->RestartWithAuth( | |
| 4376 AuthCredentials(kFoo2, kBar2), callback3.callback()); | |
| 4377 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4378 | |
| 4379 rv = callback3.WaitForResult(); | |
| 4380 EXPECT_EQ(OK, rv); | |
| 4381 | |
| 4382 response = trans->GetResponseInfo(); | |
| 4383 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 4384 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 4385 } | |
| 4386 | |
| 4387 // For the NTLM implementation using SSPI, we skip the NTLM tests since we | |
| 4388 // can't hook into its internals to cause it to generate predictable NTLM | |
| 4389 // authorization headers. | |
| 4390 #if defined(NTLM_PORTABLE) | |
| 4391 // The NTLM authentication unit tests were generated by capturing the HTTP | |
| 4392 // requests and responses using Fiddler 2 and inspecting the generated random | |
| 4393 // bytes in the debugger. | |
| 4394 | |
| 4395 // Enter the correct password and authenticate successfully. | |
| 4396 TEST_P(HttpNetworkTransactionTest, NTLMAuth1) { | |
| 4397 HttpRequestInfo request; | |
| 4398 request.method = "GET"; | |
| 4399 request.url = GURL("http://172.22.68.17/kids/login.aspx"); | |
| 4400 | |
| 4401 // Ensure load is not disrupted by flags which suppress behaviour specific | |
| 4402 // to other auth schemes. | |
| 4403 request.load_flags = LOAD_DO_NOT_USE_EMBEDDED_IDENTITY; | |
| 4404 | |
| 4405 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1, | |
| 4406 MockGetHostName); | |
| 4407 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 4408 | |
| 4409 MockWrite data_writes1[] = { | |
| 4410 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 4411 "Host: 172.22.68.17\r\n" | |
| 4412 "Connection: keep-alive\r\n\r\n"), | |
| 4413 }; | |
| 4414 | |
| 4415 MockRead data_reads1[] = { | |
| 4416 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 4417 // Negotiate and NTLM are often requested together. However, we only want | |
| 4418 // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip | |
| 4419 // the header that requests Negotiate for this test. | |
| 4420 MockRead("WWW-Authenticate: NTLM\r\n"), | |
| 4421 MockRead("Connection: close\r\n"), | |
| 4422 MockRead("Content-Length: 42\r\n"), | |
| 4423 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 4424 // Missing content -- won't matter, as connection will be reset. | |
| 4425 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), | |
| 4426 }; | |
| 4427 | |
| 4428 MockWrite data_writes2[] = { | |
| 4429 // After restarting with a null identity, this is the | |
| 4430 // request we should be issuing -- the final header line contains a Type | |
| 4431 // 1 message. | |
| 4432 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 4433 "Host: 172.22.68.17\r\n" | |
| 4434 "Connection: keep-alive\r\n" | |
| 4435 "Authorization: NTLM " | |
| 4436 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), | |
| 4437 | |
| 4438 // After calling trans->RestartWithAuth(), we should send a Type 3 message | |
| 4439 // (the credentials for the origin server). The second request continues | |
| 4440 // on the same connection. | |
| 4441 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 4442 "Host: 172.22.68.17\r\n" | |
| 4443 "Connection: keep-alive\r\n" | |
| 4444 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" | |
| 4445 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" | |
| 4446 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW" | |
| 4447 "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX" | |
| 4448 "ahlhx5I=\r\n\r\n"), | |
| 4449 }; | |
| 4450 | |
| 4451 MockRead data_reads2[] = { | |
| 4452 // The origin server responds with a Type 2 message. | |
| 4453 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 4454 MockRead("WWW-Authenticate: NTLM " | |
| 4455 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo" | |
| 4456 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" | |
| 4457 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" | |
| 4458 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" | |
| 4459 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" | |
| 4460 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" | |
| 4461 "BtAAAAAAA=\r\n"), | |
| 4462 MockRead("Content-Length: 42\r\n"), | |
| 4463 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 4464 MockRead("You are not authorized to view this page\r\n"), | |
| 4465 | |
| 4466 // Lastly we get the desired content. | |
| 4467 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 4468 MockRead("Content-Type: text/html; charset=utf-8\r\n"), | |
| 4469 MockRead("Content-Length: 13\r\n\r\n"), | |
| 4470 MockRead("Please Login\r\n"), | |
| 4471 MockRead(SYNCHRONOUS, OK), | |
| 4472 }; | |
| 4473 | |
| 4474 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 4475 data_writes1, arraysize(data_writes1)); | |
| 4476 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 4477 data_writes2, arraysize(data_writes2)); | |
| 4478 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 4479 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 4480 | |
| 4481 TestCompletionCallback callback1; | |
| 4482 | |
| 4483 scoped_ptr<HttpTransaction> trans( | |
| 4484 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 4485 | |
| 4486 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 4487 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4488 | |
| 4489 rv = callback1.WaitForResult(); | |
| 4490 EXPECT_EQ(OK, rv); | |
| 4491 | |
| 4492 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 4493 | |
| 4494 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4495 ASSERT_FALSE(response == NULL); | |
| 4496 EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); | |
| 4497 | |
| 4498 TestCompletionCallback callback2; | |
| 4499 | |
| 4500 rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM), | |
| 4501 callback2.callback()); | |
| 4502 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4503 | |
| 4504 rv = callback2.WaitForResult(); | |
| 4505 EXPECT_EQ(OK, rv); | |
| 4506 | |
| 4507 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 4508 | |
| 4509 response = trans->GetResponseInfo(); | |
| 4510 ASSERT_TRUE(response != NULL); | |
| 4511 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 4512 | |
| 4513 TestCompletionCallback callback3; | |
| 4514 | |
| 4515 rv = trans->RestartWithAuth(AuthCredentials(), callback3.callback()); | |
| 4516 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4517 | |
| 4518 rv = callback3.WaitForResult(); | |
| 4519 EXPECT_EQ(OK, rv); | |
| 4520 | |
| 4521 response = trans->GetResponseInfo(); | |
| 4522 ASSERT_TRUE(response != NULL); | |
| 4523 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 4524 EXPECT_EQ(13, response->headers->GetContentLength()); | |
| 4525 } | |
| 4526 | |
| 4527 // Enter a wrong password, and then the correct one. | |
| 4528 TEST_P(HttpNetworkTransactionTest, NTLMAuth2) { | |
| 4529 HttpRequestInfo request; | |
| 4530 request.method = "GET"; | |
| 4531 request.url = GURL("http://172.22.68.17/kids/login.aspx"); | |
| 4532 request.load_flags = 0; | |
| 4533 | |
| 4534 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom2, | |
| 4535 MockGetHostName); | |
| 4536 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 4537 | |
| 4538 MockWrite data_writes1[] = { | |
| 4539 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 4540 "Host: 172.22.68.17\r\n" | |
| 4541 "Connection: keep-alive\r\n\r\n"), | |
| 4542 }; | |
| 4543 | |
| 4544 MockRead data_reads1[] = { | |
| 4545 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 4546 // Negotiate and NTLM are often requested together. However, we only want | |
| 4547 // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip | |
| 4548 // the header that requests Negotiate for this test. | |
| 4549 MockRead("WWW-Authenticate: NTLM\r\n"), | |
| 4550 MockRead("Connection: close\r\n"), | |
| 4551 MockRead("Content-Length: 42\r\n"), | |
| 4552 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 4553 // Missing content -- won't matter, as connection will be reset. | |
| 4554 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), | |
| 4555 }; | |
| 4556 | |
| 4557 MockWrite data_writes2[] = { | |
| 4558 // After restarting with a null identity, this is the | |
| 4559 // request we should be issuing -- the final header line contains a Type | |
| 4560 // 1 message. | |
| 4561 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 4562 "Host: 172.22.68.17\r\n" | |
| 4563 "Connection: keep-alive\r\n" | |
| 4564 "Authorization: NTLM " | |
| 4565 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), | |
| 4566 | |
| 4567 // After calling trans->RestartWithAuth(), we should send a Type 3 message | |
| 4568 // (the credentials for the origin server). The second request continues | |
| 4569 // on the same connection. | |
| 4570 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 4571 "Host: 172.22.68.17\r\n" | |
| 4572 "Connection: keep-alive\r\n" | |
| 4573 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" | |
| 4574 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" | |
| 4575 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY" | |
| 4576 "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj" | |
| 4577 "4Ww7b7E=\r\n\r\n"), | |
| 4578 }; | |
| 4579 | |
| 4580 MockRead data_reads2[] = { | |
| 4581 // The origin server responds with a Type 2 message. | |
| 4582 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 4583 MockRead("WWW-Authenticate: NTLM " | |
| 4584 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCbVWUZezVGpAAAAAAAAAAALo" | |
| 4585 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" | |
| 4586 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" | |
| 4587 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" | |
| 4588 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" | |
| 4589 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" | |
| 4590 "BtAAAAAAA=\r\n"), | |
| 4591 MockRead("Content-Length: 42\r\n"), | |
| 4592 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 4593 MockRead("You are not authorized to view this page\r\n"), | |
| 4594 | |
| 4595 // Wrong password. | |
| 4596 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 4597 MockRead("WWW-Authenticate: NTLM\r\n"), | |
| 4598 MockRead("Connection: close\r\n"), | |
| 4599 MockRead("Content-Length: 42\r\n"), | |
| 4600 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 4601 // Missing content -- won't matter, as connection will be reset. | |
| 4602 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), | |
| 4603 }; | |
| 4604 | |
| 4605 MockWrite data_writes3[] = { | |
| 4606 // After restarting with a null identity, this is the | |
| 4607 // request we should be issuing -- the final header line contains a Type | |
| 4608 // 1 message. | |
| 4609 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 4610 "Host: 172.22.68.17\r\n" | |
| 4611 "Connection: keep-alive\r\n" | |
| 4612 "Authorization: NTLM " | |
| 4613 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), | |
| 4614 | |
| 4615 // After calling trans->RestartWithAuth(), we should send a Type 3 message | |
| 4616 // (the credentials for the origin server). The second request continues | |
| 4617 // on the same connection. | |
| 4618 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 4619 "Host: 172.22.68.17\r\n" | |
| 4620 "Connection: keep-alive\r\n" | |
| 4621 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" | |
| 4622 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" | |
| 4623 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54" | |
| 4624 "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI" | |
| 4625 "+4MUm7c=\r\n\r\n"), | |
| 4626 }; | |
| 4627 | |
| 4628 MockRead data_reads3[] = { | |
| 4629 // The origin server responds with a Type 2 message. | |
| 4630 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 4631 MockRead("WWW-Authenticate: NTLM " | |
| 4632 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCL24VN8dgOR8AAAAAAAAAALo" | |
| 4633 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" | |
| 4634 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" | |
| 4635 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" | |
| 4636 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" | |
| 4637 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" | |
| 4638 "BtAAAAAAA=\r\n"), | |
| 4639 MockRead("Content-Length: 42\r\n"), | |
| 4640 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 4641 MockRead("You are not authorized to view this page\r\n"), | |
| 4642 | |
| 4643 // Lastly we get the desired content. | |
| 4644 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 4645 MockRead("Content-Type: text/html; charset=utf-8\r\n"), | |
| 4646 MockRead("Content-Length: 13\r\n\r\n"), | |
| 4647 MockRead("Please Login\r\n"), | |
| 4648 MockRead(SYNCHRONOUS, OK), | |
| 4649 }; | |
| 4650 | |
| 4651 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 4652 data_writes1, arraysize(data_writes1)); | |
| 4653 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 4654 data_writes2, arraysize(data_writes2)); | |
| 4655 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
| 4656 data_writes3, arraysize(data_writes3)); | |
| 4657 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 4658 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 4659 session_deps_.socket_factory->AddSocketDataProvider(&data3); | |
| 4660 | |
| 4661 TestCompletionCallback callback1; | |
| 4662 | |
| 4663 scoped_ptr<HttpTransaction> trans( | |
| 4664 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 4665 | |
| 4666 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 4667 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4668 | |
| 4669 rv = callback1.WaitForResult(); | |
| 4670 EXPECT_EQ(OK, rv); | |
| 4671 | |
| 4672 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 4673 | |
| 4674 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4675 ASSERT_TRUE(response != NULL); | |
| 4676 EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); | |
| 4677 | |
| 4678 TestCompletionCallback callback2; | |
| 4679 | |
| 4680 // Enter the wrong password. | |
| 4681 rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kWrongPassword), | |
| 4682 callback2.callback()); | |
| 4683 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4684 | |
| 4685 rv = callback2.WaitForResult(); | |
| 4686 EXPECT_EQ(OK, rv); | |
| 4687 | |
| 4688 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 4689 TestCompletionCallback callback3; | |
| 4690 rv = trans->RestartWithAuth(AuthCredentials(), callback3.callback()); | |
| 4691 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4692 rv = callback3.WaitForResult(); | |
| 4693 EXPECT_EQ(OK, rv); | |
| 4694 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 4695 | |
| 4696 response = trans->GetResponseInfo(); | |
| 4697 ASSERT_FALSE(response == NULL); | |
| 4698 EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); | |
| 4699 | |
| 4700 TestCompletionCallback callback4; | |
| 4701 | |
| 4702 // Now enter the right password. | |
| 4703 rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM), | |
| 4704 callback4.callback()); | |
| 4705 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4706 | |
| 4707 rv = callback4.WaitForResult(); | |
| 4708 EXPECT_EQ(OK, rv); | |
| 4709 | |
| 4710 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 4711 | |
| 4712 TestCompletionCallback callback5; | |
| 4713 | |
| 4714 // One more roundtrip | |
| 4715 rv = trans->RestartWithAuth(AuthCredentials(), callback5.callback()); | |
| 4716 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4717 | |
| 4718 rv = callback5.WaitForResult(); | |
| 4719 EXPECT_EQ(OK, rv); | |
| 4720 | |
| 4721 response = trans->GetResponseInfo(); | |
| 4722 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 4723 EXPECT_EQ(13, response->headers->GetContentLength()); | |
| 4724 } | |
| 4725 #endif // NTLM_PORTABLE | |
| 4726 | |
| 4727 // Test reading a server response which has only headers, and no body. | |
| 4728 // After some maximum number of bytes is consumed, the transaction should | |
| 4729 // fail with ERR_RESPONSE_HEADERS_TOO_BIG. | |
| 4730 TEST_P(HttpNetworkTransactionTest, LargeHeadersNoBody) { | |
| 4731 HttpRequestInfo request; | |
| 4732 request.method = "GET"; | |
| 4733 request.url = GURL("http://www.google.com/"); | |
| 4734 request.load_flags = 0; | |
| 4735 | |
| 4736 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 4737 scoped_ptr<HttpTransaction> trans( | |
| 4738 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 4739 | |
| 4740 // Respond with 300 kb of headers (we should fail after 256 kb). | |
| 4741 std::string large_headers_string; | |
| 4742 FillLargeHeadersString(&large_headers_string, 300 * 1024); | |
| 4743 | |
| 4744 MockRead data_reads[] = { | |
| 4745 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 4746 MockRead(ASYNC, large_headers_string.data(), large_headers_string.size()), | |
| 4747 MockRead("\r\nBODY"), | |
| 4748 MockRead(SYNCHRONOUS, OK), | |
| 4749 }; | |
| 4750 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 4751 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 4752 | |
| 4753 TestCompletionCallback callback; | |
| 4754 | |
| 4755 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4756 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4757 | |
| 4758 rv = callback.WaitForResult(); | |
| 4759 EXPECT_EQ(ERR_RESPONSE_HEADERS_TOO_BIG, rv); | |
| 4760 | |
| 4761 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4762 EXPECT_TRUE(response == NULL); | |
| 4763 } | |
| 4764 | |
| 4765 // Make sure that we don't try to reuse a TCPClientSocket when failing to | |
| 4766 // establish tunnel. | |
| 4767 // http://code.google.com/p/chromium/issues/detail?id=3772 | |
| 4768 TEST_P(HttpNetworkTransactionTest, | |
| 4769 DontRecycleTransportSocketForSSLTunnel) { | |
| 4770 HttpRequestInfo request; | |
| 4771 request.method = "GET"; | |
| 4772 request.url = GURL("https://www.google.com/"); | |
| 4773 request.load_flags = 0; | |
| 4774 | |
| 4775 // Configure against proxy server "myproxy:70". | |
| 4776 session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); | |
| 4777 | |
| 4778 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 4779 | |
| 4780 scoped_ptr<HttpTransaction> trans( | |
| 4781 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 4782 | |
| 4783 // Since we have proxy, should try to establish tunnel. | |
| 4784 MockWrite data_writes1[] = { | |
| 4785 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 4786 "Host: www.google.com\r\n" | |
| 4787 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 4788 }; | |
| 4789 | |
| 4790 // The proxy responds to the connect with a 404, using a persistent | |
| 4791 // connection. Usually a proxy would return 501 (not implemented), | |
| 4792 // or 200 (tunnel established). | |
| 4793 MockRead data_reads1[] = { | |
| 4794 MockRead("HTTP/1.1 404 Not Found\r\n"), | |
| 4795 MockRead("Content-Length: 10\r\n\r\n"), | |
| 4796 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 4797 }; | |
| 4798 | |
| 4799 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 4800 data_writes1, arraysize(data_writes1)); | |
| 4801 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 4802 | |
| 4803 TestCompletionCallback callback1; | |
| 4804 | |
| 4805 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 4806 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4807 | |
| 4808 rv = callback1.WaitForResult(); | |
| 4809 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
| 4810 | |
| 4811 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4812 EXPECT_TRUE(response == NULL); | |
| 4813 | |
| 4814 // Empty the current queue. This is necessary because idle sockets are | |
| 4815 // added to the connection pool asynchronously with a PostTask. | |
| 4816 base::MessageLoop::current()->RunUntilIdle(); | |
| 4817 | |
| 4818 // We now check to make sure the TCPClientSocket was not added back to | |
| 4819 // the pool. | |
| 4820 EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 4821 trans.reset(); | |
| 4822 base::MessageLoop::current()->RunUntilIdle(); | |
| 4823 // Make sure that the socket didn't get recycled after calling the destructor. | |
| 4824 EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 4825 } | |
| 4826 | |
| 4827 // Make sure that we recycle a socket after reading all of the response body. | |
| 4828 TEST_P(HttpNetworkTransactionTest, RecycleSocket) { | |
| 4829 HttpRequestInfo request; | |
| 4830 request.method = "GET"; | |
| 4831 request.url = GURL("http://www.google.com/"); | |
| 4832 request.load_flags = 0; | |
| 4833 | |
| 4834 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 4835 | |
| 4836 scoped_ptr<HttpTransaction> trans( | |
| 4837 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 4838 | |
| 4839 MockRead data_reads[] = { | |
| 4840 // A part of the response body is received with the response headers. | |
| 4841 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"), | |
| 4842 // The rest of the response body is received in two parts. | |
| 4843 MockRead("lo"), | |
| 4844 MockRead(" world"), | |
| 4845 MockRead("junk"), // Should not be read!! | |
| 4846 MockRead(SYNCHRONOUS, OK), | |
| 4847 }; | |
| 4848 | |
| 4849 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 4850 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 4851 | |
| 4852 TestCompletionCallback callback; | |
| 4853 | |
| 4854 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4855 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4856 | |
| 4857 rv = callback.WaitForResult(); | |
| 4858 EXPECT_EQ(OK, rv); | |
| 4859 | |
| 4860 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4861 ASSERT_TRUE(response != NULL); | |
| 4862 | |
| 4863 EXPECT_TRUE(response->headers.get() != NULL); | |
| 4864 std::string status_line = response->headers->GetStatusLine(); | |
| 4865 EXPECT_EQ("HTTP/1.1 200 OK", status_line); | |
| 4866 | |
| 4867 EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 4868 | |
| 4869 std::string response_data; | |
| 4870 rv = ReadTransaction(trans.get(), &response_data); | |
| 4871 EXPECT_EQ(OK, rv); | |
| 4872 EXPECT_EQ("hello world", response_data); | |
| 4873 | |
| 4874 // Empty the current queue. This is necessary because idle sockets are | |
| 4875 // added to the connection pool asynchronously with a PostTask. | |
| 4876 base::MessageLoop::current()->RunUntilIdle(); | |
| 4877 | |
| 4878 // We now check to make sure the socket was added back to the pool. | |
| 4879 EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 4880 } | |
| 4881 | |
| 4882 // Make sure that we recycle a SSL socket after reading all of the response | |
| 4883 // body. | |
| 4884 TEST_P(HttpNetworkTransactionTest, RecycleSSLSocket) { | |
| 4885 HttpRequestInfo request; | |
| 4886 request.method = "GET"; | |
| 4887 request.url = GURL("https://www.google.com/"); | |
| 4888 request.load_flags = 0; | |
| 4889 | |
| 4890 MockWrite data_writes[] = { | |
| 4891 MockWrite("GET / HTTP/1.1\r\n" | |
| 4892 "Host: www.google.com\r\n" | |
| 4893 "Connection: keep-alive\r\n\r\n"), | |
| 4894 }; | |
| 4895 | |
| 4896 MockRead data_reads[] = { | |
| 4897 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 4898 MockRead("Content-Length: 11\r\n\r\n"), | |
| 4899 MockRead("hello world"), | |
| 4900 MockRead(SYNCHRONOUS, OK), | |
| 4901 }; | |
| 4902 | |
| 4903 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 4904 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 4905 | |
| 4906 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 4907 data_writes, arraysize(data_writes)); | |
| 4908 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 4909 | |
| 4910 TestCompletionCallback callback; | |
| 4911 | |
| 4912 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 4913 scoped_ptr<HttpTransaction> trans( | |
| 4914 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 4915 | |
| 4916 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4917 | |
| 4918 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4919 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 4920 | |
| 4921 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4922 ASSERT_TRUE(response != NULL); | |
| 4923 ASSERT_TRUE(response->headers.get() != NULL); | |
| 4924 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 4925 | |
| 4926 EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 4927 | |
| 4928 std::string response_data; | |
| 4929 rv = ReadTransaction(trans.get(), &response_data); | |
| 4930 EXPECT_EQ(OK, rv); | |
| 4931 EXPECT_EQ("hello world", response_data); | |
| 4932 | |
| 4933 // Empty the current queue. This is necessary because idle sockets are | |
| 4934 // added to the connection pool asynchronously with a PostTask. | |
| 4935 base::MessageLoop::current()->RunUntilIdle(); | |
| 4936 | |
| 4937 // We now check to make sure the socket was added back to the pool. | |
| 4938 EXPECT_EQ(1, GetIdleSocketCountInSSLSocketPool(session.get())); | |
| 4939 } | |
| 4940 | |
| 4941 // Grab a SSL socket, use it, and put it back into the pool. Then, reuse it | |
| 4942 // from the pool and make sure that we recover okay. | |
| 4943 TEST_P(HttpNetworkTransactionTest, RecycleDeadSSLSocket) { | |
| 4944 HttpRequestInfo request; | |
| 4945 request.method = "GET"; | |
| 4946 request.url = GURL("https://www.google.com/"); | |
| 4947 request.load_flags = 0; | |
| 4948 | |
| 4949 MockWrite data_writes[] = { | |
| 4950 MockWrite("GET / HTTP/1.1\r\n" | |
| 4951 "Host: www.google.com\r\n" | |
| 4952 "Connection: keep-alive\r\n\r\n"), | |
| 4953 MockWrite("GET / HTTP/1.1\r\n" | |
| 4954 "Host: www.google.com\r\n" | |
| 4955 "Connection: keep-alive\r\n\r\n"), | |
| 4956 }; | |
| 4957 | |
| 4958 MockRead data_reads[] = { | |
| 4959 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 4960 MockRead("Content-Length: 11\r\n\r\n"), | |
| 4961 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 4962 MockRead("hello world"), | |
| 4963 MockRead(ASYNC, 0, 0) // EOF | |
| 4964 }; | |
| 4965 | |
| 4966 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 4967 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 4968 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 4969 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2); | |
| 4970 | |
| 4971 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 4972 data_writes, arraysize(data_writes)); | |
| 4973 StaticSocketDataProvider data2(data_reads, arraysize(data_reads), | |
| 4974 data_writes, arraysize(data_writes)); | |
| 4975 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 4976 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 4977 | |
| 4978 TestCompletionCallback callback; | |
| 4979 | |
| 4980 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 4981 scoped_ptr<HttpTransaction> trans( | |
| 4982 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 4983 | |
| 4984 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4985 | |
| 4986 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4987 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 4988 | |
| 4989 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4990 ASSERT_TRUE(response != NULL); | |
| 4991 ASSERT_TRUE(response->headers.get() != NULL); | |
| 4992 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 4993 | |
| 4994 EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 4995 | |
| 4996 std::string response_data; | |
| 4997 rv = ReadTransaction(trans.get(), &response_data); | |
| 4998 EXPECT_EQ(OK, rv); | |
| 4999 EXPECT_EQ("hello world", response_data); | |
| 5000 | |
| 5001 // Empty the current queue. This is necessary because idle sockets are | |
| 5002 // added to the connection pool asynchronously with a PostTask. | |
| 5003 base::MessageLoop::current()->RunUntilIdle(); | |
| 5004 | |
| 5005 // We now check to make sure the socket was added back to the pool. | |
| 5006 EXPECT_EQ(1, GetIdleSocketCountInSSLSocketPool(session.get())); | |
| 5007 | |
| 5008 // Now start the second transaction, which should reuse the previous socket. | |
| 5009 | |
| 5010 trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5011 | |
| 5012 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5013 | |
| 5014 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5015 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 5016 | |
| 5017 response = trans->GetResponseInfo(); | |
| 5018 ASSERT_TRUE(response != NULL); | |
| 5019 ASSERT_TRUE(response->headers.get() != NULL); | |
| 5020 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 5021 | |
| 5022 EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 5023 | |
| 5024 rv = ReadTransaction(trans.get(), &response_data); | |
| 5025 EXPECT_EQ(OK, rv); | |
| 5026 EXPECT_EQ("hello world", response_data); | |
| 5027 | |
| 5028 // Empty the current queue. This is necessary because idle sockets are | |
| 5029 // added to the connection pool asynchronously with a PostTask. | |
| 5030 base::MessageLoop::current()->RunUntilIdle(); | |
| 5031 | |
| 5032 // We now check to make sure the socket was added back to the pool. | |
| 5033 EXPECT_EQ(1, GetIdleSocketCountInSSLSocketPool(session.get())); | |
| 5034 } | |
| 5035 | |
| 5036 // Make sure that we recycle a socket after a zero-length response. | |
| 5037 // http://crbug.com/9880 | |
| 5038 TEST_P(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) { | |
| 5039 HttpRequestInfo request; | |
| 5040 request.method = "GET"; | |
| 5041 request.url = GURL("http://www.google.com/csi?v=3&s=web&action=&" | |
| 5042 "tran=undefined&ei=mAXcSeegAo-SMurloeUN&" | |
| 5043 "e=17259,18167,19592,19773,19981,20133,20173,20233&" | |
| 5044 "rt=prt.2642,ol.2649,xjs.2951"); | |
| 5045 request.load_flags = 0; | |
| 5046 | |
| 5047 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 5048 | |
| 5049 scoped_ptr<HttpTransaction> trans( | |
| 5050 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5051 | |
| 5052 MockRead data_reads[] = { | |
| 5053 MockRead("HTTP/1.1 204 No Content\r\n" | |
| 5054 "Content-Length: 0\r\n" | |
| 5055 "Content-Type: text/html\r\n\r\n"), | |
| 5056 MockRead("junk"), // Should not be read!! | |
| 5057 MockRead(SYNCHRONOUS, OK), | |
| 5058 }; | |
| 5059 | |
| 5060 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 5061 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 5062 | |
| 5063 TestCompletionCallback callback; | |
| 5064 | |
| 5065 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5066 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5067 | |
| 5068 rv = callback.WaitForResult(); | |
| 5069 EXPECT_EQ(OK, rv); | |
| 5070 | |
| 5071 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5072 ASSERT_TRUE(response != NULL); | |
| 5073 | |
| 5074 EXPECT_TRUE(response->headers.get() != NULL); | |
| 5075 std::string status_line = response->headers->GetStatusLine(); | |
| 5076 EXPECT_EQ("HTTP/1.1 204 No Content", status_line); | |
| 5077 | |
| 5078 EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 5079 | |
| 5080 std::string response_data; | |
| 5081 rv = ReadTransaction(trans.get(), &response_data); | |
| 5082 EXPECT_EQ(OK, rv); | |
| 5083 EXPECT_EQ("", response_data); | |
| 5084 | |
| 5085 // Empty the current queue. This is necessary because idle sockets are | |
| 5086 // added to the connection pool asynchronously with a PostTask. | |
| 5087 base::MessageLoop::current()->RunUntilIdle(); | |
| 5088 | |
| 5089 // We now check to make sure the socket was added back to the pool. | |
| 5090 EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 5091 } | |
| 5092 | |
| 5093 TEST_P(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) { | |
| 5094 ScopedVector<UploadElementReader> element_readers; | |
| 5095 element_readers.push_back(new UploadBytesElementReader("foo", 3)); | |
| 5096 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 5097 | |
| 5098 HttpRequestInfo request[2]; | |
| 5099 // Transaction 1: a GET request that succeeds. The socket is recycled | |
| 5100 // after use. | |
| 5101 request[0].method = "GET"; | |
| 5102 request[0].url = GURL("http://www.google.com/"); | |
| 5103 request[0].load_flags = 0; | |
| 5104 // Transaction 2: a POST request. Reuses the socket kept alive from | |
| 5105 // transaction 1. The first attempts fails when writing the POST data. | |
| 5106 // This causes the transaction to retry with a new socket. The second | |
| 5107 // attempt succeeds. | |
| 5108 request[1].method = "POST"; | |
| 5109 request[1].url = GURL("http://www.google.com/login.cgi"); | |
| 5110 request[1].upload_data_stream = &upload_data_stream; | |
| 5111 request[1].load_flags = 0; | |
| 5112 | |
| 5113 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 5114 | |
| 5115 // The first socket is used for transaction 1 and the first attempt of | |
| 5116 // transaction 2. | |
| 5117 | |
| 5118 // The response of transaction 1. | |
| 5119 MockRead data_reads1[] = { | |
| 5120 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"), | |
| 5121 MockRead("hello world"), | |
| 5122 MockRead(SYNCHRONOUS, OK), | |
| 5123 }; | |
| 5124 // The mock write results of transaction 1 and the first attempt of | |
| 5125 // transaction 2. | |
| 5126 MockWrite data_writes1[] = { | |
| 5127 MockWrite(SYNCHRONOUS, 64), // GET | |
| 5128 MockWrite(SYNCHRONOUS, 93), // POST | |
| 5129 MockWrite(SYNCHRONOUS, ERR_CONNECTION_ABORTED), // POST data | |
| 5130 }; | |
| 5131 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 5132 data_writes1, arraysize(data_writes1)); | |
| 5133 | |
| 5134 // The second socket is used for the second attempt of transaction 2. | |
| 5135 | |
| 5136 // The response of transaction 2. | |
| 5137 MockRead data_reads2[] = { | |
| 5138 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"), | |
| 5139 MockRead("welcome"), | |
| 5140 MockRead(SYNCHRONOUS, OK), | |
| 5141 }; | |
| 5142 // The mock write results of the second attempt of transaction 2. | |
| 5143 MockWrite data_writes2[] = { | |
| 5144 MockWrite(SYNCHRONOUS, 93), // POST | |
| 5145 MockWrite(SYNCHRONOUS, 3), // POST data | |
| 5146 }; | |
| 5147 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 5148 data_writes2, arraysize(data_writes2)); | |
| 5149 | |
| 5150 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 5151 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 5152 | |
| 5153 const char* const kExpectedResponseData[] = { | |
| 5154 "hello world", "welcome" | |
| 5155 }; | |
| 5156 | |
| 5157 for (int i = 0; i < 2; ++i) { | |
| 5158 scoped_ptr<HttpTransaction> trans( | |
| 5159 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5160 | |
| 5161 TestCompletionCallback callback; | |
| 5162 | |
| 5163 int rv = trans->Start(&request[i], callback.callback(), BoundNetLog()); | |
| 5164 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5165 | |
| 5166 rv = callback.WaitForResult(); | |
| 5167 EXPECT_EQ(OK, rv); | |
| 5168 | |
| 5169 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5170 ASSERT_TRUE(response != NULL); | |
| 5171 | |
| 5172 EXPECT_TRUE(response->headers.get() != NULL); | |
| 5173 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 5174 | |
| 5175 std::string response_data; | |
| 5176 rv = ReadTransaction(trans.get(), &response_data); | |
| 5177 EXPECT_EQ(OK, rv); | |
| 5178 EXPECT_EQ(kExpectedResponseData[i], response_data); | |
| 5179 } | |
| 5180 } | |
| 5181 | |
| 5182 // Test the request-challenge-retry sequence for basic auth when there is | |
| 5183 // an identity in the URL. The request should be sent as normal, but when | |
| 5184 // it fails the identity from the URL is used to answer the challenge. | |
| 5185 TEST_P(HttpNetworkTransactionTest, AuthIdentityInURL) { | |
| 5186 HttpRequestInfo request; | |
| 5187 request.method = "GET"; | |
| 5188 request.url = GURL("http://foo:b@r@www.google.com/"); | |
| 5189 request.load_flags = LOAD_NORMAL; | |
| 5190 | |
| 5191 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 5192 scoped_ptr<HttpTransaction> trans( | |
| 5193 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5194 | |
| 5195 // The password contains an escaped character -- for this test to pass it | |
| 5196 // will need to be unescaped by HttpNetworkTransaction. | |
| 5197 EXPECT_EQ("b%40r", request.url.password()); | |
| 5198 | |
| 5199 MockWrite data_writes1[] = { | |
| 5200 MockWrite("GET / HTTP/1.1\r\n" | |
| 5201 "Host: www.google.com\r\n" | |
| 5202 "Connection: keep-alive\r\n\r\n"), | |
| 5203 }; | |
| 5204 | |
| 5205 MockRead data_reads1[] = { | |
| 5206 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 5207 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 5208 MockRead("Content-Length: 10\r\n\r\n"), | |
| 5209 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 5210 }; | |
| 5211 | |
| 5212 // After the challenge above, the transaction will be restarted using the | |
| 5213 // identity from the url (foo, b@r) to answer the challenge. | |
| 5214 MockWrite data_writes2[] = { | |
| 5215 MockWrite("GET / HTTP/1.1\r\n" | |
| 5216 "Host: www.google.com\r\n" | |
| 5217 "Connection: keep-alive\r\n" | |
| 5218 "Authorization: Basic Zm9vOmJAcg==\r\n\r\n"), | |
| 5219 }; | |
| 5220 | |
| 5221 MockRead data_reads2[] = { | |
| 5222 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5223 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5224 MockRead(SYNCHRONOUS, OK), | |
| 5225 }; | |
| 5226 | |
| 5227 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 5228 data_writes1, arraysize(data_writes1)); | |
| 5229 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 5230 data_writes2, arraysize(data_writes2)); | |
| 5231 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 5232 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 5233 | |
| 5234 TestCompletionCallback callback1; | |
| 5235 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 5236 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5237 rv = callback1.WaitForResult(); | |
| 5238 EXPECT_EQ(OK, rv); | |
| 5239 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 5240 | |
| 5241 TestCompletionCallback callback2; | |
| 5242 rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback()); | |
| 5243 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5244 rv = callback2.WaitForResult(); | |
| 5245 EXPECT_EQ(OK, rv); | |
| 5246 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 5247 | |
| 5248 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5249 ASSERT_TRUE(response != NULL); | |
| 5250 | |
| 5251 // There is no challenge info, since the identity in URL worked. | |
| 5252 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 5253 | |
| 5254 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 5255 | |
| 5256 // Empty the current queue. | |
| 5257 base::MessageLoop::current()->RunUntilIdle(); | |
| 5258 } | |
| 5259 | |
| 5260 // Test the request-challenge-retry sequence for basic auth when there is an | |
| 5261 // incorrect identity in the URL. The identity from the URL should be used only | |
| 5262 // once. | |
| 5263 TEST_P(HttpNetworkTransactionTest, WrongAuthIdentityInURL) { | |
| 5264 HttpRequestInfo request; | |
| 5265 request.method = "GET"; | |
| 5266 // Note: the URL has a username:password in it. The password "baz" is | |
| 5267 // wrong (should be "bar"). | |
| 5268 request.url = GURL("http://foo:baz@www.google.com/"); | |
| 5269 | |
| 5270 request.load_flags = LOAD_NORMAL; | |
| 5271 | |
| 5272 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 5273 scoped_ptr<HttpTransaction> trans( | |
| 5274 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5275 | |
| 5276 MockWrite data_writes1[] = { | |
| 5277 MockWrite("GET / HTTP/1.1\r\n" | |
| 5278 "Host: www.google.com\r\n" | |
| 5279 "Connection: keep-alive\r\n\r\n"), | |
| 5280 }; | |
| 5281 | |
| 5282 MockRead data_reads1[] = { | |
| 5283 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 5284 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 5285 MockRead("Content-Length: 10\r\n\r\n"), | |
| 5286 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 5287 }; | |
| 5288 | |
| 5289 // After the challenge above, the transaction will be restarted using the | |
| 5290 // identity from the url (foo, baz) to answer the challenge. | |
| 5291 MockWrite data_writes2[] = { | |
| 5292 MockWrite("GET / HTTP/1.1\r\n" | |
| 5293 "Host: www.google.com\r\n" | |
| 5294 "Connection: keep-alive\r\n" | |
| 5295 "Authorization: Basic Zm9vOmJheg==\r\n\r\n"), | |
| 5296 }; | |
| 5297 | |
| 5298 MockRead data_reads2[] = { | |
| 5299 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 5300 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 5301 MockRead("Content-Length: 10\r\n\r\n"), | |
| 5302 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 5303 }; | |
| 5304 | |
| 5305 // After the challenge above, the transaction will be restarted using the | |
| 5306 // identity supplied by the user (foo, bar) to answer the challenge. | |
| 5307 MockWrite data_writes3[] = { | |
| 5308 MockWrite("GET / HTTP/1.1\r\n" | |
| 5309 "Host: www.google.com\r\n" | |
| 5310 "Connection: keep-alive\r\n" | |
| 5311 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 5312 }; | |
| 5313 | |
| 5314 MockRead data_reads3[] = { | |
| 5315 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5316 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5317 MockRead(SYNCHRONOUS, OK), | |
| 5318 }; | |
| 5319 | |
| 5320 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 5321 data_writes1, arraysize(data_writes1)); | |
| 5322 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 5323 data_writes2, arraysize(data_writes2)); | |
| 5324 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
| 5325 data_writes3, arraysize(data_writes3)); | |
| 5326 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 5327 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 5328 session_deps_.socket_factory->AddSocketDataProvider(&data3); | |
| 5329 | |
| 5330 TestCompletionCallback callback1; | |
| 5331 | |
| 5332 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 5333 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5334 | |
| 5335 rv = callback1.WaitForResult(); | |
| 5336 EXPECT_EQ(OK, rv); | |
| 5337 | |
| 5338 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 5339 TestCompletionCallback callback2; | |
| 5340 rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback()); | |
| 5341 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5342 rv = callback2.WaitForResult(); | |
| 5343 EXPECT_EQ(OK, rv); | |
| 5344 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 5345 | |
| 5346 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5347 ASSERT_TRUE(response != NULL); | |
| 5348 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 5349 | |
| 5350 TestCompletionCallback callback3; | |
| 5351 rv = trans->RestartWithAuth( | |
| 5352 AuthCredentials(kFoo, kBar), callback3.callback()); | |
| 5353 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5354 rv = callback3.WaitForResult(); | |
| 5355 EXPECT_EQ(OK, rv); | |
| 5356 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 5357 | |
| 5358 response = trans->GetResponseInfo(); | |
| 5359 ASSERT_TRUE(response != NULL); | |
| 5360 | |
| 5361 // There is no challenge info, since the identity worked. | |
| 5362 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 5363 | |
| 5364 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 5365 | |
| 5366 // Empty the current queue. | |
| 5367 base::MessageLoop::current()->RunUntilIdle(); | |
| 5368 } | |
| 5369 | |
| 5370 | |
| 5371 // Test the request-challenge-retry sequence for basic auth when there is a | |
| 5372 // correct identity in the URL, but its use is being suppressed. The identity | |
| 5373 // from the URL should never be used. | |
| 5374 TEST_P(HttpNetworkTransactionTest, AuthIdentityInURLSuppressed) { | |
| 5375 HttpRequestInfo request; | |
| 5376 request.method = "GET"; | |
| 5377 request.url = GURL("http://foo:bar@www.google.com/"); | |
| 5378 request.load_flags = LOAD_DO_NOT_USE_EMBEDDED_IDENTITY; | |
| 5379 | |
| 5380 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 5381 scoped_ptr<HttpTransaction> trans( | |
| 5382 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5383 | |
| 5384 MockWrite data_writes1[] = { | |
| 5385 MockWrite("GET / HTTP/1.1\r\n" | |
| 5386 "Host: www.google.com\r\n" | |
| 5387 "Connection: keep-alive\r\n\r\n"), | |
| 5388 }; | |
| 5389 | |
| 5390 MockRead data_reads1[] = { | |
| 5391 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 5392 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 5393 MockRead("Content-Length: 10\r\n\r\n"), | |
| 5394 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 5395 }; | |
| 5396 | |
| 5397 // After the challenge above, the transaction will be restarted using the | |
| 5398 // identity supplied by the user, not the one in the URL, to answer the | |
| 5399 // challenge. | |
| 5400 MockWrite data_writes3[] = { | |
| 5401 MockWrite("GET / HTTP/1.1\r\n" | |
| 5402 "Host: www.google.com\r\n" | |
| 5403 "Connection: keep-alive\r\n" | |
| 5404 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 5405 }; | |
| 5406 | |
| 5407 MockRead data_reads3[] = { | |
| 5408 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5409 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5410 MockRead(SYNCHRONOUS, OK), | |
| 5411 }; | |
| 5412 | |
| 5413 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 5414 data_writes1, arraysize(data_writes1)); | |
| 5415 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
| 5416 data_writes3, arraysize(data_writes3)); | |
| 5417 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 5418 session_deps_.socket_factory->AddSocketDataProvider(&data3); | |
| 5419 | |
| 5420 TestCompletionCallback callback1; | |
| 5421 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 5422 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5423 rv = callback1.WaitForResult(); | |
| 5424 EXPECT_EQ(OK, rv); | |
| 5425 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 5426 | |
| 5427 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5428 ASSERT_TRUE(response != NULL); | |
| 5429 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 5430 | |
| 5431 TestCompletionCallback callback3; | |
| 5432 rv = trans->RestartWithAuth( | |
| 5433 AuthCredentials(kFoo, kBar), callback3.callback()); | |
| 5434 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5435 rv = callback3.WaitForResult(); | |
| 5436 EXPECT_EQ(OK, rv); | |
| 5437 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 5438 | |
| 5439 response = trans->GetResponseInfo(); | |
| 5440 ASSERT_TRUE(response != NULL); | |
| 5441 | |
| 5442 // There is no challenge info, since the identity worked. | |
| 5443 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 5444 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 5445 | |
| 5446 // Empty the current queue. | |
| 5447 base::MessageLoop::current()->RunUntilIdle(); | |
| 5448 } | |
| 5449 | |
| 5450 // Test that previously tried username/passwords for a realm get re-used. | |
| 5451 TEST_P(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) { | |
| 5452 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 5453 | |
| 5454 // Transaction 1: authenticate (foo, bar) on MyRealm1 | |
| 5455 { | |
| 5456 HttpRequestInfo request; | |
| 5457 request.method = "GET"; | |
| 5458 request.url = GURL("http://www.google.com/x/y/z"); | |
| 5459 request.load_flags = 0; | |
| 5460 | |
| 5461 scoped_ptr<HttpTransaction> trans( | |
| 5462 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5463 | |
| 5464 MockWrite data_writes1[] = { | |
| 5465 MockWrite("GET /x/y/z HTTP/1.1\r\n" | |
| 5466 "Host: www.google.com\r\n" | |
| 5467 "Connection: keep-alive\r\n\r\n"), | |
| 5468 }; | |
| 5469 | |
| 5470 MockRead data_reads1[] = { | |
| 5471 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 5472 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 5473 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 5474 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 5475 }; | |
| 5476 | |
| 5477 // Resend with authorization (username=foo, password=bar) | |
| 5478 MockWrite data_writes2[] = { | |
| 5479 MockWrite("GET /x/y/z HTTP/1.1\r\n" | |
| 5480 "Host: www.google.com\r\n" | |
| 5481 "Connection: keep-alive\r\n" | |
| 5482 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 5483 }; | |
| 5484 | |
| 5485 // Sever accepts the authorization. | |
| 5486 MockRead data_reads2[] = { | |
| 5487 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5488 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5489 MockRead(SYNCHRONOUS, OK), | |
| 5490 }; | |
| 5491 | |
| 5492 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 5493 data_writes1, arraysize(data_writes1)); | |
| 5494 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 5495 data_writes2, arraysize(data_writes2)); | |
| 5496 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 5497 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 5498 | |
| 5499 TestCompletionCallback callback1; | |
| 5500 | |
| 5501 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 5502 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5503 | |
| 5504 rv = callback1.WaitForResult(); | |
| 5505 EXPECT_EQ(OK, rv); | |
| 5506 | |
| 5507 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5508 ASSERT_TRUE(response != NULL); | |
| 5509 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 5510 | |
| 5511 TestCompletionCallback callback2; | |
| 5512 | |
| 5513 rv = trans->RestartWithAuth( | |
| 5514 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 5515 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5516 | |
| 5517 rv = callback2.WaitForResult(); | |
| 5518 EXPECT_EQ(OK, rv); | |
| 5519 | |
| 5520 response = trans->GetResponseInfo(); | |
| 5521 ASSERT_TRUE(response != NULL); | |
| 5522 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 5523 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 5524 } | |
| 5525 | |
| 5526 // ------------------------------------------------------------------------ | |
| 5527 | |
| 5528 // Transaction 2: authenticate (foo2, bar2) on MyRealm2 | |
| 5529 { | |
| 5530 HttpRequestInfo request; | |
| 5531 request.method = "GET"; | |
| 5532 // Note that Transaction 1 was at /x/y/z, so this is in the same | |
| 5533 // protection space as MyRealm1. | |
| 5534 request.url = GURL("http://www.google.com/x/y/a/b"); | |
| 5535 request.load_flags = 0; | |
| 5536 | |
| 5537 scoped_ptr<HttpTransaction> trans( | |
| 5538 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5539 | |
| 5540 MockWrite data_writes1[] = { | |
| 5541 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" | |
| 5542 "Host: www.google.com\r\n" | |
| 5543 "Connection: keep-alive\r\n" | |
| 5544 // Send preemptive authorization for MyRealm1 | |
| 5545 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 5546 }; | |
| 5547 | |
| 5548 // The server didn't like the preemptive authorization, and | |
| 5549 // challenges us for a different realm (MyRealm2). | |
| 5550 MockRead data_reads1[] = { | |
| 5551 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 5552 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"), | |
| 5553 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 5554 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 5555 }; | |
| 5556 | |
| 5557 // Resend with authorization for MyRealm2 (username=foo2, password=bar2) | |
| 5558 MockWrite data_writes2[] = { | |
| 5559 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" | |
| 5560 "Host: www.google.com\r\n" | |
| 5561 "Connection: keep-alive\r\n" | |
| 5562 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), | |
| 5563 }; | |
| 5564 | |
| 5565 // Sever accepts the authorization. | |
| 5566 MockRead data_reads2[] = { | |
| 5567 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5568 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5569 MockRead(SYNCHRONOUS, OK), | |
| 5570 }; | |
| 5571 | |
| 5572 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 5573 data_writes1, arraysize(data_writes1)); | |
| 5574 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 5575 data_writes2, arraysize(data_writes2)); | |
| 5576 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 5577 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 5578 | |
| 5579 TestCompletionCallback callback1; | |
| 5580 | |
| 5581 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 5582 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5583 | |
| 5584 rv = callback1.WaitForResult(); | |
| 5585 EXPECT_EQ(OK, rv); | |
| 5586 | |
| 5587 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5588 ASSERT_TRUE(response != NULL); | |
| 5589 ASSERT_TRUE(response->auth_challenge.get()); | |
| 5590 EXPECT_FALSE(response->auth_challenge->is_proxy); | |
| 5591 EXPECT_EQ("www.google.com:80", | |
| 5592 response->auth_challenge->challenger.ToString()); | |
| 5593 EXPECT_EQ("MyRealm2", response->auth_challenge->realm); | |
| 5594 EXPECT_EQ("basic", response->auth_challenge->scheme); | |
| 5595 | |
| 5596 TestCompletionCallback callback2; | |
| 5597 | |
| 5598 rv = trans->RestartWithAuth( | |
| 5599 AuthCredentials(kFoo2, kBar2), callback2.callback()); | |
| 5600 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5601 | |
| 5602 rv = callback2.WaitForResult(); | |
| 5603 EXPECT_EQ(OK, rv); | |
| 5604 | |
| 5605 response = trans->GetResponseInfo(); | |
| 5606 ASSERT_TRUE(response != NULL); | |
| 5607 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 5608 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 5609 } | |
| 5610 | |
| 5611 // ------------------------------------------------------------------------ | |
| 5612 | |
| 5613 // Transaction 3: Resend a request in MyRealm's protection space -- | |
| 5614 // succeed with preemptive authorization. | |
| 5615 { | |
| 5616 HttpRequestInfo request; | |
| 5617 request.method = "GET"; | |
| 5618 request.url = GURL("http://www.google.com/x/y/z2"); | |
| 5619 request.load_flags = 0; | |
| 5620 | |
| 5621 scoped_ptr<HttpTransaction> trans( | |
| 5622 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5623 | |
| 5624 MockWrite data_writes1[] = { | |
| 5625 MockWrite("GET /x/y/z2 HTTP/1.1\r\n" | |
| 5626 "Host: www.google.com\r\n" | |
| 5627 "Connection: keep-alive\r\n" | |
| 5628 // The authorization for MyRealm1 gets sent preemptively | |
| 5629 // (since the url is in the same protection space) | |
| 5630 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 5631 }; | |
| 5632 | |
| 5633 // Sever accepts the preemptive authorization | |
| 5634 MockRead data_reads1[] = { | |
| 5635 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5636 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5637 MockRead(SYNCHRONOUS, OK), | |
| 5638 }; | |
| 5639 | |
| 5640 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 5641 data_writes1, arraysize(data_writes1)); | |
| 5642 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 5643 | |
| 5644 TestCompletionCallback callback1; | |
| 5645 | |
| 5646 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 5647 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5648 | |
| 5649 rv = callback1.WaitForResult(); | |
| 5650 EXPECT_EQ(OK, rv); | |
| 5651 | |
| 5652 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5653 ASSERT_TRUE(response != NULL); | |
| 5654 | |
| 5655 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 5656 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 5657 } | |
| 5658 | |
| 5659 // ------------------------------------------------------------------------ | |
| 5660 | |
| 5661 // Transaction 4: request another URL in MyRealm (however the | |
| 5662 // url is not known to belong to the protection space, so no pre-auth). | |
| 5663 { | |
| 5664 HttpRequestInfo request; | |
| 5665 request.method = "GET"; | |
| 5666 request.url = GURL("http://www.google.com/x/1"); | |
| 5667 request.load_flags = 0; | |
| 5668 | |
| 5669 scoped_ptr<HttpTransaction> trans( | |
| 5670 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5671 | |
| 5672 MockWrite data_writes1[] = { | |
| 5673 MockWrite("GET /x/1 HTTP/1.1\r\n" | |
| 5674 "Host: www.google.com\r\n" | |
| 5675 "Connection: keep-alive\r\n\r\n"), | |
| 5676 }; | |
| 5677 | |
| 5678 MockRead data_reads1[] = { | |
| 5679 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 5680 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 5681 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 5682 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 5683 }; | |
| 5684 | |
| 5685 // Resend with authorization from MyRealm's cache. | |
| 5686 MockWrite data_writes2[] = { | |
| 5687 MockWrite("GET /x/1 HTTP/1.1\r\n" | |
| 5688 "Host: www.google.com\r\n" | |
| 5689 "Connection: keep-alive\r\n" | |
| 5690 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 5691 }; | |
| 5692 | |
| 5693 // Sever accepts the authorization. | |
| 5694 MockRead data_reads2[] = { | |
| 5695 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5696 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5697 MockRead(SYNCHRONOUS, OK), | |
| 5698 }; | |
| 5699 | |
| 5700 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 5701 data_writes1, arraysize(data_writes1)); | |
| 5702 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 5703 data_writes2, arraysize(data_writes2)); | |
| 5704 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 5705 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 5706 | |
| 5707 TestCompletionCallback callback1; | |
| 5708 | |
| 5709 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 5710 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5711 | |
| 5712 rv = callback1.WaitForResult(); | |
| 5713 EXPECT_EQ(OK, rv); | |
| 5714 | |
| 5715 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 5716 TestCompletionCallback callback2; | |
| 5717 rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback()); | |
| 5718 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5719 rv = callback2.WaitForResult(); | |
| 5720 EXPECT_EQ(OK, rv); | |
| 5721 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 5722 | |
| 5723 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5724 ASSERT_TRUE(response != NULL); | |
| 5725 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 5726 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 5727 } | |
| 5728 | |
| 5729 // ------------------------------------------------------------------------ | |
| 5730 | |
| 5731 // Transaction 5: request a URL in MyRealm, but the server rejects the | |
| 5732 // cached identity. Should invalidate and re-prompt. | |
| 5733 { | |
| 5734 HttpRequestInfo request; | |
| 5735 request.method = "GET"; | |
| 5736 request.url = GURL("http://www.google.com/p/q/t"); | |
| 5737 request.load_flags = 0; | |
| 5738 | |
| 5739 scoped_ptr<HttpTransaction> trans( | |
| 5740 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5741 | |
| 5742 MockWrite data_writes1[] = { | |
| 5743 MockWrite("GET /p/q/t HTTP/1.1\r\n" | |
| 5744 "Host: www.google.com\r\n" | |
| 5745 "Connection: keep-alive\r\n\r\n"), | |
| 5746 }; | |
| 5747 | |
| 5748 MockRead data_reads1[] = { | |
| 5749 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 5750 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 5751 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 5752 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 5753 }; | |
| 5754 | |
| 5755 // Resend with authorization from cache for MyRealm. | |
| 5756 MockWrite data_writes2[] = { | |
| 5757 MockWrite("GET /p/q/t HTTP/1.1\r\n" | |
| 5758 "Host: www.google.com\r\n" | |
| 5759 "Connection: keep-alive\r\n" | |
| 5760 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 5761 }; | |
| 5762 | |
| 5763 // Sever rejects the authorization. | |
| 5764 MockRead data_reads2[] = { | |
| 5765 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 5766 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 5767 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 5768 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 5769 }; | |
| 5770 | |
| 5771 // At this point we should prompt for new credentials for MyRealm. | |
| 5772 // Restart with username=foo3, password=foo4. | |
| 5773 MockWrite data_writes3[] = { | |
| 5774 MockWrite("GET /p/q/t HTTP/1.1\r\n" | |
| 5775 "Host: www.google.com\r\n" | |
| 5776 "Connection: keep-alive\r\n" | |
| 5777 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"), | |
| 5778 }; | |
| 5779 | |
| 5780 // Sever accepts the authorization. | |
| 5781 MockRead data_reads3[] = { | |
| 5782 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5783 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5784 MockRead(SYNCHRONOUS, OK), | |
| 5785 }; | |
| 5786 | |
| 5787 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 5788 data_writes1, arraysize(data_writes1)); | |
| 5789 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 5790 data_writes2, arraysize(data_writes2)); | |
| 5791 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
| 5792 data_writes3, arraysize(data_writes3)); | |
| 5793 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 5794 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 5795 session_deps_.socket_factory->AddSocketDataProvider(&data3); | |
| 5796 | |
| 5797 TestCompletionCallback callback1; | |
| 5798 | |
| 5799 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 5800 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5801 | |
| 5802 rv = callback1.WaitForResult(); | |
| 5803 EXPECT_EQ(OK, rv); | |
| 5804 | |
| 5805 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 5806 TestCompletionCallback callback2; | |
| 5807 rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback()); | |
| 5808 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5809 rv = callback2.WaitForResult(); | |
| 5810 EXPECT_EQ(OK, rv); | |
| 5811 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 5812 | |
| 5813 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5814 ASSERT_TRUE(response != NULL); | |
| 5815 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 5816 | |
| 5817 TestCompletionCallback callback3; | |
| 5818 | |
| 5819 rv = trans->RestartWithAuth( | |
| 5820 AuthCredentials(kFoo3, kBar3), callback3.callback()); | |
| 5821 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5822 | |
| 5823 rv = callback3.WaitForResult(); | |
| 5824 EXPECT_EQ(OK, rv); | |
| 5825 | |
| 5826 response = trans->GetResponseInfo(); | |
| 5827 ASSERT_TRUE(response != NULL); | |
| 5828 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 5829 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 5830 } | |
| 5831 } | |
| 5832 | |
| 5833 // Tests that nonce count increments when multiple auth attempts | |
| 5834 // are started with the same nonce. | |
| 5835 TEST_P(HttpNetworkTransactionTest, DigestPreAuthNonceCount) { | |
| 5836 HttpAuthHandlerDigest::Factory* digest_factory = | |
| 5837 new HttpAuthHandlerDigest::Factory(); | |
| 5838 HttpAuthHandlerDigest::FixedNonceGenerator* nonce_generator = | |
| 5839 new HttpAuthHandlerDigest::FixedNonceGenerator("0123456789abcdef"); | |
| 5840 digest_factory->set_nonce_generator(nonce_generator); | |
| 5841 session_deps_.http_auth_handler_factory.reset(digest_factory); | |
| 5842 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 5843 | |
| 5844 // Transaction 1: authenticate (foo, bar) on MyRealm1 | |
| 5845 { | |
| 5846 HttpRequestInfo request; | |
| 5847 request.method = "GET"; | |
| 5848 request.url = GURL("http://www.google.com/x/y/z"); | |
| 5849 request.load_flags = 0; | |
| 5850 | |
| 5851 scoped_ptr<HttpTransaction> trans( | |
| 5852 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5853 | |
| 5854 MockWrite data_writes1[] = { | |
| 5855 MockWrite("GET /x/y/z HTTP/1.1\r\n" | |
| 5856 "Host: www.google.com\r\n" | |
| 5857 "Connection: keep-alive\r\n\r\n"), | |
| 5858 }; | |
| 5859 | |
| 5860 MockRead data_reads1[] = { | |
| 5861 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 5862 MockRead("WWW-Authenticate: Digest realm=\"digestive\", nonce=\"OU812\", " | |
| 5863 "algorithm=MD5, qop=\"auth\"\r\n\r\n"), | |
| 5864 MockRead(SYNCHRONOUS, OK), | |
| 5865 }; | |
| 5866 | |
| 5867 // Resend with authorization (username=foo, password=bar) | |
| 5868 MockWrite data_writes2[] = { | |
| 5869 MockWrite("GET /x/y/z HTTP/1.1\r\n" | |
| 5870 "Host: www.google.com\r\n" | |
| 5871 "Connection: keep-alive\r\n" | |
| 5872 "Authorization: Digest username=\"foo\", realm=\"digestive\", " | |
| 5873 "nonce=\"OU812\", uri=\"/x/y/z\", algorithm=MD5, " | |
| 5874 "response=\"03ffbcd30add722589c1de345d7a927f\", qop=auth, " | |
| 5875 "nc=00000001, cnonce=\"0123456789abcdef\"\r\n\r\n"), | |
| 5876 }; | |
| 5877 | |
| 5878 // Sever accepts the authorization. | |
| 5879 MockRead data_reads2[] = { | |
| 5880 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5881 MockRead(SYNCHRONOUS, OK), | |
| 5882 }; | |
| 5883 | |
| 5884 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 5885 data_writes1, arraysize(data_writes1)); | |
| 5886 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 5887 data_writes2, arraysize(data_writes2)); | |
| 5888 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 5889 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 5890 | |
| 5891 TestCompletionCallback callback1; | |
| 5892 | |
| 5893 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 5894 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5895 | |
| 5896 rv = callback1.WaitForResult(); | |
| 5897 EXPECT_EQ(OK, rv); | |
| 5898 | |
| 5899 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5900 ASSERT_TRUE(response != NULL); | |
| 5901 EXPECT_TRUE(CheckDigestServerAuth(response->auth_challenge.get())); | |
| 5902 | |
| 5903 TestCompletionCallback callback2; | |
| 5904 | |
| 5905 rv = trans->RestartWithAuth( | |
| 5906 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 5907 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5908 | |
| 5909 rv = callback2.WaitForResult(); | |
| 5910 EXPECT_EQ(OK, rv); | |
| 5911 | |
| 5912 response = trans->GetResponseInfo(); | |
| 5913 ASSERT_TRUE(response != NULL); | |
| 5914 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 5915 } | |
| 5916 | |
| 5917 // ------------------------------------------------------------------------ | |
| 5918 | |
| 5919 // Transaction 2: Request another resource in digestive's protection space. | |
| 5920 // This will preemptively add an Authorization header which should have an | |
| 5921 // "nc" value of 2 (as compared to 1 in the first use. | |
| 5922 { | |
| 5923 HttpRequestInfo request; | |
| 5924 request.method = "GET"; | |
| 5925 // Note that Transaction 1 was at /x/y/z, so this is in the same | |
| 5926 // protection space as digest. | |
| 5927 request.url = GURL("http://www.google.com/x/y/a/b"); | |
| 5928 request.load_flags = 0; | |
| 5929 | |
| 5930 scoped_ptr<HttpTransaction> trans( | |
| 5931 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5932 | |
| 5933 MockWrite data_writes1[] = { | |
| 5934 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" | |
| 5935 "Host: www.google.com\r\n" | |
| 5936 "Connection: keep-alive\r\n" | |
| 5937 "Authorization: Digest username=\"foo\", realm=\"digestive\", " | |
| 5938 "nonce=\"OU812\", uri=\"/x/y/a/b\", algorithm=MD5, " | |
| 5939 "response=\"d6f9a2c07d1c5df7b89379dca1269b35\", qop=auth, " | |
| 5940 "nc=00000002, cnonce=\"0123456789abcdef\"\r\n\r\n"), | |
| 5941 }; | |
| 5942 | |
| 5943 // Sever accepts the authorization. | |
| 5944 MockRead data_reads1[] = { | |
| 5945 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5946 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5947 MockRead(SYNCHRONOUS, OK), | |
| 5948 }; | |
| 5949 | |
| 5950 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 5951 data_writes1, arraysize(data_writes1)); | |
| 5952 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 5953 | |
| 5954 TestCompletionCallback callback1; | |
| 5955 | |
| 5956 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 5957 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5958 | |
| 5959 rv = callback1.WaitForResult(); | |
| 5960 EXPECT_EQ(OK, rv); | |
| 5961 | |
| 5962 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5963 ASSERT_TRUE(response != NULL); | |
| 5964 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 5965 } | |
| 5966 } | |
| 5967 | |
| 5968 // Test the ResetStateForRestart() private method. | |
| 5969 TEST_P(HttpNetworkTransactionTest, ResetStateForRestart) { | |
| 5970 // Create a transaction (the dependencies aren't important). | |
| 5971 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 5972 scoped_ptr<HttpNetworkTransaction> trans( | |
| 5973 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 5974 | |
| 5975 // Setup some state (which we expect ResetStateForRestart() will clear). | |
| 5976 trans->read_buf_ = new IOBuffer(15); | |
| 5977 trans->read_buf_len_ = 15; | |
| 5978 trans->request_headers_.SetHeader("Authorization", "NTLM"); | |
| 5979 | |
| 5980 // Setup state in response_ | |
| 5981 HttpResponseInfo* response = &trans->response_; | |
| 5982 response->auth_challenge = new AuthChallengeInfo(); | |
| 5983 response->ssl_info.cert_status = static_cast<CertStatus>(-1); // Nonsensical. | |
| 5984 response->response_time = base::Time::Now(); | |
| 5985 response->was_cached = true; // (Wouldn't ever actually be true...) | |
| 5986 | |
| 5987 { // Setup state for response_.vary_data | |
| 5988 HttpRequestInfo request; | |
| 5989 std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n"); | |
| 5990 std::replace(temp.begin(), temp.end(), '\n', '\0'); | |
| 5991 scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(temp)); | |
| 5992 request.extra_headers.SetHeader("Foo", "1"); | |
| 5993 request.extra_headers.SetHeader("bar", "23"); | |
| 5994 EXPECT_TRUE(response->vary_data.Init(request, *headers.get())); | |
| 5995 } | |
| 5996 | |
| 5997 // Cause the above state to be reset. | |
| 5998 trans->ResetStateForRestart(); | |
| 5999 | |
| 6000 // Verify that the state that needed to be reset, has been reset. | |
| 6001 EXPECT_TRUE(trans->read_buf_.get() == NULL); | |
| 6002 EXPECT_EQ(0, trans->read_buf_len_); | |
| 6003 EXPECT_TRUE(trans->request_headers_.IsEmpty()); | |
| 6004 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 6005 EXPECT_TRUE(response->headers.get() == NULL); | |
| 6006 EXPECT_FALSE(response->was_cached); | |
| 6007 EXPECT_EQ(0U, response->ssl_info.cert_status); | |
| 6008 EXPECT_FALSE(response->vary_data.is_valid()); | |
| 6009 } | |
| 6010 | |
| 6011 // Test HTTPS connections to a site with a bad certificate | |
| 6012 TEST_P(HttpNetworkTransactionTest, HTTPSBadCertificate) { | |
| 6013 HttpRequestInfo request; | |
| 6014 request.method = "GET"; | |
| 6015 request.url = GURL("https://www.google.com/"); | |
| 6016 request.load_flags = 0; | |
| 6017 | |
| 6018 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6019 scoped_ptr<HttpTransaction> trans( | |
| 6020 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6021 | |
| 6022 MockWrite data_writes[] = { | |
| 6023 MockWrite("GET / HTTP/1.1\r\n" | |
| 6024 "Host: www.google.com\r\n" | |
| 6025 "Connection: keep-alive\r\n\r\n"), | |
| 6026 }; | |
| 6027 | |
| 6028 MockRead data_reads[] = { | |
| 6029 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 6030 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 6031 MockRead("Content-Length: 100\r\n\r\n"), | |
| 6032 MockRead(SYNCHRONOUS, OK), | |
| 6033 }; | |
| 6034 | |
| 6035 StaticSocketDataProvider ssl_bad_certificate; | |
| 6036 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 6037 data_writes, arraysize(data_writes)); | |
| 6038 SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); | |
| 6039 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 6040 | |
| 6041 session_deps_.socket_factory->AddSocketDataProvider(&ssl_bad_certificate); | |
| 6042 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 6043 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_bad); | |
| 6044 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 6045 | |
| 6046 TestCompletionCallback callback; | |
| 6047 | |
| 6048 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6049 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6050 | |
| 6051 rv = callback.WaitForResult(); | |
| 6052 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); | |
| 6053 | |
| 6054 rv = trans->RestartIgnoringLastError(callback.callback()); | |
| 6055 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6056 | |
| 6057 rv = callback.WaitForResult(); | |
| 6058 EXPECT_EQ(OK, rv); | |
| 6059 | |
| 6060 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6061 | |
| 6062 ASSERT_TRUE(response != NULL); | |
| 6063 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 6064 } | |
| 6065 | |
| 6066 // Test HTTPS connections to a site with a bad certificate, going through a | |
| 6067 // proxy | |
| 6068 TEST_P(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) { | |
| 6069 session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); | |
| 6070 | |
| 6071 HttpRequestInfo request; | |
| 6072 request.method = "GET"; | |
| 6073 request.url = GURL("https://www.google.com/"); | |
| 6074 request.load_flags = 0; | |
| 6075 | |
| 6076 MockWrite proxy_writes[] = { | |
| 6077 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 6078 "Host: www.google.com\r\n" | |
| 6079 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 6080 }; | |
| 6081 | |
| 6082 MockRead proxy_reads[] = { | |
| 6083 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
| 6084 MockRead(SYNCHRONOUS, OK) | |
| 6085 }; | |
| 6086 | |
| 6087 MockWrite data_writes[] = { | |
| 6088 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 6089 "Host: www.google.com\r\n" | |
| 6090 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 6091 MockWrite("GET / HTTP/1.1\r\n" | |
| 6092 "Host: www.google.com\r\n" | |
| 6093 "Connection: keep-alive\r\n\r\n"), | |
| 6094 }; | |
| 6095 | |
| 6096 MockRead data_reads[] = { | |
| 6097 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
| 6098 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 6099 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 6100 MockRead("Content-Length: 100\r\n\r\n"), | |
| 6101 MockRead(SYNCHRONOUS, OK), | |
| 6102 }; | |
| 6103 | |
| 6104 StaticSocketDataProvider ssl_bad_certificate( | |
| 6105 proxy_reads, arraysize(proxy_reads), | |
| 6106 proxy_writes, arraysize(proxy_writes)); | |
| 6107 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 6108 data_writes, arraysize(data_writes)); | |
| 6109 SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); | |
| 6110 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 6111 | |
| 6112 session_deps_.socket_factory->AddSocketDataProvider(&ssl_bad_certificate); | |
| 6113 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 6114 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_bad); | |
| 6115 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 6116 | |
| 6117 TestCompletionCallback callback; | |
| 6118 | |
| 6119 for (int i = 0; i < 2; i++) { | |
| 6120 session_deps_.socket_factory->ResetNextMockIndexes(); | |
| 6121 | |
| 6122 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6123 scoped_ptr<HttpTransaction> trans( | |
| 6124 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6125 | |
| 6126 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6127 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6128 | |
| 6129 rv = callback.WaitForResult(); | |
| 6130 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); | |
| 6131 | |
| 6132 rv = trans->RestartIgnoringLastError(callback.callback()); | |
| 6133 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6134 | |
| 6135 rv = callback.WaitForResult(); | |
| 6136 EXPECT_EQ(OK, rv); | |
| 6137 | |
| 6138 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6139 | |
| 6140 ASSERT_TRUE(response != NULL); | |
| 6141 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 6142 } | |
| 6143 } | |
| 6144 | |
| 6145 | |
| 6146 // Test HTTPS connections to a site, going through an HTTPS proxy | |
| 6147 TEST_P(HttpNetworkTransactionTest, HTTPSViaHttpsProxy) { | |
| 6148 session_deps_.proxy_service.reset( | |
| 6149 ProxyService::CreateFixedFromPacResult("HTTPS proxy:70")); | |
| 6150 CapturingNetLog net_log; | |
| 6151 session_deps_.net_log = &net_log; | |
| 6152 | |
| 6153 HttpRequestInfo request; | |
| 6154 request.method = "GET"; | |
| 6155 request.url = GURL("https://www.google.com/"); | |
| 6156 request.load_flags = 0; | |
| 6157 | |
| 6158 MockWrite data_writes[] = { | |
| 6159 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 6160 "Host: www.google.com\r\n" | |
| 6161 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 6162 MockWrite("GET / HTTP/1.1\r\n" | |
| 6163 "Host: www.google.com\r\n" | |
| 6164 "Connection: keep-alive\r\n\r\n"), | |
| 6165 }; | |
| 6166 | |
| 6167 MockRead data_reads[] = { | |
| 6168 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
| 6169 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 6170 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 6171 MockRead("Content-Length: 100\r\n\r\n"), | |
| 6172 MockRead(SYNCHRONOUS, OK), | |
| 6173 }; | |
| 6174 | |
| 6175 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 6176 data_writes, arraysize(data_writes)); | |
| 6177 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
| 6178 SSLSocketDataProvider tunnel_ssl(ASYNC, OK); // SSL through the tunnel | |
| 6179 | |
| 6180 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 6181 session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl); | |
| 6182 session_deps_.socket_factory->AddSSLSocketDataProvider(&tunnel_ssl); | |
| 6183 | |
| 6184 TestCompletionCallback callback; | |
| 6185 | |
| 6186 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6187 scoped_ptr<HttpTransaction> trans( | |
| 6188 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6189 | |
| 6190 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6191 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6192 | |
| 6193 rv = callback.WaitForResult(); | |
| 6194 EXPECT_EQ(OK, rv); | |
| 6195 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6196 | |
| 6197 ASSERT_TRUE(response != NULL); | |
| 6198 | |
| 6199 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 6200 EXPECT_EQ(200, response->headers->response_code()); | |
| 6201 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 6202 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 6203 | |
| 6204 LoadTimingInfo load_timing_info; | |
| 6205 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 6206 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 6207 CONNECT_TIMING_HAS_SSL_TIMES); | |
| 6208 } | |
| 6209 | |
| 6210 // Test an HTTPS Proxy's ability to redirect a CONNECT request | |
| 6211 TEST_P(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) { | |
| 6212 session_deps_.proxy_service.reset( | |
| 6213 ProxyService::CreateFixedFromPacResult("HTTPS proxy:70")); | |
| 6214 CapturingNetLog net_log; | |
| 6215 session_deps_.net_log = &net_log; | |
| 6216 | |
| 6217 HttpRequestInfo request; | |
| 6218 request.method = "GET"; | |
| 6219 request.url = GURL("https://www.google.com/"); | |
| 6220 request.load_flags = 0; | |
| 6221 | |
| 6222 MockWrite data_writes[] = { | |
| 6223 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 6224 "Host: www.google.com\r\n" | |
| 6225 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 6226 }; | |
| 6227 | |
| 6228 MockRead data_reads[] = { | |
| 6229 MockRead("HTTP/1.1 302 Redirect\r\n"), | |
| 6230 MockRead("Location: http://login.example.com/\r\n"), | |
| 6231 MockRead("Content-Length: 0\r\n\r\n"), | |
| 6232 MockRead(SYNCHRONOUS, OK), | |
| 6233 }; | |
| 6234 | |
| 6235 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 6236 data_writes, arraysize(data_writes)); | |
| 6237 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
| 6238 | |
| 6239 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 6240 session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl); | |
| 6241 | |
| 6242 TestCompletionCallback callback; | |
| 6243 | |
| 6244 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6245 scoped_ptr<HttpTransaction> trans( | |
| 6246 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6247 | |
| 6248 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6249 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6250 | |
| 6251 rv = callback.WaitForResult(); | |
| 6252 EXPECT_EQ(OK, rv); | |
| 6253 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6254 | |
| 6255 ASSERT_TRUE(response != NULL); | |
| 6256 | |
| 6257 EXPECT_EQ(302, response->headers->response_code()); | |
| 6258 std::string url; | |
| 6259 EXPECT_TRUE(response->headers->IsRedirect(&url)); | |
| 6260 EXPECT_EQ("http://login.example.com/", url); | |
| 6261 | |
| 6262 // In the case of redirects from proxies, HttpNetworkTransaction returns | |
| 6263 // timing for the proxy connection instead of the connection to the host, | |
| 6264 // and no send / receive times. | |
| 6265 // See HttpNetworkTransaction::OnHttpsProxyTunnelResponse. | |
| 6266 LoadTimingInfo load_timing_info; | |
| 6267 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 6268 | |
| 6269 EXPECT_FALSE(load_timing_info.socket_reused); | |
| 6270 EXPECT_NE(net::NetLog::Source::kInvalidId, load_timing_info.socket_log_id); | |
| 6271 | |
| 6272 EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null()); | |
| 6273 EXPECT_LE(load_timing_info.proxy_resolve_start, | |
| 6274 load_timing_info.proxy_resolve_end); | |
| 6275 EXPECT_LE(load_timing_info.proxy_resolve_end, | |
| 6276 load_timing_info.connect_timing.connect_start); | |
| 6277 ExpectConnectTimingHasTimes( | |
| 6278 load_timing_info.connect_timing, | |
| 6279 CONNECT_TIMING_HAS_DNS_TIMES | CONNECT_TIMING_HAS_SSL_TIMES); | |
| 6280 | |
| 6281 EXPECT_TRUE(load_timing_info.send_start.is_null()); | |
| 6282 EXPECT_TRUE(load_timing_info.send_end.is_null()); | |
| 6283 EXPECT_TRUE(load_timing_info.receive_headers_end.is_null()); | |
| 6284 } | |
| 6285 | |
| 6286 // Test an HTTPS (SPDY) Proxy's ability to redirect a CONNECT request | |
| 6287 TEST_P(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) { | |
| 6288 session_deps_.proxy_service.reset( | |
| 6289 ProxyService::CreateFixed("https://proxy:70")); | |
| 6290 | |
| 6291 HttpRequestInfo request; | |
| 6292 request.method = "GET"; | |
| 6293 request.url = GURL("https://www.google.com/"); | |
| 6294 request.load_flags = 0; | |
| 6295 | |
| 6296 scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect( | |
| 6297 NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); | |
| 6298 scoped_ptr<SpdyFrame> goaway( | |
| 6299 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 6300 MockWrite data_writes[] = { | |
| 6301 CreateMockWrite(*conn.get(), 0, SYNCHRONOUS), | |
| 6302 CreateMockWrite(*goaway.get(), 3, SYNCHRONOUS), | |
| 6303 }; | |
| 6304 | |
| 6305 static const char* const kExtraHeaders[] = { | |
| 6306 "location", | |
| 6307 "http://login.example.com/", | |
| 6308 }; | |
| 6309 scoped_ptr<SpdyFrame> resp( | |
| 6310 spdy_util_.ConstructSpdySynReplyError("302 Redirect", kExtraHeaders, | |
| 6311 arraysize(kExtraHeaders)/2, 1)); | |
| 6312 MockRead data_reads[] = { | |
| 6313 CreateMockRead(*resp.get(), 1, SYNCHRONOUS), | |
| 6314 MockRead(ASYNC, 0, 2), // EOF | |
| 6315 }; | |
| 6316 | |
| 6317 DelayedSocketData data( | |
| 6318 1, // wait for one write to finish before reading. | |
| 6319 data_reads, arraysize(data_reads), | |
| 6320 data_writes, arraysize(data_writes)); | |
| 6321 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
| 6322 proxy_ssl.SetNextProto(GetParam()); | |
| 6323 | |
| 6324 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 6325 session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl); | |
| 6326 | |
| 6327 TestCompletionCallback callback; | |
| 6328 | |
| 6329 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6330 scoped_ptr<HttpTransaction> trans( | |
| 6331 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6332 | |
| 6333 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6334 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6335 | |
| 6336 rv = callback.WaitForResult(); | |
| 6337 EXPECT_EQ(OK, rv); | |
| 6338 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6339 | |
| 6340 ASSERT_TRUE(response != NULL); | |
| 6341 | |
| 6342 EXPECT_EQ(302, response->headers->response_code()); | |
| 6343 std::string url; | |
| 6344 EXPECT_TRUE(response->headers->IsRedirect(&url)); | |
| 6345 EXPECT_EQ("http://login.example.com/", url); | |
| 6346 } | |
| 6347 | |
| 6348 // Test that an HTTPS proxy's response to a CONNECT request is filtered. | |
| 6349 TEST_P(HttpNetworkTransactionTest, | |
| 6350 ErrorResponseToHttpsConnectViaHttpsProxy) { | |
| 6351 session_deps_.proxy_service.reset( | |
| 6352 ProxyService::CreateFixed("https://proxy:70")); | |
| 6353 | |
| 6354 HttpRequestInfo request; | |
| 6355 request.method = "GET"; | |
| 6356 request.url = GURL("https://www.google.com/"); | |
| 6357 request.load_flags = 0; | |
| 6358 | |
| 6359 MockWrite data_writes[] = { | |
| 6360 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 6361 "Host: www.google.com\r\n" | |
| 6362 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 6363 }; | |
| 6364 | |
| 6365 MockRead data_reads[] = { | |
| 6366 MockRead("HTTP/1.1 404 Not Found\r\n"), | |
| 6367 MockRead("Content-Length: 23\r\n\r\n"), | |
| 6368 MockRead("The host does not exist"), | |
| 6369 MockRead(SYNCHRONOUS, OK), | |
| 6370 }; | |
| 6371 | |
| 6372 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 6373 data_writes, arraysize(data_writes)); | |
| 6374 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
| 6375 | |
| 6376 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 6377 session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl); | |
| 6378 | |
| 6379 TestCompletionCallback callback; | |
| 6380 | |
| 6381 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6382 scoped_ptr<HttpTransaction> trans( | |
| 6383 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6384 | |
| 6385 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6386 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6387 | |
| 6388 rv = callback.WaitForResult(); | |
| 6389 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
| 6390 | |
| 6391 // TODO(ttuttle): Anything else to check here? | |
| 6392 } | |
| 6393 | |
| 6394 // Test that a SPDY proxy's response to a CONNECT request is filtered. | |
| 6395 TEST_P(HttpNetworkTransactionTest, | |
| 6396 ErrorResponseToHttpsConnectViaSpdyProxy) { | |
| 6397 session_deps_.proxy_service.reset( | |
| 6398 ProxyService::CreateFixed("https://proxy:70")); | |
| 6399 | |
| 6400 HttpRequestInfo request; | |
| 6401 request.method = "GET"; | |
| 6402 request.url = GURL("https://www.google.com/"); | |
| 6403 request.load_flags = 0; | |
| 6404 | |
| 6405 scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect( | |
| 6406 NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); | |
| 6407 scoped_ptr<SpdyFrame> rst( | |
| 6408 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 6409 MockWrite data_writes[] = { | |
| 6410 CreateMockWrite(*conn.get(), 0, SYNCHRONOUS), | |
| 6411 CreateMockWrite(*rst.get(), 3, SYNCHRONOUS), | |
| 6412 }; | |
| 6413 | |
| 6414 static const char* const kExtraHeaders[] = { | |
| 6415 "location", | |
| 6416 "http://login.example.com/", | |
| 6417 }; | |
| 6418 scoped_ptr<SpdyFrame> resp( | |
| 6419 spdy_util_.ConstructSpdySynReplyError("404 Not Found", kExtraHeaders, | |
| 6420 arraysize(kExtraHeaders)/2, 1)); | |
| 6421 scoped_ptr<SpdyFrame> body( | |
| 6422 spdy_util_.ConstructSpdyBodyFrame( | |
| 6423 1, "The host does not exist", 23, true)); | |
| 6424 MockRead data_reads[] = { | |
| 6425 CreateMockRead(*resp.get(), 1, SYNCHRONOUS), | |
| 6426 CreateMockRead(*body.get(), 2, SYNCHRONOUS), | |
| 6427 MockRead(ASYNC, 0, 4), // EOF | |
| 6428 }; | |
| 6429 | |
| 6430 DelayedSocketData data( | |
| 6431 1, // wait for one write to finish before reading. | |
| 6432 data_reads, arraysize(data_reads), | |
| 6433 data_writes, arraysize(data_writes)); | |
| 6434 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
| 6435 proxy_ssl.SetNextProto(GetParam()); | |
| 6436 | |
| 6437 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 6438 session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl); | |
| 6439 | |
| 6440 TestCompletionCallback callback; | |
| 6441 | |
| 6442 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6443 scoped_ptr<HttpTransaction> trans( | |
| 6444 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6445 | |
| 6446 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6447 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6448 | |
| 6449 rv = callback.WaitForResult(); | |
| 6450 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
| 6451 | |
| 6452 // TODO(ttuttle): Anything else to check here? | |
| 6453 } | |
| 6454 | |
| 6455 // Test the request-challenge-retry sequence for basic auth, through | |
| 6456 // a SPDY proxy over a single SPDY session. | |
| 6457 TEST_P(HttpNetworkTransactionTest, BasicAuthSpdyProxy) { | |
| 6458 HttpRequestInfo request; | |
| 6459 request.method = "GET"; | |
| 6460 request.url = GURL("https://www.google.com/"); | |
| 6461 // when the no authentication data flag is set. | |
| 6462 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
| 6463 | |
| 6464 // Configure against https proxy server "myproxy:70". | |
| 6465 session_deps_.proxy_service.reset( | |
| 6466 ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")); | |
| 6467 CapturingBoundNetLog log; | |
| 6468 session_deps_.net_log = log.bound().net_log(); | |
| 6469 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6470 | |
| 6471 // Since we have proxy, should try to establish tunnel. | |
| 6472 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect( | |
| 6473 NULL, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); | |
| 6474 scoped_ptr<SpdyFrame> rst( | |
| 6475 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
| 6476 | |
| 6477 // After calling trans->RestartWithAuth(), this is the request we should | |
| 6478 // be issuing -- the final header line contains the credentials. | |
| 6479 const char* const kAuthCredentials[] = { | |
| 6480 "proxy-authorization", "Basic Zm9vOmJhcg==", | |
| 6481 }; | |
| 6482 scoped_ptr<SpdyFrame> connect2(spdy_util_.ConstructSpdyConnect( | |
| 6483 kAuthCredentials, arraysize(kAuthCredentials) / 2, 3, LOWEST, | |
| 6484 HostPortPair("www.google.com", 443))); | |
| 6485 // fetch https://www.google.com/ via HTTP | |
| 6486 const char get[] = "GET / HTTP/1.1\r\n" | |
| 6487 "Host: www.google.com\r\n" | |
| 6488 "Connection: keep-alive\r\n\r\n"; | |
| 6489 scoped_ptr<SpdyFrame> wrapped_get( | |
| 6490 spdy_util_.ConstructSpdyBodyFrame(3, get, strlen(get), false)); | |
| 6491 | |
| 6492 MockWrite spdy_writes[] = { | |
| 6493 CreateMockWrite(*req, 1, ASYNC), | |
| 6494 CreateMockWrite(*rst, 4, ASYNC), | |
| 6495 CreateMockWrite(*connect2, 5), | |
| 6496 CreateMockWrite(*wrapped_get, 8), | |
| 6497 }; | |
| 6498 | |
| 6499 // The proxy responds to the connect with a 407, using a persistent | |
| 6500 // connection. | |
| 6501 const char kAuthStatus[] = "407"; | |
| 6502 const char* const kAuthChallenge[] = { | |
| 6503 "proxy-authenticate", "Basic realm=\"MyRealm1\"", | |
| 6504 }; | |
| 6505 scoped_ptr<SpdyFrame> conn_auth_resp(spdy_util_.ConstructSpdySynReplyError( | |
| 6506 kAuthStatus, kAuthChallenge, arraysize(kAuthChallenge) / 2, 1)); | |
| 6507 | |
| 6508 scoped_ptr<SpdyFrame> conn_resp( | |
| 6509 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 6510 const char resp[] = "HTTP/1.1 200 OK\r\n" | |
| 6511 "Content-Length: 5\r\n\r\n"; | |
| 6512 | |
| 6513 scoped_ptr<SpdyFrame> wrapped_get_resp( | |
| 6514 spdy_util_.ConstructSpdyBodyFrame(3, resp, strlen(resp), false)); | |
| 6515 scoped_ptr<SpdyFrame> wrapped_body( | |
| 6516 spdy_util_.ConstructSpdyBodyFrame(3, "hello", 5, false)); | |
| 6517 MockRead spdy_reads[] = { | |
| 6518 CreateMockRead(*conn_auth_resp, 2, ASYNC), | |
| 6519 CreateMockRead(*conn_resp, 6, ASYNC), | |
| 6520 CreateMockRead(*wrapped_get_resp, 9, ASYNC), | |
| 6521 CreateMockRead(*wrapped_body, 10, ASYNC), | |
| 6522 MockRead(ASYNC, OK, 11), // EOF. May or may not be read. | |
| 6523 }; | |
| 6524 | |
| 6525 OrderedSocketData spdy_data( | |
| 6526 spdy_reads, arraysize(spdy_reads), | |
| 6527 spdy_writes, arraysize(spdy_writes)); | |
| 6528 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 6529 // Negotiate SPDY to the proxy | |
| 6530 SSLSocketDataProvider proxy(ASYNC, OK); | |
| 6531 proxy.SetNextProto(GetParam()); | |
| 6532 session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy); | |
| 6533 // Vanilla SSL to the server | |
| 6534 SSLSocketDataProvider server(ASYNC, OK); | |
| 6535 session_deps_.socket_factory->AddSSLSocketDataProvider(&server); | |
| 6536 | |
| 6537 TestCompletionCallback callback1; | |
| 6538 | |
| 6539 scoped_ptr<HttpTransaction> trans( | |
| 6540 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6541 | |
| 6542 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 6543 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6544 | |
| 6545 rv = callback1.WaitForResult(); | |
| 6546 EXPECT_EQ(OK, rv); | |
| 6547 net::CapturingNetLog::CapturedEntryList entries; | |
| 6548 log.GetEntries(&entries); | |
| 6549 size_t pos = ExpectLogContainsSomewhere( | |
| 6550 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 6551 NetLog::PHASE_NONE); | |
| 6552 ExpectLogContainsSomewhere( | |
| 6553 entries, pos, | |
| 6554 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 6555 NetLog::PHASE_NONE); | |
| 6556 | |
| 6557 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6558 ASSERT_TRUE(response != NULL); | |
| 6559 ASSERT_FALSE(response->headers.get() == NULL); | |
| 6560 EXPECT_EQ(407, response->headers->response_code()); | |
| 6561 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 6562 EXPECT_TRUE(response->auth_challenge.get() != NULL); | |
| 6563 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 6564 | |
| 6565 TestCompletionCallback callback2; | |
| 6566 | |
| 6567 rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), | |
| 6568 callback2.callback()); | |
| 6569 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6570 | |
| 6571 rv = callback2.WaitForResult(); | |
| 6572 EXPECT_EQ(OK, rv); | |
| 6573 | |
| 6574 response = trans->GetResponseInfo(); | |
| 6575 ASSERT_TRUE(response != NULL); | |
| 6576 | |
| 6577 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 6578 EXPECT_EQ(200, response->headers->response_code()); | |
| 6579 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 6580 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 6581 | |
| 6582 // The password prompt info should not be set. | |
| 6583 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 6584 | |
| 6585 LoadTimingInfo load_timing_info; | |
| 6586 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 6587 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 6588 CONNECT_TIMING_HAS_SSL_TIMES); | |
| 6589 | |
| 6590 trans.reset(); | |
| 6591 session->CloseAllConnections(); | |
| 6592 } | |
| 6593 | |
| 6594 // Test that an explicitly trusted SPDY proxy can push a resource from an | |
| 6595 // origin that is different from that of its associated resource. | |
| 6596 TEST_P(HttpNetworkTransactionTest, CrossOriginProxyPush) { | |
| 6597 HttpRequestInfo request; | |
| 6598 HttpRequestInfo push_request; | |
| 6599 | |
| 6600 request.method = "GET"; | |
| 6601 request.url = GURL("http://www.google.com/"); | |
| 6602 push_request.method = "GET"; | |
| 6603 push_request.url = GURL("http://www.another-origin.com/foo.dat"); | |
| 6604 | |
| 6605 // Configure against https proxy server "myproxy:70". | |
| 6606 session_deps_.proxy_service.reset( | |
| 6607 ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70")); | |
| 6608 CapturingBoundNetLog log; | |
| 6609 session_deps_.net_log = log.bound().net_log(); | |
| 6610 | |
| 6611 // Enable cross-origin push. | |
| 6612 session_deps_.trusted_spdy_proxy = "myproxy:70"; | |
| 6613 | |
| 6614 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6615 | |
| 6616 scoped_ptr<SpdyFrame> stream1_syn( | |
| 6617 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false)); | |
| 6618 | |
| 6619 MockWrite spdy_writes[] = { | |
| 6620 CreateMockWrite(*stream1_syn, 1, ASYNC), | |
| 6621 }; | |
| 6622 | |
| 6623 scoped_ptr<SpdyFrame> | |
| 6624 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 6625 | |
| 6626 scoped_ptr<SpdyFrame> | |
| 6627 stream1_body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 6628 | |
| 6629 scoped_ptr<SpdyFrame> | |
| 6630 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
| 6631 0, | |
| 6632 2, | |
| 6633 1, | |
| 6634 "http://www.another-origin.com/foo.dat")); | |
| 6635 const char kPushedData[] = "pushed"; | |
| 6636 scoped_ptr<SpdyFrame> stream2_body( | |
| 6637 spdy_util_.ConstructSpdyBodyFrame( | |
| 6638 2, kPushedData, strlen(kPushedData), true)); | |
| 6639 | |
| 6640 MockRead spdy_reads[] = { | |
| 6641 CreateMockRead(*stream1_reply, 2, ASYNC), | |
| 6642 CreateMockRead(*stream2_syn, 3, ASYNC), | |
| 6643 CreateMockRead(*stream1_body, 4, ASYNC), | |
| 6644 CreateMockRead(*stream2_body, 5, ASYNC), | |
| 6645 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause | |
| 6646 }; | |
| 6647 | |
| 6648 OrderedSocketData spdy_data( | |
| 6649 spdy_reads, arraysize(spdy_reads), | |
| 6650 spdy_writes, arraysize(spdy_writes)); | |
| 6651 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 6652 // Negotiate SPDY to the proxy | |
| 6653 SSLSocketDataProvider proxy(ASYNC, OK); | |
| 6654 proxy.SetNextProto(GetParam()); | |
| 6655 session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy); | |
| 6656 | |
| 6657 scoped_ptr<HttpTransaction> trans( | |
| 6658 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6659 TestCompletionCallback callback; | |
| 6660 int rv = trans->Start(&request, callback.callback(), log.bound()); | |
| 6661 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6662 | |
| 6663 rv = callback.WaitForResult(); | |
| 6664 EXPECT_EQ(OK, rv); | |
| 6665 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6666 | |
| 6667 scoped_ptr<HttpTransaction> push_trans( | |
| 6668 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6669 rv = push_trans->Start(&push_request, callback.callback(), log.bound()); | |
| 6670 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6671 | |
| 6672 rv = callback.WaitForResult(); | |
| 6673 EXPECT_EQ(OK, rv); | |
| 6674 const HttpResponseInfo* push_response = push_trans->GetResponseInfo(); | |
| 6675 | |
| 6676 ASSERT_TRUE(response != NULL); | |
| 6677 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 6678 | |
| 6679 EXPECT_EQ(200, response->headers->response_code()); | |
| 6680 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 6681 | |
| 6682 std::string response_data; | |
| 6683 rv = ReadTransaction(trans.get(), &response_data); | |
| 6684 EXPECT_EQ(OK, rv); | |
| 6685 EXPECT_EQ("hello!", response_data); | |
| 6686 | |
| 6687 LoadTimingInfo load_timing_info; | |
| 6688 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 6689 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 6690 CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); | |
| 6691 | |
| 6692 // Verify the pushed stream. | |
| 6693 EXPECT_TRUE(push_response->headers.get() != NULL); | |
| 6694 EXPECT_EQ(200, push_response->headers->response_code()); | |
| 6695 | |
| 6696 rv = ReadTransaction(push_trans.get(), &response_data); | |
| 6697 EXPECT_EQ(OK, rv); | |
| 6698 EXPECT_EQ("pushed", response_data); | |
| 6699 | |
| 6700 LoadTimingInfo push_load_timing_info; | |
| 6701 EXPECT_TRUE(push_trans->GetLoadTimingInfo(&push_load_timing_info)); | |
| 6702 TestLoadTimingReusedWithPac(push_load_timing_info); | |
| 6703 // The transactions should share a socket ID, despite being for different | |
| 6704 // origins. | |
| 6705 EXPECT_EQ(load_timing_info.socket_log_id, | |
| 6706 push_load_timing_info.socket_log_id); | |
| 6707 | |
| 6708 trans.reset(); | |
| 6709 push_trans.reset(); | |
| 6710 session->CloseAllConnections(); | |
| 6711 } | |
| 6712 | |
| 6713 // Test that an explicitly trusted SPDY proxy cannot push HTTPS content. | |
| 6714 TEST_P(HttpNetworkTransactionTest, CrossOriginProxyPushCorrectness) { | |
| 6715 HttpRequestInfo request; | |
| 6716 | |
| 6717 request.method = "GET"; | |
| 6718 request.url = GURL("http://www.google.com/"); | |
| 6719 | |
| 6720 // Configure against https proxy server "myproxy:70". | |
| 6721 session_deps_.proxy_service.reset( | |
| 6722 ProxyService::CreateFixed("https://myproxy:70")); | |
| 6723 CapturingBoundNetLog log; | |
| 6724 session_deps_.net_log = log.bound().net_log(); | |
| 6725 | |
| 6726 // Enable cross-origin push. | |
| 6727 session_deps_.trusted_spdy_proxy = "myproxy:70"; | |
| 6728 | |
| 6729 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6730 | |
| 6731 scoped_ptr<SpdyFrame> stream1_syn( | |
| 6732 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false)); | |
| 6733 | |
| 6734 scoped_ptr<SpdyFrame> push_rst( | |
| 6735 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM)); | |
| 6736 | |
| 6737 MockWrite spdy_writes[] = { | |
| 6738 CreateMockWrite(*stream1_syn, 1, ASYNC), | |
| 6739 CreateMockWrite(*push_rst, 4), | |
| 6740 }; | |
| 6741 | |
| 6742 scoped_ptr<SpdyFrame> | |
| 6743 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 6744 | |
| 6745 scoped_ptr<SpdyFrame> | |
| 6746 stream1_body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 6747 | |
| 6748 scoped_ptr<SpdyFrame> | |
| 6749 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
| 6750 0, | |
| 6751 2, | |
| 6752 1, | |
| 6753 "https://www.another-origin.com/foo.dat")); | |
| 6754 | |
| 6755 MockRead spdy_reads[] = { | |
| 6756 CreateMockRead(*stream1_reply, 2, ASYNC), | |
| 6757 CreateMockRead(*stream2_syn, 3, ASYNC), | |
| 6758 CreateMockRead(*stream1_body, 5, ASYNC), | |
| 6759 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause | |
| 6760 }; | |
| 6761 | |
| 6762 OrderedSocketData spdy_data( | |
| 6763 spdy_reads, arraysize(spdy_reads), | |
| 6764 spdy_writes, arraysize(spdy_writes)); | |
| 6765 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 6766 // Negotiate SPDY to the proxy | |
| 6767 SSLSocketDataProvider proxy(ASYNC, OK); | |
| 6768 proxy.SetNextProto(GetParam()); | |
| 6769 session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy); | |
| 6770 | |
| 6771 scoped_ptr<HttpTransaction> trans( | |
| 6772 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6773 TestCompletionCallback callback; | |
| 6774 int rv = trans->Start(&request, callback.callback(), log.bound()); | |
| 6775 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6776 | |
| 6777 rv = callback.WaitForResult(); | |
| 6778 EXPECT_EQ(OK, rv); | |
| 6779 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6780 | |
| 6781 ASSERT_TRUE(response != NULL); | |
| 6782 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 6783 | |
| 6784 EXPECT_EQ(200, response->headers->response_code()); | |
| 6785 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 6786 | |
| 6787 std::string response_data; | |
| 6788 rv = ReadTransaction(trans.get(), &response_data); | |
| 6789 EXPECT_EQ(OK, rv); | |
| 6790 EXPECT_EQ("hello!", response_data); | |
| 6791 | |
| 6792 trans.reset(); | |
| 6793 session->CloseAllConnections(); | |
| 6794 } | |
| 6795 | |
| 6796 // Test HTTPS connections to a site with a bad certificate, going through an | |
| 6797 // HTTPS proxy | |
| 6798 TEST_P(HttpNetworkTransactionTest, HTTPSBadCertificateViaHttpsProxy) { | |
| 6799 session_deps_.proxy_service.reset(ProxyService::CreateFixed( | |
| 6800 "https://proxy:70")); | |
| 6801 | |
| 6802 HttpRequestInfo request; | |
| 6803 request.method = "GET"; | |
| 6804 request.url = GURL("https://www.google.com/"); | |
| 6805 request.load_flags = 0; | |
| 6806 | |
| 6807 // Attempt to fetch the URL from a server with a bad cert | |
| 6808 MockWrite bad_cert_writes[] = { | |
| 6809 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 6810 "Host: www.google.com\r\n" | |
| 6811 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 6812 }; | |
| 6813 | |
| 6814 MockRead bad_cert_reads[] = { | |
| 6815 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
| 6816 MockRead(SYNCHRONOUS, OK) | |
| 6817 }; | |
| 6818 | |
| 6819 // Attempt to fetch the URL with a good cert | |
| 6820 MockWrite good_data_writes[] = { | |
| 6821 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 6822 "Host: www.google.com\r\n" | |
| 6823 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 6824 MockWrite("GET / HTTP/1.1\r\n" | |
| 6825 "Host: www.google.com\r\n" | |
| 6826 "Connection: keep-alive\r\n\r\n"), | |
| 6827 }; | |
| 6828 | |
| 6829 MockRead good_cert_reads[] = { | |
| 6830 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
| 6831 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 6832 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 6833 MockRead("Content-Length: 100\r\n\r\n"), | |
| 6834 MockRead(SYNCHRONOUS, OK), | |
| 6835 }; | |
| 6836 | |
| 6837 StaticSocketDataProvider ssl_bad_certificate( | |
| 6838 bad_cert_reads, arraysize(bad_cert_reads), | |
| 6839 bad_cert_writes, arraysize(bad_cert_writes)); | |
| 6840 StaticSocketDataProvider data(good_cert_reads, arraysize(good_cert_reads), | |
| 6841 good_data_writes, arraysize(good_data_writes)); | |
| 6842 SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); | |
| 6843 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 6844 | |
| 6845 // SSL to the proxy, then CONNECT request, then SSL with bad certificate | |
| 6846 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 6847 session_deps_.socket_factory->AddSocketDataProvider(&ssl_bad_certificate); | |
| 6848 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_bad); | |
| 6849 | |
| 6850 // SSL to the proxy, then CONNECT request, then valid SSL certificate | |
| 6851 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 6852 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 6853 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 6854 | |
| 6855 TestCompletionCallback callback; | |
| 6856 | |
| 6857 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6858 scoped_ptr<HttpTransaction> trans( | |
| 6859 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6860 | |
| 6861 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6862 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6863 | |
| 6864 rv = callback.WaitForResult(); | |
| 6865 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); | |
| 6866 | |
| 6867 rv = trans->RestartIgnoringLastError(callback.callback()); | |
| 6868 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6869 | |
| 6870 rv = callback.WaitForResult(); | |
| 6871 EXPECT_EQ(OK, rv); | |
| 6872 | |
| 6873 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6874 | |
| 6875 ASSERT_TRUE(response != NULL); | |
| 6876 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 6877 } | |
| 6878 | |
| 6879 TEST_P(HttpNetworkTransactionTest, BuildRequest_UserAgent) { | |
| 6880 HttpRequestInfo request; | |
| 6881 request.method = "GET"; | |
| 6882 request.url = GURL("http://www.google.com/"); | |
| 6883 request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, | |
| 6884 "Chromium Ultra Awesome X Edition"); | |
| 6885 | |
| 6886 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6887 scoped_ptr<HttpTransaction> trans( | |
| 6888 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6889 | |
| 6890 MockWrite data_writes[] = { | |
| 6891 MockWrite("GET / HTTP/1.1\r\n" | |
| 6892 "Host: www.google.com\r\n" | |
| 6893 "Connection: keep-alive\r\n" | |
| 6894 "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"), | |
| 6895 }; | |
| 6896 | |
| 6897 // Lastly, the server responds with the actual content. | |
| 6898 MockRead data_reads[] = { | |
| 6899 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 6900 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 6901 MockRead("Content-Length: 100\r\n\r\n"), | |
| 6902 MockRead(SYNCHRONOUS, OK), | |
| 6903 }; | |
| 6904 | |
| 6905 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 6906 data_writes, arraysize(data_writes)); | |
| 6907 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 6908 | |
| 6909 TestCompletionCallback callback; | |
| 6910 | |
| 6911 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6912 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6913 | |
| 6914 rv = callback.WaitForResult(); | |
| 6915 EXPECT_EQ(OK, rv); | |
| 6916 } | |
| 6917 | |
| 6918 TEST_P(HttpNetworkTransactionTest, BuildRequest_UserAgentOverTunnel) { | |
| 6919 HttpRequestInfo request; | |
| 6920 request.method = "GET"; | |
| 6921 request.url = GURL("https://www.google.com/"); | |
| 6922 request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, | |
| 6923 "Chromium Ultra Awesome X Edition"); | |
| 6924 | |
| 6925 session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); | |
| 6926 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6927 scoped_ptr<HttpTransaction> trans( | |
| 6928 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6929 | |
| 6930 MockWrite data_writes[] = { | |
| 6931 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 6932 "Host: www.google.com\r\n" | |
| 6933 "Proxy-Connection: keep-alive\r\n" | |
| 6934 "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"), | |
| 6935 }; | |
| 6936 MockRead data_reads[] = { | |
| 6937 // Return an error, so the transaction stops here (this test isn't | |
| 6938 // interested in the rest). | |
| 6939 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 6940 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 6941 MockRead("Proxy-Connection: close\r\n\r\n"), | |
| 6942 }; | |
| 6943 | |
| 6944 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 6945 data_writes, arraysize(data_writes)); | |
| 6946 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 6947 | |
| 6948 TestCompletionCallback callback; | |
| 6949 | |
| 6950 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6951 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6952 | |
| 6953 rv = callback.WaitForResult(); | |
| 6954 EXPECT_EQ(OK, rv); | |
| 6955 } | |
| 6956 | |
| 6957 TEST_P(HttpNetworkTransactionTest, BuildRequest_Referer) { | |
| 6958 HttpRequestInfo request; | |
| 6959 request.method = "GET"; | |
| 6960 request.url = GURL("http://www.google.com/"); | |
| 6961 request.load_flags = 0; | |
| 6962 request.extra_headers.SetHeader(HttpRequestHeaders::kReferer, | |
| 6963 "http://the.previous.site.com/"); | |
| 6964 | |
| 6965 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 6966 scoped_ptr<HttpTransaction> trans( | |
| 6967 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 6968 | |
| 6969 MockWrite data_writes[] = { | |
| 6970 MockWrite("GET / HTTP/1.1\r\n" | |
| 6971 "Host: www.google.com\r\n" | |
| 6972 "Connection: keep-alive\r\n" | |
| 6973 "Referer: http://the.previous.site.com/\r\n\r\n"), | |
| 6974 }; | |
| 6975 | |
| 6976 // Lastly, the server responds with the actual content. | |
| 6977 MockRead data_reads[] = { | |
| 6978 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 6979 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 6980 MockRead("Content-Length: 100\r\n\r\n"), | |
| 6981 MockRead(SYNCHRONOUS, OK), | |
| 6982 }; | |
| 6983 | |
| 6984 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 6985 data_writes, arraysize(data_writes)); | |
| 6986 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 6987 | |
| 6988 TestCompletionCallback callback; | |
| 6989 | |
| 6990 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6991 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6992 | |
| 6993 rv = callback.WaitForResult(); | |
| 6994 EXPECT_EQ(OK, rv); | |
| 6995 } | |
| 6996 | |
| 6997 TEST_P(HttpNetworkTransactionTest, BuildRequest_PostContentLengthZero) { | |
| 6998 HttpRequestInfo request; | |
| 6999 request.method = "POST"; | |
| 7000 request.url = GURL("http://www.google.com/"); | |
| 7001 | |
| 7002 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7003 scoped_ptr<HttpTransaction> trans( | |
| 7004 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7005 | |
| 7006 MockWrite data_writes[] = { | |
| 7007 MockWrite("POST / HTTP/1.1\r\n" | |
| 7008 "Host: www.google.com\r\n" | |
| 7009 "Connection: keep-alive\r\n" | |
| 7010 "Content-Length: 0\r\n\r\n"), | |
| 7011 }; | |
| 7012 | |
| 7013 // Lastly, the server responds with the actual content. | |
| 7014 MockRead data_reads[] = { | |
| 7015 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7016 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 7017 MockRead("Content-Length: 100\r\n\r\n"), | |
| 7018 MockRead(SYNCHRONOUS, OK), | |
| 7019 }; | |
| 7020 | |
| 7021 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7022 data_writes, arraysize(data_writes)); | |
| 7023 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7024 | |
| 7025 TestCompletionCallback callback; | |
| 7026 | |
| 7027 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7028 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7029 | |
| 7030 rv = callback.WaitForResult(); | |
| 7031 EXPECT_EQ(OK, rv); | |
| 7032 } | |
| 7033 | |
| 7034 TEST_P(HttpNetworkTransactionTest, BuildRequest_PutContentLengthZero) { | |
| 7035 HttpRequestInfo request; | |
| 7036 request.method = "PUT"; | |
| 7037 request.url = GURL("http://www.google.com/"); | |
| 7038 | |
| 7039 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7040 scoped_ptr<HttpTransaction> trans( | |
| 7041 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7042 | |
| 7043 MockWrite data_writes[] = { | |
| 7044 MockWrite("PUT / HTTP/1.1\r\n" | |
| 7045 "Host: www.google.com\r\n" | |
| 7046 "Connection: keep-alive\r\n" | |
| 7047 "Content-Length: 0\r\n\r\n"), | |
| 7048 }; | |
| 7049 | |
| 7050 // Lastly, the server responds with the actual content. | |
| 7051 MockRead data_reads[] = { | |
| 7052 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7053 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 7054 MockRead("Content-Length: 100\r\n\r\n"), | |
| 7055 MockRead(SYNCHRONOUS, OK), | |
| 7056 }; | |
| 7057 | |
| 7058 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7059 data_writes, arraysize(data_writes)); | |
| 7060 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7061 | |
| 7062 TestCompletionCallback callback; | |
| 7063 | |
| 7064 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7065 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7066 | |
| 7067 rv = callback.WaitForResult(); | |
| 7068 EXPECT_EQ(OK, rv); | |
| 7069 } | |
| 7070 | |
| 7071 TEST_P(HttpNetworkTransactionTest, BuildRequest_HeadContentLengthZero) { | |
| 7072 HttpRequestInfo request; | |
| 7073 request.method = "HEAD"; | |
| 7074 request.url = GURL("http://www.google.com/"); | |
| 7075 | |
| 7076 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7077 scoped_ptr<HttpTransaction> trans( | |
| 7078 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7079 | |
| 7080 MockWrite data_writes[] = { | |
| 7081 MockWrite("HEAD / HTTP/1.1\r\n" | |
| 7082 "Host: www.google.com\r\n" | |
| 7083 "Connection: keep-alive\r\n" | |
| 7084 "Content-Length: 0\r\n\r\n"), | |
| 7085 }; | |
| 7086 | |
| 7087 // Lastly, the server responds with the actual content. | |
| 7088 MockRead data_reads[] = { | |
| 7089 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7090 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 7091 MockRead("Content-Length: 100\r\n\r\n"), | |
| 7092 MockRead(SYNCHRONOUS, OK), | |
| 7093 }; | |
| 7094 | |
| 7095 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7096 data_writes, arraysize(data_writes)); | |
| 7097 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7098 | |
| 7099 TestCompletionCallback callback; | |
| 7100 | |
| 7101 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7102 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7103 | |
| 7104 rv = callback.WaitForResult(); | |
| 7105 EXPECT_EQ(OK, rv); | |
| 7106 } | |
| 7107 | |
| 7108 TEST_P(HttpNetworkTransactionTest, BuildRequest_CacheControlNoCache) { | |
| 7109 HttpRequestInfo request; | |
| 7110 request.method = "GET"; | |
| 7111 request.url = GURL("http://www.google.com/"); | |
| 7112 request.load_flags = LOAD_BYPASS_CACHE; | |
| 7113 | |
| 7114 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7115 scoped_ptr<HttpTransaction> trans( | |
| 7116 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7117 | |
| 7118 MockWrite data_writes[] = { | |
| 7119 MockWrite("GET / HTTP/1.1\r\n" | |
| 7120 "Host: www.google.com\r\n" | |
| 7121 "Connection: keep-alive\r\n" | |
| 7122 "Pragma: no-cache\r\n" | |
| 7123 "Cache-Control: no-cache\r\n\r\n"), | |
| 7124 }; | |
| 7125 | |
| 7126 // Lastly, the server responds with the actual content. | |
| 7127 MockRead data_reads[] = { | |
| 7128 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7129 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 7130 MockRead("Content-Length: 100\r\n\r\n"), | |
| 7131 MockRead(SYNCHRONOUS, OK), | |
| 7132 }; | |
| 7133 | |
| 7134 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7135 data_writes, arraysize(data_writes)); | |
| 7136 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7137 | |
| 7138 TestCompletionCallback callback; | |
| 7139 | |
| 7140 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7141 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7142 | |
| 7143 rv = callback.WaitForResult(); | |
| 7144 EXPECT_EQ(OK, rv); | |
| 7145 } | |
| 7146 | |
| 7147 TEST_P(HttpNetworkTransactionTest, | |
| 7148 BuildRequest_CacheControlValidateCache) { | |
| 7149 HttpRequestInfo request; | |
| 7150 request.method = "GET"; | |
| 7151 request.url = GURL("http://www.google.com/"); | |
| 7152 request.load_flags = LOAD_VALIDATE_CACHE; | |
| 7153 | |
| 7154 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7155 scoped_ptr<HttpTransaction> trans( | |
| 7156 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7157 | |
| 7158 MockWrite data_writes[] = { | |
| 7159 MockWrite("GET / HTTP/1.1\r\n" | |
| 7160 "Host: www.google.com\r\n" | |
| 7161 "Connection: keep-alive\r\n" | |
| 7162 "Cache-Control: max-age=0\r\n\r\n"), | |
| 7163 }; | |
| 7164 | |
| 7165 // Lastly, the server responds with the actual content. | |
| 7166 MockRead data_reads[] = { | |
| 7167 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7168 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 7169 MockRead("Content-Length: 100\r\n\r\n"), | |
| 7170 MockRead(SYNCHRONOUS, OK), | |
| 7171 }; | |
| 7172 | |
| 7173 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7174 data_writes, arraysize(data_writes)); | |
| 7175 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7176 | |
| 7177 TestCompletionCallback callback; | |
| 7178 | |
| 7179 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7180 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7181 | |
| 7182 rv = callback.WaitForResult(); | |
| 7183 EXPECT_EQ(OK, rv); | |
| 7184 } | |
| 7185 | |
| 7186 TEST_P(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) { | |
| 7187 HttpRequestInfo request; | |
| 7188 request.method = "GET"; | |
| 7189 request.url = GURL("http://www.google.com/"); | |
| 7190 request.extra_headers.SetHeader("FooHeader", "Bar"); | |
| 7191 | |
| 7192 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7193 scoped_ptr<HttpTransaction> trans( | |
| 7194 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7195 | |
| 7196 MockWrite data_writes[] = { | |
| 7197 MockWrite("GET / HTTP/1.1\r\n" | |
| 7198 "Host: www.google.com\r\n" | |
| 7199 "Connection: keep-alive\r\n" | |
| 7200 "FooHeader: Bar\r\n\r\n"), | |
| 7201 }; | |
| 7202 | |
| 7203 // Lastly, the server responds with the actual content. | |
| 7204 MockRead data_reads[] = { | |
| 7205 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7206 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 7207 MockRead("Content-Length: 100\r\n\r\n"), | |
| 7208 MockRead(SYNCHRONOUS, OK), | |
| 7209 }; | |
| 7210 | |
| 7211 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7212 data_writes, arraysize(data_writes)); | |
| 7213 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7214 | |
| 7215 TestCompletionCallback callback; | |
| 7216 | |
| 7217 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7218 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7219 | |
| 7220 rv = callback.WaitForResult(); | |
| 7221 EXPECT_EQ(OK, rv); | |
| 7222 } | |
| 7223 | |
| 7224 TEST_P(HttpNetworkTransactionTest, BuildRequest_ExtraHeadersStripped) { | |
| 7225 HttpRequestInfo request; | |
| 7226 request.method = "GET"; | |
| 7227 request.url = GURL("http://www.google.com/"); | |
| 7228 request.extra_headers.SetHeader("referer", "www.foo.com"); | |
| 7229 request.extra_headers.SetHeader("hEllo", "Kitty"); | |
| 7230 request.extra_headers.SetHeader("FoO", "bar"); | |
| 7231 | |
| 7232 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7233 scoped_ptr<HttpTransaction> trans( | |
| 7234 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7235 | |
| 7236 MockWrite data_writes[] = { | |
| 7237 MockWrite("GET / HTTP/1.1\r\n" | |
| 7238 "Host: www.google.com\r\n" | |
| 7239 "Connection: keep-alive\r\n" | |
| 7240 "referer: www.foo.com\r\n" | |
| 7241 "hEllo: Kitty\r\n" | |
| 7242 "FoO: bar\r\n\r\n"), | |
| 7243 }; | |
| 7244 | |
| 7245 // Lastly, the server responds with the actual content. | |
| 7246 MockRead data_reads[] = { | |
| 7247 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7248 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 7249 MockRead("Content-Length: 100\r\n\r\n"), | |
| 7250 MockRead(SYNCHRONOUS, OK), | |
| 7251 }; | |
| 7252 | |
| 7253 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7254 data_writes, arraysize(data_writes)); | |
| 7255 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7256 | |
| 7257 TestCompletionCallback callback; | |
| 7258 | |
| 7259 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7260 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7261 | |
| 7262 rv = callback.WaitForResult(); | |
| 7263 EXPECT_EQ(OK, rv); | |
| 7264 } | |
| 7265 | |
| 7266 TEST_P(HttpNetworkTransactionTest, SOCKS4_HTTP_GET) { | |
| 7267 HttpRequestInfo request; | |
| 7268 request.method = "GET"; | |
| 7269 request.url = GURL("http://www.google.com/"); | |
| 7270 request.load_flags = 0; | |
| 7271 | |
| 7272 session_deps_.proxy_service.reset( | |
| 7273 ProxyService::CreateFixedFromPacResult("SOCKS myproxy:1080")); | |
| 7274 CapturingNetLog net_log; | |
| 7275 session_deps_.net_log = &net_log; | |
| 7276 | |
| 7277 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7278 scoped_ptr<HttpTransaction> trans( | |
| 7279 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7280 | |
| 7281 char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 }; | |
| 7282 char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; | |
| 7283 | |
| 7284 MockWrite data_writes[] = { | |
| 7285 MockWrite(ASYNC, write_buffer, arraysize(write_buffer)), | |
| 7286 MockWrite("GET / HTTP/1.1\r\n" | |
| 7287 "Host: www.google.com\r\n" | |
| 7288 "Connection: keep-alive\r\n\r\n") | |
| 7289 }; | |
| 7290 | |
| 7291 MockRead data_reads[] = { | |
| 7292 MockRead(ASYNC, read_buffer, arraysize(read_buffer)), | |
| 7293 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7294 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
| 7295 MockRead("Payload"), | |
| 7296 MockRead(SYNCHRONOUS, OK) | |
| 7297 }; | |
| 7298 | |
| 7299 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7300 data_writes, arraysize(data_writes)); | |
| 7301 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7302 | |
| 7303 TestCompletionCallback callback; | |
| 7304 | |
| 7305 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7306 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7307 | |
| 7308 rv = callback.WaitForResult(); | |
| 7309 EXPECT_EQ(OK, rv); | |
| 7310 | |
| 7311 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 7312 ASSERT_TRUE(response != NULL); | |
| 7313 | |
| 7314 LoadTimingInfo load_timing_info; | |
| 7315 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 7316 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 7317 CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); | |
| 7318 | |
| 7319 std::string response_text; | |
| 7320 rv = ReadTransaction(trans.get(), &response_text); | |
| 7321 EXPECT_EQ(OK, rv); | |
| 7322 EXPECT_EQ("Payload", response_text); | |
| 7323 } | |
| 7324 | |
| 7325 TEST_P(HttpNetworkTransactionTest, SOCKS4_SSL_GET) { | |
| 7326 HttpRequestInfo request; | |
| 7327 request.method = "GET"; | |
| 7328 request.url = GURL("https://www.google.com/"); | |
| 7329 request.load_flags = 0; | |
| 7330 | |
| 7331 session_deps_.proxy_service.reset( | |
| 7332 ProxyService::CreateFixedFromPacResult("SOCKS myproxy:1080")); | |
| 7333 CapturingNetLog net_log; | |
| 7334 session_deps_.net_log = &net_log; | |
| 7335 | |
| 7336 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7337 scoped_ptr<HttpTransaction> trans( | |
| 7338 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7339 | |
| 7340 unsigned char write_buffer[] = { 0x04, 0x01, 0x01, 0xBB, 127, 0, 0, 1, 0 }; | |
| 7341 unsigned char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; | |
| 7342 | |
| 7343 MockWrite data_writes[] = { | |
| 7344 MockWrite(ASYNC, reinterpret_cast<char*>(write_buffer), | |
| 7345 arraysize(write_buffer)), | |
| 7346 MockWrite("GET / HTTP/1.1\r\n" | |
| 7347 "Host: www.google.com\r\n" | |
| 7348 "Connection: keep-alive\r\n\r\n") | |
| 7349 }; | |
| 7350 | |
| 7351 MockRead data_reads[] = { | |
| 7352 MockRead(ASYNC, reinterpret_cast<char*>(read_buffer), | |
| 7353 arraysize(read_buffer)), | |
| 7354 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7355 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
| 7356 MockRead("Payload"), | |
| 7357 MockRead(SYNCHRONOUS, OK) | |
| 7358 }; | |
| 7359 | |
| 7360 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7361 data_writes, arraysize(data_writes)); | |
| 7362 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7363 | |
| 7364 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 7365 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 7366 | |
| 7367 TestCompletionCallback callback; | |
| 7368 | |
| 7369 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7370 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7371 | |
| 7372 rv = callback.WaitForResult(); | |
| 7373 EXPECT_EQ(OK, rv); | |
| 7374 | |
| 7375 LoadTimingInfo load_timing_info; | |
| 7376 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 7377 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 7378 CONNECT_TIMING_HAS_SSL_TIMES); | |
| 7379 | |
| 7380 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 7381 ASSERT_TRUE(response != NULL); | |
| 7382 | |
| 7383 std::string response_text; | |
| 7384 rv = ReadTransaction(trans.get(), &response_text); | |
| 7385 EXPECT_EQ(OK, rv); | |
| 7386 EXPECT_EQ("Payload", response_text); | |
| 7387 } | |
| 7388 | |
| 7389 TEST_P(HttpNetworkTransactionTest, SOCKS4_HTTP_GET_no_PAC) { | |
| 7390 HttpRequestInfo request; | |
| 7391 request.method = "GET"; | |
| 7392 request.url = GURL("http://www.google.com/"); | |
| 7393 request.load_flags = 0; | |
| 7394 | |
| 7395 session_deps_.proxy_service.reset( | |
| 7396 ProxyService::CreateFixed("socks4://myproxy:1080")); | |
| 7397 CapturingNetLog net_log; | |
| 7398 session_deps_.net_log = &net_log; | |
| 7399 | |
| 7400 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7401 scoped_ptr<HttpTransaction> trans( | |
| 7402 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7403 | |
| 7404 char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 }; | |
| 7405 char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; | |
| 7406 | |
| 7407 MockWrite data_writes[] = { | |
| 7408 MockWrite(ASYNC, write_buffer, arraysize(write_buffer)), | |
| 7409 MockWrite("GET / HTTP/1.1\r\n" | |
| 7410 "Host: www.google.com\r\n" | |
| 7411 "Connection: keep-alive\r\n\r\n") | |
| 7412 }; | |
| 7413 | |
| 7414 MockRead data_reads[] = { | |
| 7415 MockRead(ASYNC, read_buffer, arraysize(read_buffer)), | |
| 7416 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7417 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
| 7418 MockRead("Payload"), | |
| 7419 MockRead(SYNCHRONOUS, OK) | |
| 7420 }; | |
| 7421 | |
| 7422 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7423 data_writes, arraysize(data_writes)); | |
| 7424 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7425 | |
| 7426 TestCompletionCallback callback; | |
| 7427 | |
| 7428 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7429 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7430 | |
| 7431 rv = callback.WaitForResult(); | |
| 7432 EXPECT_EQ(OK, rv); | |
| 7433 | |
| 7434 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 7435 ASSERT_TRUE(response != NULL); | |
| 7436 | |
| 7437 LoadTimingInfo load_timing_info; | |
| 7438 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 7439 TestLoadTimingNotReused(load_timing_info, | |
| 7440 CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); | |
| 7441 | |
| 7442 std::string response_text; | |
| 7443 rv = ReadTransaction(trans.get(), &response_text); | |
| 7444 EXPECT_EQ(OK, rv); | |
| 7445 EXPECT_EQ("Payload", response_text); | |
| 7446 } | |
| 7447 | |
| 7448 TEST_P(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) { | |
| 7449 HttpRequestInfo request; | |
| 7450 request.method = "GET"; | |
| 7451 request.url = GURL("http://www.google.com/"); | |
| 7452 request.load_flags = 0; | |
| 7453 | |
| 7454 session_deps_.proxy_service.reset( | |
| 7455 ProxyService::CreateFixedFromPacResult("SOCKS5 myproxy:1080")); | |
| 7456 CapturingNetLog net_log; | |
| 7457 session_deps_.net_log = &net_log; | |
| 7458 | |
| 7459 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7460 scoped_ptr<HttpTransaction> trans( | |
| 7461 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7462 | |
| 7463 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; | |
| 7464 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 }; | |
| 7465 const char kSOCKS5OkRequest[] = { | |
| 7466 0x05, // Version | |
| 7467 0x01, // Command (CONNECT) | |
| 7468 0x00, // Reserved. | |
| 7469 0x03, // Address type (DOMAINNAME). | |
| 7470 0x0E, // Length of domain (14) | |
| 7471 // Domain string: | |
| 7472 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', | |
| 7473 0x00, 0x50, // 16-bit port (80) | |
| 7474 }; | |
| 7475 const char kSOCKS5OkResponse[] = | |
| 7476 { 0x05, 0x00, 0x00, 0x01, 127, 0, 0, 1, 0x00, 0x50 }; | |
| 7477 | |
| 7478 MockWrite data_writes[] = { | |
| 7479 MockWrite(ASYNC, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)), | |
| 7480 MockWrite(ASYNC, kSOCKS5OkRequest, arraysize(kSOCKS5OkRequest)), | |
| 7481 MockWrite("GET / HTTP/1.1\r\n" | |
| 7482 "Host: www.google.com\r\n" | |
| 7483 "Connection: keep-alive\r\n\r\n") | |
| 7484 }; | |
| 7485 | |
| 7486 MockRead data_reads[] = { | |
| 7487 MockRead(ASYNC, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), | |
| 7488 MockRead(ASYNC, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)), | |
| 7489 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7490 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
| 7491 MockRead("Payload"), | |
| 7492 MockRead(SYNCHRONOUS, OK) | |
| 7493 }; | |
| 7494 | |
| 7495 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7496 data_writes, arraysize(data_writes)); | |
| 7497 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7498 | |
| 7499 TestCompletionCallback callback; | |
| 7500 | |
| 7501 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7502 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7503 | |
| 7504 rv = callback.WaitForResult(); | |
| 7505 EXPECT_EQ(OK, rv); | |
| 7506 | |
| 7507 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 7508 ASSERT_TRUE(response != NULL); | |
| 7509 | |
| 7510 LoadTimingInfo load_timing_info; | |
| 7511 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 7512 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 7513 CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); | |
| 7514 | |
| 7515 std::string response_text; | |
| 7516 rv = ReadTransaction(trans.get(), &response_text); | |
| 7517 EXPECT_EQ(OK, rv); | |
| 7518 EXPECT_EQ("Payload", response_text); | |
| 7519 } | |
| 7520 | |
| 7521 TEST_P(HttpNetworkTransactionTest, SOCKS5_SSL_GET) { | |
| 7522 HttpRequestInfo request; | |
| 7523 request.method = "GET"; | |
| 7524 request.url = GURL("https://www.google.com/"); | |
| 7525 request.load_flags = 0; | |
| 7526 | |
| 7527 session_deps_.proxy_service.reset( | |
| 7528 ProxyService::CreateFixedFromPacResult("SOCKS5 myproxy:1080")); | |
| 7529 CapturingNetLog net_log; | |
| 7530 session_deps_.net_log = &net_log; | |
| 7531 | |
| 7532 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7533 scoped_ptr<HttpTransaction> trans( | |
| 7534 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7535 | |
| 7536 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; | |
| 7537 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 }; | |
| 7538 const unsigned char kSOCKS5OkRequest[] = { | |
| 7539 0x05, // Version | |
| 7540 0x01, // Command (CONNECT) | |
| 7541 0x00, // Reserved. | |
| 7542 0x03, // Address type (DOMAINNAME). | |
| 7543 0x0E, // Length of domain (14) | |
| 7544 // Domain string: | |
| 7545 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', | |
| 7546 0x01, 0xBB, // 16-bit port (443) | |
| 7547 }; | |
| 7548 | |
| 7549 const char kSOCKS5OkResponse[] = | |
| 7550 { 0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0x00, 0x00 }; | |
| 7551 | |
| 7552 MockWrite data_writes[] = { | |
| 7553 MockWrite(ASYNC, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)), | |
| 7554 MockWrite(ASYNC, reinterpret_cast<const char*>(kSOCKS5OkRequest), | |
| 7555 arraysize(kSOCKS5OkRequest)), | |
| 7556 MockWrite("GET / HTTP/1.1\r\n" | |
| 7557 "Host: www.google.com\r\n" | |
| 7558 "Connection: keep-alive\r\n\r\n") | |
| 7559 }; | |
| 7560 | |
| 7561 MockRead data_reads[] = { | |
| 7562 MockRead(ASYNC, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), | |
| 7563 MockRead(ASYNC, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)), | |
| 7564 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 7565 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
| 7566 MockRead("Payload"), | |
| 7567 MockRead(SYNCHRONOUS, OK) | |
| 7568 }; | |
| 7569 | |
| 7570 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 7571 data_writes, arraysize(data_writes)); | |
| 7572 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7573 | |
| 7574 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 7575 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 7576 | |
| 7577 TestCompletionCallback callback; | |
| 7578 | |
| 7579 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7580 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7581 | |
| 7582 rv = callback.WaitForResult(); | |
| 7583 EXPECT_EQ(OK, rv); | |
| 7584 | |
| 7585 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 7586 ASSERT_TRUE(response != NULL); | |
| 7587 | |
| 7588 LoadTimingInfo load_timing_info; | |
| 7589 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 7590 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 7591 CONNECT_TIMING_HAS_SSL_TIMES); | |
| 7592 | |
| 7593 std::string response_text; | |
| 7594 rv = ReadTransaction(trans.get(), &response_text); | |
| 7595 EXPECT_EQ(OK, rv); | |
| 7596 EXPECT_EQ("Payload", response_text); | |
| 7597 } | |
| 7598 | |
| 7599 namespace { | |
| 7600 | |
| 7601 // Tests that for connection endpoints the group names are correctly set. | |
| 7602 | |
| 7603 struct GroupNameTest { | |
| 7604 std::string proxy_server; | |
| 7605 std::string url; | |
| 7606 std::string expected_group_name; | |
| 7607 bool ssl; | |
| 7608 }; | |
| 7609 | |
| 7610 scoped_refptr<HttpNetworkSession> SetupSessionForGroupNameTests( | |
| 7611 NextProto next_proto, | |
| 7612 SpdySessionDependencies* session_deps_) { | |
| 7613 scoped_refptr<HttpNetworkSession> session(CreateSession(session_deps_)); | |
| 7614 | |
| 7615 base::WeakPtr<HttpServerProperties> http_server_properties = | |
| 7616 session->http_server_properties(); | |
| 7617 http_server_properties->SetAlternateProtocol( | |
| 7618 HostPortPair("host.with.alternate", 80), 443, | |
| 7619 AlternateProtocolFromNextProto(next_proto), 1.0); | |
| 7620 | |
| 7621 return session; | |
| 7622 } | |
| 7623 | |
| 7624 int GroupNameTransactionHelper( | |
| 7625 const std::string& url, | |
| 7626 const scoped_refptr<HttpNetworkSession>& session) { | |
| 7627 HttpRequestInfo request; | |
| 7628 request.method = "GET"; | |
| 7629 request.url = GURL(url); | |
| 7630 request.load_flags = 0; | |
| 7631 | |
| 7632 scoped_ptr<HttpTransaction> trans( | |
| 7633 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7634 | |
| 7635 TestCompletionCallback callback; | |
| 7636 | |
| 7637 // We do not complete this request, the dtor will clean the transaction up. | |
| 7638 return trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7639 } | |
| 7640 | |
| 7641 } // namespace | |
| 7642 | |
| 7643 TEST_P(HttpNetworkTransactionTest, GroupNameForDirectConnections) { | |
| 7644 const GroupNameTest tests[] = { | |
| 7645 { | |
| 7646 "", // unused | |
| 7647 "http://www.google.com/direct", | |
| 7648 "www.google.com:80", | |
| 7649 false, | |
| 7650 }, | |
| 7651 { | |
| 7652 "", // unused | |
| 7653 "http://[2001:1418:13:1::25]/direct", | |
| 7654 "[2001:1418:13:1::25]:80", | |
| 7655 false, | |
| 7656 }, | |
| 7657 | |
| 7658 // SSL Tests | |
| 7659 { | |
| 7660 "", // unused | |
| 7661 "https://www.google.com/direct_ssl", | |
| 7662 "ssl/www.google.com:443", | |
| 7663 true, | |
| 7664 }, | |
| 7665 { | |
| 7666 "", // unused | |
| 7667 "https://[2001:1418:13:1::25]/direct", | |
| 7668 "ssl/[2001:1418:13:1::25]:443", | |
| 7669 true, | |
| 7670 }, | |
| 7671 { | |
| 7672 "", // unused | |
| 7673 "http://host.with.alternate/direct", | |
| 7674 "ssl/host.with.alternate:443", | |
| 7675 true, | |
| 7676 }, | |
| 7677 }; | |
| 7678 | |
| 7679 session_deps_.use_alternate_protocols = true; | |
| 7680 | |
| 7681 for (size_t i = 0; i < arraysize(tests); ++i) { | |
| 7682 session_deps_.proxy_service.reset( | |
| 7683 ProxyService::CreateFixed(tests[i].proxy_server)); | |
| 7684 scoped_refptr<HttpNetworkSession> session( | |
| 7685 SetupSessionForGroupNameTests(GetParam(), &session_deps_)); | |
| 7686 | |
| 7687 HttpNetworkSessionPeer peer(session); | |
| 7688 CaptureGroupNameTransportSocketPool* transport_conn_pool = | |
| 7689 new CaptureGroupNameTransportSocketPool(NULL, NULL); | |
| 7690 CaptureGroupNameSSLSocketPool* ssl_conn_pool = | |
| 7691 new CaptureGroupNameSSLSocketPool(NULL, NULL); | |
| 7692 scoped_ptr<MockClientSocketPoolManager> mock_pool_manager( | |
| 7693 new MockClientSocketPoolManager); | |
| 7694 mock_pool_manager->SetTransportSocketPool(transport_conn_pool); | |
| 7695 mock_pool_manager->SetSSLSocketPool(ssl_conn_pool); | |
| 7696 peer.SetClientSocketPoolManager(mock_pool_manager.Pass()); | |
| 7697 | |
| 7698 EXPECT_EQ(ERR_IO_PENDING, | |
| 7699 GroupNameTransactionHelper(tests[i].url, session)); | |
| 7700 if (tests[i].ssl) | |
| 7701 EXPECT_EQ(tests[i].expected_group_name, | |
| 7702 ssl_conn_pool->last_group_name_received()); | |
| 7703 else | |
| 7704 EXPECT_EQ(tests[i].expected_group_name, | |
| 7705 transport_conn_pool->last_group_name_received()); | |
| 7706 } | |
| 7707 | |
| 7708 } | |
| 7709 | |
| 7710 TEST_P(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) { | |
| 7711 const GroupNameTest tests[] = { | |
| 7712 { | |
| 7713 "http_proxy", | |
| 7714 "http://www.google.com/http_proxy_normal", | |
| 7715 "www.google.com:80", | |
| 7716 false, | |
| 7717 }, | |
| 7718 | |
| 7719 // SSL Tests | |
| 7720 { | |
| 7721 "http_proxy", | |
| 7722 "https://www.google.com/http_connect_ssl", | |
| 7723 "ssl/www.google.com:443", | |
| 7724 true, | |
| 7725 }, | |
| 7726 | |
| 7727 { | |
| 7728 "http_proxy", | |
| 7729 "http://host.with.alternate/direct", | |
| 7730 "ssl/host.with.alternate:443", | |
| 7731 true, | |
| 7732 }, | |
| 7733 | |
| 7734 { | |
| 7735 "http_proxy", | |
| 7736 "ftp://ftp.google.com/http_proxy_normal", | |
| 7737 "ftp/ftp.google.com:21", | |
| 7738 false, | |
| 7739 }, | |
| 7740 }; | |
| 7741 | |
| 7742 session_deps_.use_alternate_protocols = true; | |
| 7743 | |
| 7744 for (size_t i = 0; i < arraysize(tests); ++i) { | |
| 7745 session_deps_.proxy_service.reset( | |
| 7746 ProxyService::CreateFixed(tests[i].proxy_server)); | |
| 7747 scoped_refptr<HttpNetworkSession> session( | |
| 7748 SetupSessionForGroupNameTests(GetParam(), &session_deps_)); | |
| 7749 | |
| 7750 HttpNetworkSessionPeer peer(session); | |
| 7751 | |
| 7752 HostPortPair proxy_host("http_proxy", 80); | |
| 7753 CaptureGroupNameHttpProxySocketPool* http_proxy_pool = | |
| 7754 new CaptureGroupNameHttpProxySocketPool(NULL, NULL); | |
| 7755 CaptureGroupNameSSLSocketPool* ssl_conn_pool = | |
| 7756 new CaptureGroupNameSSLSocketPool(NULL, NULL); | |
| 7757 | |
| 7758 scoped_ptr<MockClientSocketPoolManager> mock_pool_manager( | |
| 7759 new MockClientSocketPoolManager); | |
| 7760 mock_pool_manager->SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool); | |
| 7761 mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); | |
| 7762 peer.SetClientSocketPoolManager(mock_pool_manager.Pass()); | |
| 7763 | |
| 7764 EXPECT_EQ(ERR_IO_PENDING, | |
| 7765 GroupNameTransactionHelper(tests[i].url, session)); | |
| 7766 if (tests[i].ssl) | |
| 7767 EXPECT_EQ(tests[i].expected_group_name, | |
| 7768 ssl_conn_pool->last_group_name_received()); | |
| 7769 else | |
| 7770 EXPECT_EQ(tests[i].expected_group_name, | |
| 7771 http_proxy_pool->last_group_name_received()); | |
| 7772 } | |
| 7773 } | |
| 7774 | |
| 7775 TEST_P(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) { | |
| 7776 const GroupNameTest tests[] = { | |
| 7777 { | |
| 7778 "socks4://socks_proxy:1080", | |
| 7779 "http://www.google.com/socks4_direct", | |
| 7780 "socks4/www.google.com:80", | |
| 7781 false, | |
| 7782 }, | |
| 7783 { | |
| 7784 "socks5://socks_proxy:1080", | |
| 7785 "http://www.google.com/socks5_direct", | |
| 7786 "socks5/www.google.com:80", | |
| 7787 false, | |
| 7788 }, | |
| 7789 | |
| 7790 // SSL Tests | |
| 7791 { | |
| 7792 "socks4://socks_proxy:1080", | |
| 7793 "https://www.google.com/socks4_ssl", | |
| 7794 "socks4/ssl/www.google.com:443", | |
| 7795 true, | |
| 7796 }, | |
| 7797 { | |
| 7798 "socks5://socks_proxy:1080", | |
| 7799 "https://www.google.com/socks5_ssl", | |
| 7800 "socks5/ssl/www.google.com:443", | |
| 7801 true, | |
| 7802 }, | |
| 7803 | |
| 7804 { | |
| 7805 "socks4://socks_proxy:1080", | |
| 7806 "http://host.with.alternate/direct", | |
| 7807 "socks4/ssl/host.with.alternate:443", | |
| 7808 true, | |
| 7809 }, | |
| 7810 }; | |
| 7811 | |
| 7812 session_deps_.use_alternate_protocols = true; | |
| 7813 | |
| 7814 for (size_t i = 0; i < arraysize(tests); ++i) { | |
| 7815 session_deps_.proxy_service.reset( | |
| 7816 ProxyService::CreateFixed(tests[i].proxy_server)); | |
| 7817 scoped_refptr<HttpNetworkSession> session( | |
| 7818 SetupSessionForGroupNameTests(GetParam(), &session_deps_)); | |
| 7819 | |
| 7820 HttpNetworkSessionPeer peer(session); | |
| 7821 | |
| 7822 HostPortPair proxy_host("socks_proxy", 1080); | |
| 7823 CaptureGroupNameSOCKSSocketPool* socks_conn_pool = | |
| 7824 new CaptureGroupNameSOCKSSocketPool(NULL, NULL); | |
| 7825 CaptureGroupNameSSLSocketPool* ssl_conn_pool = | |
| 7826 new CaptureGroupNameSSLSocketPool(NULL, NULL); | |
| 7827 | |
| 7828 scoped_ptr<MockClientSocketPoolManager> mock_pool_manager( | |
| 7829 new MockClientSocketPoolManager); | |
| 7830 mock_pool_manager->SetSocketPoolForSOCKSProxy(proxy_host, socks_conn_pool); | |
| 7831 mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); | |
| 7832 peer.SetClientSocketPoolManager(mock_pool_manager.Pass()); | |
| 7833 | |
| 7834 scoped_ptr<HttpTransaction> trans( | |
| 7835 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7836 | |
| 7837 EXPECT_EQ(ERR_IO_PENDING, | |
| 7838 GroupNameTransactionHelper(tests[i].url, session)); | |
| 7839 if (tests[i].ssl) | |
| 7840 EXPECT_EQ(tests[i].expected_group_name, | |
| 7841 ssl_conn_pool->last_group_name_received()); | |
| 7842 else | |
| 7843 EXPECT_EQ(tests[i].expected_group_name, | |
| 7844 socks_conn_pool->last_group_name_received()); | |
| 7845 } | |
| 7846 } | |
| 7847 | |
| 7848 TEST_P(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) { | |
| 7849 HttpRequestInfo request; | |
| 7850 request.method = "GET"; | |
| 7851 request.url = GURL("http://www.google.com/"); | |
| 7852 | |
| 7853 session_deps_.proxy_service.reset( | |
| 7854 ProxyService::CreateFixed("myproxy:70;foobar:80")); | |
| 7855 | |
| 7856 // This simulates failure resolving all hostnames; that means we will fail | |
| 7857 // connecting to both proxies (myproxy:70 and foobar:80). | |
| 7858 session_deps_.host_resolver->rules()->AddSimulatedFailure("*"); | |
| 7859 | |
| 7860 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7861 scoped_ptr<HttpTransaction> trans( | |
| 7862 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7863 | |
| 7864 TestCompletionCallback callback; | |
| 7865 | |
| 7866 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7867 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7868 | |
| 7869 rv = callback.WaitForResult(); | |
| 7870 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv); | |
| 7871 } | |
| 7872 | |
| 7873 // Base test to make sure that when the load flags for a request specify to | |
| 7874 // bypass the cache, the DNS cache is not used. | |
| 7875 void HttpNetworkTransactionTest::BypassHostCacheOnRefreshHelper( | |
| 7876 int load_flags) { | |
| 7877 // Issue a request, asking to bypass the cache(s). | |
| 7878 HttpRequestInfo request; | |
| 7879 request.method = "GET"; | |
| 7880 request.load_flags = load_flags; | |
| 7881 request.url = GURL("http://www.google.com/"); | |
| 7882 | |
| 7883 // Select a host resolver that does caching. | |
| 7884 session_deps_.host_resolver.reset(new MockCachingHostResolver); | |
| 7885 | |
| 7886 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7887 scoped_ptr<HttpTransaction> trans( | |
| 7888 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7889 | |
| 7890 // Warm up the host cache so it has an entry for "www.google.com". | |
| 7891 AddressList addrlist; | |
| 7892 TestCompletionCallback callback; | |
| 7893 int rv = session_deps_.host_resolver->Resolve( | |
| 7894 HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), | |
| 7895 DEFAULT_PRIORITY, | |
| 7896 &addrlist, | |
| 7897 callback.callback(), | |
| 7898 NULL, | |
| 7899 BoundNetLog()); | |
| 7900 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7901 rv = callback.WaitForResult(); | |
| 7902 EXPECT_EQ(OK, rv); | |
| 7903 | |
| 7904 // Verify that it was added to host cache, by doing a subsequent async lookup | |
| 7905 // and confirming it completes synchronously. | |
| 7906 rv = session_deps_.host_resolver->Resolve( | |
| 7907 HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), | |
| 7908 DEFAULT_PRIORITY, | |
| 7909 &addrlist, | |
| 7910 callback.callback(), | |
| 7911 NULL, | |
| 7912 BoundNetLog()); | |
| 7913 ASSERT_EQ(OK, rv); | |
| 7914 | |
| 7915 // Inject a failure the next time that "www.google.com" is resolved. This way | |
| 7916 // we can tell if the next lookup hit the cache, or the "network". | |
| 7917 // (cache --> success, "network" --> failure). | |
| 7918 session_deps_.host_resolver->rules()->AddSimulatedFailure("www.google.com"); | |
| 7919 | |
| 7920 // Connect up a mock socket which will fail with ERR_UNEXPECTED during the | |
| 7921 // first read -- this won't be reached as the host resolution will fail first. | |
| 7922 MockRead data_reads[] = { MockRead(SYNCHRONOUS, ERR_UNEXPECTED) }; | |
| 7923 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 7924 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7925 | |
| 7926 // Run the request. | |
| 7927 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7928 ASSERT_EQ(ERR_IO_PENDING, rv); | |
| 7929 rv = callback.WaitForResult(); | |
| 7930 | |
| 7931 // If we bypassed the cache, we would have gotten a failure while resolving | |
| 7932 // "www.google.com". | |
| 7933 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv); | |
| 7934 } | |
| 7935 | |
| 7936 // There are multiple load flags that should trigger the host cache bypass. | |
| 7937 // Test each in isolation: | |
| 7938 TEST_P(HttpNetworkTransactionTest, BypassHostCacheOnRefresh1) { | |
| 7939 BypassHostCacheOnRefreshHelper(LOAD_BYPASS_CACHE); | |
| 7940 } | |
| 7941 | |
| 7942 TEST_P(HttpNetworkTransactionTest, BypassHostCacheOnRefresh2) { | |
| 7943 BypassHostCacheOnRefreshHelper(LOAD_VALIDATE_CACHE); | |
| 7944 } | |
| 7945 | |
| 7946 TEST_P(HttpNetworkTransactionTest, BypassHostCacheOnRefresh3) { | |
| 7947 BypassHostCacheOnRefreshHelper(LOAD_DISABLE_CACHE); | |
| 7948 } | |
| 7949 | |
| 7950 // Make sure we can handle an error when writing the request. | |
| 7951 TEST_P(HttpNetworkTransactionTest, RequestWriteError) { | |
| 7952 HttpRequestInfo request; | |
| 7953 request.method = "GET"; | |
| 7954 request.url = GURL("http://www.foo.com/"); | |
| 7955 request.load_flags = 0; | |
| 7956 | |
| 7957 MockWrite write_failure[] = { | |
| 7958 MockWrite(ASYNC, ERR_CONNECTION_RESET), | |
| 7959 }; | |
| 7960 StaticSocketDataProvider data(NULL, 0, | |
| 7961 write_failure, arraysize(write_failure)); | |
| 7962 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7963 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7964 | |
| 7965 TestCompletionCallback callback; | |
| 7966 | |
| 7967 scoped_ptr<HttpTransaction> trans( | |
| 7968 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7969 | |
| 7970 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7971 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7972 | |
| 7973 rv = callback.WaitForResult(); | |
| 7974 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 7975 } | |
| 7976 | |
| 7977 // Check that a connection closed after the start of the headers finishes ok. | |
| 7978 TEST_P(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) { | |
| 7979 HttpRequestInfo request; | |
| 7980 request.method = "GET"; | |
| 7981 request.url = GURL("http://www.foo.com/"); | |
| 7982 request.load_flags = 0; | |
| 7983 | |
| 7984 MockRead data_reads[] = { | |
| 7985 MockRead("HTTP/1."), | |
| 7986 MockRead(SYNCHRONOUS, OK), | |
| 7987 }; | |
| 7988 | |
| 7989 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 7990 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 7991 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 7992 | |
| 7993 TestCompletionCallback callback; | |
| 7994 | |
| 7995 scoped_ptr<HttpTransaction> trans( | |
| 7996 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 7997 | |
| 7998 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7999 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8000 | |
| 8001 rv = callback.WaitForResult(); | |
| 8002 EXPECT_EQ(OK, rv); | |
| 8003 | |
| 8004 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8005 ASSERT_TRUE(response != NULL); | |
| 8006 | |
| 8007 EXPECT_TRUE(response->headers.get() != NULL); | |
| 8008 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
| 8009 | |
| 8010 std::string response_data; | |
| 8011 rv = ReadTransaction(trans.get(), &response_data); | |
| 8012 EXPECT_EQ(OK, rv); | |
| 8013 EXPECT_EQ("", response_data); | |
| 8014 } | |
| 8015 | |
| 8016 // Make sure that a dropped connection while draining the body for auth | |
| 8017 // restart does the right thing. | |
| 8018 TEST_P(HttpNetworkTransactionTest, DrainResetOK) { | |
| 8019 HttpRequestInfo request; | |
| 8020 request.method = "GET"; | |
| 8021 request.url = GURL("http://www.google.com/"); | |
| 8022 request.load_flags = 0; | |
| 8023 | |
| 8024 MockWrite data_writes1[] = { | |
| 8025 MockWrite("GET / HTTP/1.1\r\n" | |
| 8026 "Host: www.google.com\r\n" | |
| 8027 "Connection: keep-alive\r\n\r\n"), | |
| 8028 }; | |
| 8029 | |
| 8030 MockRead data_reads1[] = { | |
| 8031 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
| 8032 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 8033 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 8034 MockRead("Content-Length: 14\r\n\r\n"), | |
| 8035 MockRead("Unauth"), | |
| 8036 MockRead(ASYNC, ERR_CONNECTION_RESET), | |
| 8037 }; | |
| 8038 | |
| 8039 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 8040 data_writes1, arraysize(data_writes1)); | |
| 8041 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 8042 | |
| 8043 // After calling trans->RestartWithAuth(), this is the request we should | |
| 8044 // be issuing -- the final header line contains the credentials. | |
| 8045 MockWrite data_writes2[] = { | |
| 8046 MockWrite("GET / HTTP/1.1\r\n" | |
| 8047 "Host: www.google.com\r\n" | |
| 8048 "Connection: keep-alive\r\n" | |
| 8049 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 8050 }; | |
| 8051 | |
| 8052 // Lastly, the server responds with the actual content. | |
| 8053 MockRead data_reads2[] = { | |
| 8054 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 8055 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 8056 MockRead("Content-Length: 100\r\n\r\n"), | |
| 8057 MockRead(SYNCHRONOUS, OK), | |
| 8058 }; | |
| 8059 | |
| 8060 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 8061 data_writes2, arraysize(data_writes2)); | |
| 8062 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 8063 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8064 | |
| 8065 TestCompletionCallback callback1; | |
| 8066 | |
| 8067 scoped_ptr<HttpTransaction> trans( | |
| 8068 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8069 | |
| 8070 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 8071 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8072 | |
| 8073 rv = callback1.WaitForResult(); | |
| 8074 EXPECT_EQ(OK, rv); | |
| 8075 | |
| 8076 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8077 ASSERT_TRUE(response != NULL); | |
| 8078 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 8079 | |
| 8080 TestCompletionCallback callback2; | |
| 8081 | |
| 8082 rv = trans->RestartWithAuth( | |
| 8083 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 8084 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8085 | |
| 8086 rv = callback2.WaitForResult(); | |
| 8087 EXPECT_EQ(OK, rv); | |
| 8088 | |
| 8089 response = trans->GetResponseInfo(); | |
| 8090 ASSERT_TRUE(response != NULL); | |
| 8091 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 8092 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 8093 } | |
| 8094 | |
| 8095 // Test HTTPS connections going through a proxy that sends extra data. | |
| 8096 TEST_P(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) { | |
| 8097 session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); | |
| 8098 | |
| 8099 HttpRequestInfo request; | |
| 8100 request.method = "GET"; | |
| 8101 request.url = GURL("https://www.google.com/"); | |
| 8102 request.load_flags = 0; | |
| 8103 | |
| 8104 MockRead proxy_reads[] = { | |
| 8105 MockRead("HTTP/1.0 200 Connected\r\n\r\nExtra data"), | |
| 8106 MockRead(SYNCHRONOUS, OK) | |
| 8107 }; | |
| 8108 | |
| 8109 StaticSocketDataProvider data(proxy_reads, arraysize(proxy_reads), NULL, 0); | |
| 8110 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 8111 | |
| 8112 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 8113 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 8114 | |
| 8115 TestCompletionCallback callback; | |
| 8116 | |
| 8117 session_deps_.socket_factory->ResetNextMockIndexes(); | |
| 8118 | |
| 8119 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8120 scoped_ptr<HttpTransaction> trans( | |
| 8121 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8122 | |
| 8123 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8124 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8125 | |
| 8126 rv = callback.WaitForResult(); | |
| 8127 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
| 8128 } | |
| 8129 | |
| 8130 TEST_P(HttpNetworkTransactionTest, LargeContentLengthThenClose) { | |
| 8131 HttpRequestInfo request; | |
| 8132 request.method = "GET"; | |
| 8133 request.url = GURL("http://www.google.com/"); | |
| 8134 request.load_flags = 0; | |
| 8135 | |
| 8136 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8137 scoped_ptr<HttpTransaction> trans( | |
| 8138 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8139 | |
| 8140 MockRead data_reads[] = { | |
| 8141 MockRead("HTTP/1.0 200 OK\r\nContent-Length:6719476739\r\n\r\n"), | |
| 8142 MockRead(SYNCHRONOUS, OK), | |
| 8143 }; | |
| 8144 | |
| 8145 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 8146 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 8147 | |
| 8148 TestCompletionCallback callback; | |
| 8149 | |
| 8150 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8151 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8152 | |
| 8153 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8154 | |
| 8155 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8156 ASSERT_TRUE(response != NULL); | |
| 8157 | |
| 8158 EXPECT_TRUE(response->headers.get() != NULL); | |
| 8159 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
| 8160 | |
| 8161 std::string response_data; | |
| 8162 rv = ReadTransaction(trans.get(), &response_data); | |
| 8163 EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, rv); | |
| 8164 } | |
| 8165 | |
| 8166 TEST_P(HttpNetworkTransactionTest, UploadFileSmallerThanLength) { | |
| 8167 base::FilePath temp_file_path; | |
| 8168 ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path)); | |
| 8169 const uint64 kFakeSize = 100000; // file is actually blank | |
| 8170 UploadFileElementReader::ScopedOverridingContentLengthForTests | |
| 8171 overriding_content_length(kFakeSize); | |
| 8172 | |
| 8173 ScopedVector<UploadElementReader> element_readers; | |
| 8174 element_readers.push_back( | |
| 8175 new UploadFileElementReader(base::MessageLoopProxy::current().get(), | |
| 8176 temp_file_path, | |
| 8177 0, | |
| 8178 kuint64max, | |
| 8179 base::Time())); | |
| 8180 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 8181 | |
| 8182 HttpRequestInfo request; | |
| 8183 request.method = "POST"; | |
| 8184 request.url = GURL("http://www.google.com/upload"); | |
| 8185 request.upload_data_stream = &upload_data_stream; | |
| 8186 request.load_flags = 0; | |
| 8187 | |
| 8188 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8189 scoped_ptr<HttpTransaction> trans( | |
| 8190 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8191 | |
| 8192 MockRead data_reads[] = { | |
| 8193 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
| 8194 MockRead("hello world"), | |
| 8195 MockRead(SYNCHRONOUS, OK), | |
| 8196 }; | |
| 8197 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 8198 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 8199 | |
| 8200 TestCompletionCallback callback; | |
| 8201 | |
| 8202 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8203 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8204 | |
| 8205 rv = callback.WaitForResult(); | |
| 8206 EXPECT_EQ(OK, rv); | |
| 8207 | |
| 8208 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8209 ASSERT_TRUE(response != NULL); | |
| 8210 | |
| 8211 EXPECT_TRUE(response->headers.get() != NULL); | |
| 8212 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
| 8213 | |
| 8214 std::string response_data; | |
| 8215 rv = ReadTransaction(trans.get(), &response_data); | |
| 8216 EXPECT_EQ(OK, rv); | |
| 8217 EXPECT_EQ("hello world", response_data); | |
| 8218 | |
| 8219 base::DeleteFile(temp_file_path, false); | |
| 8220 } | |
| 8221 | |
| 8222 TEST_P(HttpNetworkTransactionTest, UploadUnreadableFile) { | |
| 8223 base::FilePath temp_file; | |
| 8224 ASSERT_TRUE(base::CreateTemporaryFile(&temp_file)); | |
| 8225 std::string temp_file_content("Unreadable file."); | |
| 8226 ASSERT_TRUE(base::WriteFile(temp_file, temp_file_content.c_str(), | |
| 8227 temp_file_content.length())); | |
| 8228 ASSERT_TRUE(base::MakeFileUnreadable(temp_file)); | |
| 8229 | |
| 8230 ScopedVector<UploadElementReader> element_readers; | |
| 8231 element_readers.push_back( | |
| 8232 new UploadFileElementReader(base::MessageLoopProxy::current().get(), | |
| 8233 temp_file, | |
| 8234 0, | |
| 8235 kuint64max, | |
| 8236 base::Time())); | |
| 8237 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 8238 | |
| 8239 HttpRequestInfo request; | |
| 8240 request.method = "POST"; | |
| 8241 request.url = GURL("http://www.google.com/upload"); | |
| 8242 request.upload_data_stream = &upload_data_stream; | |
| 8243 request.load_flags = 0; | |
| 8244 | |
| 8245 // If we try to upload an unreadable file, the transaction should fail. | |
| 8246 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8247 scoped_ptr<HttpTransaction> trans( | |
| 8248 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8249 | |
| 8250 StaticSocketDataProvider data(NULL, 0, NULL, 0); | |
| 8251 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 8252 | |
| 8253 TestCompletionCallback callback; | |
| 8254 | |
| 8255 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8256 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8257 | |
| 8258 rv = callback.WaitForResult(); | |
| 8259 EXPECT_EQ(ERR_ACCESS_DENIED, rv); | |
| 8260 | |
| 8261 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8262 EXPECT_FALSE(response); | |
| 8263 | |
| 8264 base::DeleteFile(temp_file, false); | |
| 8265 } | |
| 8266 | |
| 8267 TEST_P(HttpNetworkTransactionTest, CancelDuringInitRequestBody) { | |
| 8268 class FakeUploadElementReader : public UploadElementReader { | |
| 8269 public: | |
| 8270 FakeUploadElementReader() {} | |
| 8271 ~FakeUploadElementReader() override {} | |
| 8272 | |
| 8273 const CompletionCallback& callback() const { return callback_; } | |
| 8274 | |
| 8275 // UploadElementReader overrides: | |
| 8276 int Init(const CompletionCallback& callback) override { | |
| 8277 callback_ = callback; | |
| 8278 return ERR_IO_PENDING; | |
| 8279 } | |
| 8280 uint64 GetContentLength() const override { return 0; } | |
| 8281 uint64 BytesRemaining() const override { return 0; } | |
| 8282 int Read(IOBuffer* buf, | |
| 8283 int buf_length, | |
| 8284 const CompletionCallback& callback) override { | |
| 8285 return ERR_FAILED; | |
| 8286 } | |
| 8287 | |
| 8288 private: | |
| 8289 CompletionCallback callback_; | |
| 8290 }; | |
| 8291 | |
| 8292 FakeUploadElementReader* fake_reader = new FakeUploadElementReader; | |
| 8293 ScopedVector<UploadElementReader> element_readers; | |
| 8294 element_readers.push_back(fake_reader); | |
| 8295 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 8296 | |
| 8297 HttpRequestInfo request; | |
| 8298 request.method = "POST"; | |
| 8299 request.url = GURL("http://www.google.com/upload"); | |
| 8300 request.upload_data_stream = &upload_data_stream; | |
| 8301 request.load_flags = 0; | |
| 8302 | |
| 8303 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8304 scoped_ptr<HttpTransaction> trans( | |
| 8305 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8306 | |
| 8307 StaticSocketDataProvider data; | |
| 8308 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 8309 | |
| 8310 TestCompletionCallback callback; | |
| 8311 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8312 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8313 base::MessageLoop::current()->RunUntilIdle(); | |
| 8314 | |
| 8315 // Transaction is pending on request body initialization. | |
| 8316 ASSERT_FALSE(fake_reader->callback().is_null()); | |
| 8317 | |
| 8318 // Return Init()'s result after the transaction gets destroyed. | |
| 8319 trans.reset(); | |
| 8320 fake_reader->callback().Run(OK); // Should not crash. | |
| 8321 } | |
| 8322 | |
| 8323 // Tests that changes to Auth realms are treated like auth rejections. | |
| 8324 TEST_P(HttpNetworkTransactionTest, ChangeAuthRealms) { | |
| 8325 | |
| 8326 HttpRequestInfo request; | |
| 8327 request.method = "GET"; | |
| 8328 request.url = GURL("http://www.google.com/"); | |
| 8329 request.load_flags = 0; | |
| 8330 | |
| 8331 // First transaction will request a resource and receive a Basic challenge | |
| 8332 // with realm="first_realm". | |
| 8333 MockWrite data_writes1[] = { | |
| 8334 MockWrite("GET / HTTP/1.1\r\n" | |
| 8335 "Host: www.google.com\r\n" | |
| 8336 "Connection: keep-alive\r\n" | |
| 8337 "\r\n"), | |
| 8338 }; | |
| 8339 MockRead data_reads1[] = { | |
| 8340 MockRead("HTTP/1.1 401 Unauthorized\r\n" | |
| 8341 "WWW-Authenticate: Basic realm=\"first_realm\"\r\n" | |
| 8342 "\r\n"), | |
| 8343 }; | |
| 8344 | |
| 8345 // After calling trans->RestartWithAuth(), provide an Authentication header | |
| 8346 // for first_realm. The server will reject and provide a challenge with | |
| 8347 // second_realm. | |
| 8348 MockWrite data_writes2[] = { | |
| 8349 MockWrite("GET / HTTP/1.1\r\n" | |
| 8350 "Host: www.google.com\r\n" | |
| 8351 "Connection: keep-alive\r\n" | |
| 8352 "Authorization: Basic Zmlyc3Q6YmF6\r\n" | |
| 8353 "\r\n"), | |
| 8354 }; | |
| 8355 MockRead data_reads2[] = { | |
| 8356 MockRead("HTTP/1.1 401 Unauthorized\r\n" | |
| 8357 "WWW-Authenticate: Basic realm=\"second_realm\"\r\n" | |
| 8358 "\r\n"), | |
| 8359 }; | |
| 8360 | |
| 8361 // This again fails, and goes back to first_realm. Make sure that the | |
| 8362 // entry is removed from cache. | |
| 8363 MockWrite data_writes3[] = { | |
| 8364 MockWrite("GET / HTTP/1.1\r\n" | |
| 8365 "Host: www.google.com\r\n" | |
| 8366 "Connection: keep-alive\r\n" | |
| 8367 "Authorization: Basic c2Vjb25kOmZvdQ==\r\n" | |
| 8368 "\r\n"), | |
| 8369 }; | |
| 8370 MockRead data_reads3[] = { | |
| 8371 MockRead("HTTP/1.1 401 Unauthorized\r\n" | |
| 8372 "WWW-Authenticate: Basic realm=\"first_realm\"\r\n" | |
| 8373 "\r\n"), | |
| 8374 }; | |
| 8375 | |
| 8376 // Try one last time (with the correct password) and get the resource. | |
| 8377 MockWrite data_writes4[] = { | |
| 8378 MockWrite("GET / HTTP/1.1\r\n" | |
| 8379 "Host: www.google.com\r\n" | |
| 8380 "Connection: keep-alive\r\n" | |
| 8381 "Authorization: Basic Zmlyc3Q6YmFy\r\n" | |
| 8382 "\r\n"), | |
| 8383 }; | |
| 8384 MockRead data_reads4[] = { | |
| 8385 MockRead("HTTP/1.1 200 OK\r\n" | |
| 8386 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 8387 "Content-Length: 5\r\n" | |
| 8388 "\r\n" | |
| 8389 "hello"), | |
| 8390 }; | |
| 8391 | |
| 8392 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 8393 data_writes1, arraysize(data_writes1)); | |
| 8394 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 8395 data_writes2, arraysize(data_writes2)); | |
| 8396 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
| 8397 data_writes3, arraysize(data_writes3)); | |
| 8398 StaticSocketDataProvider data4(data_reads4, arraysize(data_reads4), | |
| 8399 data_writes4, arraysize(data_writes4)); | |
| 8400 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 8401 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 8402 session_deps_.socket_factory->AddSocketDataProvider(&data3); | |
| 8403 session_deps_.socket_factory->AddSocketDataProvider(&data4); | |
| 8404 | |
| 8405 TestCompletionCallback callback1; | |
| 8406 | |
| 8407 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8408 scoped_ptr<HttpTransaction> trans( | |
| 8409 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8410 | |
| 8411 // Issue the first request with Authorize headers. There should be a | |
| 8412 // password prompt for first_realm waiting to be filled in after the | |
| 8413 // transaction completes. | |
| 8414 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 8415 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8416 rv = callback1.WaitForResult(); | |
| 8417 EXPECT_EQ(OK, rv); | |
| 8418 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8419 ASSERT_TRUE(response != NULL); | |
| 8420 const AuthChallengeInfo* challenge = response->auth_challenge.get(); | |
| 8421 ASSERT_FALSE(challenge == NULL); | |
| 8422 EXPECT_FALSE(challenge->is_proxy); | |
| 8423 EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); | |
| 8424 EXPECT_EQ("first_realm", challenge->realm); | |
| 8425 EXPECT_EQ("basic", challenge->scheme); | |
| 8426 | |
| 8427 // Issue the second request with an incorrect password. There should be a | |
| 8428 // password prompt for second_realm waiting to be filled in after the | |
| 8429 // transaction completes. | |
| 8430 TestCompletionCallback callback2; | |
| 8431 rv = trans->RestartWithAuth( | |
| 8432 AuthCredentials(kFirst, kBaz), callback2.callback()); | |
| 8433 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8434 rv = callback2.WaitForResult(); | |
| 8435 EXPECT_EQ(OK, rv); | |
| 8436 response = trans->GetResponseInfo(); | |
| 8437 ASSERT_TRUE(response != NULL); | |
| 8438 challenge = response->auth_challenge.get(); | |
| 8439 ASSERT_FALSE(challenge == NULL); | |
| 8440 EXPECT_FALSE(challenge->is_proxy); | |
| 8441 EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); | |
| 8442 EXPECT_EQ("second_realm", challenge->realm); | |
| 8443 EXPECT_EQ("basic", challenge->scheme); | |
| 8444 | |
| 8445 // Issue the third request with another incorrect password. There should be | |
| 8446 // a password prompt for first_realm waiting to be filled in. If the password | |
| 8447 // prompt is not present, it indicates that the HttpAuthCacheEntry for | |
| 8448 // first_realm was not correctly removed. | |
| 8449 TestCompletionCallback callback3; | |
| 8450 rv = trans->RestartWithAuth( | |
| 8451 AuthCredentials(kSecond, kFou), callback3.callback()); | |
| 8452 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8453 rv = callback3.WaitForResult(); | |
| 8454 EXPECT_EQ(OK, rv); | |
| 8455 response = trans->GetResponseInfo(); | |
| 8456 ASSERT_TRUE(response != NULL); | |
| 8457 challenge = response->auth_challenge.get(); | |
| 8458 ASSERT_FALSE(challenge == NULL); | |
| 8459 EXPECT_FALSE(challenge->is_proxy); | |
| 8460 EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); | |
| 8461 EXPECT_EQ("first_realm", challenge->realm); | |
| 8462 EXPECT_EQ("basic", challenge->scheme); | |
| 8463 | |
| 8464 // Issue the fourth request with the correct password and username. | |
| 8465 TestCompletionCallback callback4; | |
| 8466 rv = trans->RestartWithAuth( | |
| 8467 AuthCredentials(kFirst, kBar), callback4.callback()); | |
| 8468 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8469 rv = callback4.WaitForResult(); | |
| 8470 EXPECT_EQ(OK, rv); | |
| 8471 response = trans->GetResponseInfo(); | |
| 8472 ASSERT_TRUE(response != NULL); | |
| 8473 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 8474 } | |
| 8475 | |
| 8476 TEST_P(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) { | |
| 8477 session_deps_.next_protos = SpdyNextProtos(); | |
| 8478 session_deps_.use_alternate_protocols = true; | |
| 8479 | |
| 8480 std::string alternate_protocol_http_header = | |
| 8481 GetAlternateProtocolHttpHeader(); | |
| 8482 | |
| 8483 MockRead data_reads[] = { | |
| 8484 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 8485 MockRead(alternate_protocol_http_header.c_str()), | |
| 8486 MockRead("hello world"), | |
| 8487 MockRead(SYNCHRONOUS, OK), | |
| 8488 }; | |
| 8489 | |
| 8490 HttpRequestInfo request; | |
| 8491 request.method = "GET"; | |
| 8492 request.url = GURL("http://www.google.com/"); | |
| 8493 request.load_flags = 0; | |
| 8494 | |
| 8495 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 8496 | |
| 8497 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 8498 | |
| 8499 TestCompletionCallback callback; | |
| 8500 | |
| 8501 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8502 scoped_ptr<HttpTransaction> trans( | |
| 8503 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8504 | |
| 8505 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8506 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8507 | |
| 8508 HostPortPair http_host_port_pair("www.google.com", 80); | |
| 8509 HttpServerProperties& http_server_properties = | |
| 8510 *session->http_server_properties(); | |
| 8511 AlternateProtocolInfo alternate = | |
| 8512 http_server_properties.GetAlternateProtocol(http_host_port_pair); | |
| 8513 EXPECT_EQ(alternate.protocol, UNINITIALIZED_ALTERNATE_PROTOCOL); | |
| 8514 | |
| 8515 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8516 | |
| 8517 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8518 ASSERT_TRUE(response != NULL); | |
| 8519 ASSERT_TRUE(response->headers.get() != NULL); | |
| 8520 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 8521 EXPECT_FALSE(response->was_fetched_via_spdy); | |
| 8522 EXPECT_FALSE(response->was_npn_negotiated); | |
| 8523 | |
| 8524 std::string response_data; | |
| 8525 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 8526 EXPECT_EQ("hello world", response_data); | |
| 8527 | |
| 8528 alternate = http_server_properties.GetAlternateProtocol(http_host_port_pair); | |
| 8529 EXPECT_EQ(443, alternate.port); | |
| 8530 EXPECT_EQ(AlternateProtocolFromNextProto(GetParam()), alternate.protocol); | |
| 8531 EXPECT_EQ(1.0, alternate.probability); | |
| 8532 } | |
| 8533 | |
| 8534 TEST_P(HttpNetworkTransactionTest, | |
| 8535 MarkBrokenAlternateProtocolAndFallback) { | |
| 8536 session_deps_.use_alternate_protocols = true; | |
| 8537 | |
| 8538 HttpRequestInfo request; | |
| 8539 request.method = "GET"; | |
| 8540 request.url = GURL("http://www.google.com/"); | |
| 8541 request.load_flags = 0; | |
| 8542 | |
| 8543 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 8544 StaticSocketDataProvider first_data; | |
| 8545 first_data.set_connect_data(mock_connect); | |
| 8546 session_deps_.socket_factory->AddSocketDataProvider(&first_data); | |
| 8547 | |
| 8548 MockRead data_reads[] = { | |
| 8549 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 8550 MockRead("hello world"), | |
| 8551 MockRead(ASYNC, OK), | |
| 8552 }; | |
| 8553 StaticSocketDataProvider second_data( | |
| 8554 data_reads, arraysize(data_reads), NULL, 0); | |
| 8555 session_deps_.socket_factory->AddSocketDataProvider(&second_data); | |
| 8556 | |
| 8557 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8558 | |
| 8559 base::WeakPtr<HttpServerProperties> http_server_properties = | |
| 8560 session->http_server_properties(); | |
| 8561 // Port must be < 1024, or the header will be ignored (since initial port was | |
| 8562 // port 80 (another restricted port). | |
| 8563 http_server_properties->SetAlternateProtocol( | |
| 8564 HostPortPair::FromURL(request.url), | |
| 8565 666 /* port is ignored by MockConnect anyway */, | |
| 8566 AlternateProtocolFromNextProto(GetParam()), 1.0); | |
| 8567 | |
| 8568 scoped_ptr<HttpTransaction> trans( | |
| 8569 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8570 TestCompletionCallback callback; | |
| 8571 | |
| 8572 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8573 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8574 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8575 | |
| 8576 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8577 ASSERT_TRUE(response != NULL); | |
| 8578 ASSERT_TRUE(response->headers.get() != NULL); | |
| 8579 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 8580 | |
| 8581 std::string response_data; | |
| 8582 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 8583 EXPECT_EQ("hello world", response_data); | |
| 8584 | |
| 8585 const AlternateProtocolInfo alternate = | |
| 8586 http_server_properties->GetAlternateProtocol( | |
| 8587 HostPortPair::FromURL(request.url)); | |
| 8588 EXPECT_NE(UNINITIALIZED_ALTERNATE_PROTOCOL, alternate.protocol); | |
| 8589 EXPECT_TRUE(alternate.is_broken); | |
| 8590 } | |
| 8591 | |
| 8592 TEST_P(HttpNetworkTransactionTest, | |
| 8593 AlternateProtocolPortRestrictedBlocked) { | |
| 8594 // Ensure that we're not allowed to redirect traffic via an alternate | |
| 8595 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
| 8596 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
| 8597 // other cases. | |
| 8598 session_deps_.use_alternate_protocols = true; | |
| 8599 | |
| 8600 HttpRequestInfo restricted_port_request; | |
| 8601 restricted_port_request.method = "GET"; | |
| 8602 restricted_port_request.url = GURL("http://www.google.com:1023/"); | |
| 8603 restricted_port_request.load_flags = 0; | |
| 8604 | |
| 8605 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 8606 StaticSocketDataProvider first_data; | |
| 8607 first_data.set_connect_data(mock_connect); | |
| 8608 session_deps_.socket_factory->AddSocketDataProvider(&first_data); | |
| 8609 | |
| 8610 MockRead data_reads[] = { | |
| 8611 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 8612 MockRead("hello world"), | |
| 8613 MockRead(ASYNC, OK), | |
| 8614 }; | |
| 8615 StaticSocketDataProvider second_data( | |
| 8616 data_reads, arraysize(data_reads), NULL, 0); | |
| 8617 session_deps_.socket_factory->AddSocketDataProvider(&second_data); | |
| 8618 | |
| 8619 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8620 | |
| 8621 base::WeakPtr<HttpServerProperties> http_server_properties = | |
| 8622 session->http_server_properties(); | |
| 8623 const int kUnrestrictedAlternatePort = 1024; | |
| 8624 http_server_properties->SetAlternateProtocol( | |
| 8625 HostPortPair::FromURL(restricted_port_request.url), | |
| 8626 kUnrestrictedAlternatePort, AlternateProtocolFromNextProto(GetParam()), | |
| 8627 1.0); | |
| 8628 | |
| 8629 scoped_ptr<HttpTransaction> trans( | |
| 8630 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8631 TestCompletionCallback callback; | |
| 8632 | |
| 8633 int rv = trans->Start( | |
| 8634 &restricted_port_request, | |
| 8635 callback.callback(), BoundNetLog()); | |
| 8636 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8637 // Invalid change to unrestricted port should fail. | |
| 8638 EXPECT_EQ(ERR_CONNECTION_REFUSED, callback.WaitForResult()); | |
| 8639 } | |
| 8640 | |
| 8641 TEST_P(HttpNetworkTransactionTest, | |
| 8642 AlternateProtocolPortRestrictedPermitted) { | |
| 8643 // Ensure that we're allowed to redirect traffic via an alternate | |
| 8644 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
| 8645 // on a restricted port (port < 1024) if we set | |
| 8646 // enable_user_alternate_protocol_ports. | |
| 8647 | |
| 8648 session_deps_.use_alternate_protocols = true; | |
| 8649 session_deps_.enable_user_alternate_protocol_ports = true; | |
| 8650 | |
| 8651 HttpRequestInfo restricted_port_request; | |
| 8652 restricted_port_request.method = "GET"; | |
| 8653 restricted_port_request.url = GURL("http://www.google.com:1023/"); | |
| 8654 restricted_port_request.load_flags = 0; | |
| 8655 | |
| 8656 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 8657 StaticSocketDataProvider first_data; | |
| 8658 first_data.set_connect_data(mock_connect); | |
| 8659 session_deps_.socket_factory->AddSocketDataProvider(&first_data); | |
| 8660 | |
| 8661 MockRead data_reads[] = { | |
| 8662 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 8663 MockRead("hello world"), | |
| 8664 MockRead(ASYNC, OK), | |
| 8665 }; | |
| 8666 StaticSocketDataProvider second_data( | |
| 8667 data_reads, arraysize(data_reads), NULL, 0); | |
| 8668 session_deps_.socket_factory->AddSocketDataProvider(&second_data); | |
| 8669 | |
| 8670 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8671 | |
| 8672 base::WeakPtr<HttpServerProperties> http_server_properties = | |
| 8673 session->http_server_properties(); | |
| 8674 const int kUnrestrictedAlternatePort = 1024; | |
| 8675 http_server_properties->SetAlternateProtocol( | |
| 8676 HostPortPair::FromURL(restricted_port_request.url), | |
| 8677 kUnrestrictedAlternatePort, AlternateProtocolFromNextProto(GetParam()), | |
| 8678 1.0); | |
| 8679 | |
| 8680 scoped_ptr<HttpTransaction> trans( | |
| 8681 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8682 TestCompletionCallback callback; | |
| 8683 | |
| 8684 EXPECT_EQ(ERR_IO_PENDING, trans->Start( | |
| 8685 &restricted_port_request, | |
| 8686 callback.callback(), BoundNetLog())); | |
| 8687 // Change to unrestricted port should succeed. | |
| 8688 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8689 } | |
| 8690 | |
| 8691 TEST_P(HttpNetworkTransactionTest, | |
| 8692 AlternateProtocolPortRestrictedAllowed) { | |
| 8693 // Ensure that we're not allowed to redirect traffic via an alternate | |
| 8694 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
| 8695 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
| 8696 // other cases. | |
| 8697 session_deps_.use_alternate_protocols = true; | |
| 8698 | |
| 8699 HttpRequestInfo restricted_port_request; | |
| 8700 restricted_port_request.method = "GET"; | |
| 8701 restricted_port_request.url = GURL("http://www.google.com:1023/"); | |
| 8702 restricted_port_request.load_flags = 0; | |
| 8703 | |
| 8704 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 8705 StaticSocketDataProvider first_data; | |
| 8706 first_data.set_connect_data(mock_connect); | |
| 8707 session_deps_.socket_factory->AddSocketDataProvider(&first_data); | |
| 8708 | |
| 8709 MockRead data_reads[] = { | |
| 8710 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 8711 MockRead("hello world"), | |
| 8712 MockRead(ASYNC, OK), | |
| 8713 }; | |
| 8714 StaticSocketDataProvider second_data( | |
| 8715 data_reads, arraysize(data_reads), NULL, 0); | |
| 8716 session_deps_.socket_factory->AddSocketDataProvider(&second_data); | |
| 8717 | |
| 8718 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8719 | |
| 8720 base::WeakPtr<HttpServerProperties> http_server_properties = | |
| 8721 session->http_server_properties(); | |
| 8722 const int kRestrictedAlternatePort = 80; | |
| 8723 http_server_properties->SetAlternateProtocol( | |
| 8724 HostPortPair::FromURL(restricted_port_request.url), | |
| 8725 kRestrictedAlternatePort, AlternateProtocolFromNextProto(GetParam()), | |
| 8726 1.0); | |
| 8727 | |
| 8728 scoped_ptr<HttpTransaction> trans( | |
| 8729 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8730 TestCompletionCallback callback; | |
| 8731 | |
| 8732 int rv = trans->Start( | |
| 8733 &restricted_port_request, | |
| 8734 callback.callback(), BoundNetLog()); | |
| 8735 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8736 // Valid change to restricted port should pass. | |
| 8737 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8738 } | |
| 8739 | |
| 8740 TEST_P(HttpNetworkTransactionTest, | |
| 8741 AlternateProtocolPortUnrestrictedAllowed1) { | |
| 8742 // Ensure that we're not allowed to redirect traffic via an alternate | |
| 8743 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
| 8744 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
| 8745 // other cases. | |
| 8746 session_deps_.use_alternate_protocols = true; | |
| 8747 | |
| 8748 HttpRequestInfo unrestricted_port_request; | |
| 8749 unrestricted_port_request.method = "GET"; | |
| 8750 unrestricted_port_request.url = GURL("http://www.google.com:1024/"); | |
| 8751 unrestricted_port_request.load_flags = 0; | |
| 8752 | |
| 8753 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 8754 StaticSocketDataProvider first_data; | |
| 8755 first_data.set_connect_data(mock_connect); | |
| 8756 session_deps_.socket_factory->AddSocketDataProvider(&first_data); | |
| 8757 | |
| 8758 MockRead data_reads[] = { | |
| 8759 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 8760 MockRead("hello world"), | |
| 8761 MockRead(ASYNC, OK), | |
| 8762 }; | |
| 8763 StaticSocketDataProvider second_data( | |
| 8764 data_reads, arraysize(data_reads), NULL, 0); | |
| 8765 session_deps_.socket_factory->AddSocketDataProvider(&second_data); | |
| 8766 | |
| 8767 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8768 | |
| 8769 base::WeakPtr<HttpServerProperties> http_server_properties = | |
| 8770 session->http_server_properties(); | |
| 8771 const int kRestrictedAlternatePort = 80; | |
| 8772 http_server_properties->SetAlternateProtocol( | |
| 8773 HostPortPair::FromURL(unrestricted_port_request.url), | |
| 8774 kRestrictedAlternatePort, AlternateProtocolFromNextProto(GetParam()), | |
| 8775 1.0); | |
| 8776 | |
| 8777 scoped_ptr<HttpTransaction> trans( | |
| 8778 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8779 TestCompletionCallback callback; | |
| 8780 | |
| 8781 int rv = trans->Start( | |
| 8782 &unrestricted_port_request, callback.callback(), BoundNetLog()); | |
| 8783 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8784 // Valid change to restricted port should pass. | |
| 8785 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8786 } | |
| 8787 | |
| 8788 TEST_P(HttpNetworkTransactionTest, | |
| 8789 AlternateProtocolPortUnrestrictedAllowed2) { | |
| 8790 // Ensure that we're not allowed to redirect traffic via an alternate | |
| 8791 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
| 8792 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
| 8793 // other cases. | |
| 8794 session_deps_.use_alternate_protocols = true; | |
| 8795 | |
| 8796 HttpRequestInfo unrestricted_port_request; | |
| 8797 unrestricted_port_request.method = "GET"; | |
| 8798 unrestricted_port_request.url = GURL("http://www.google.com:1024/"); | |
| 8799 unrestricted_port_request.load_flags = 0; | |
| 8800 | |
| 8801 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 8802 StaticSocketDataProvider first_data; | |
| 8803 first_data.set_connect_data(mock_connect); | |
| 8804 session_deps_.socket_factory->AddSocketDataProvider(&first_data); | |
| 8805 | |
| 8806 MockRead data_reads[] = { | |
| 8807 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 8808 MockRead("hello world"), | |
| 8809 MockRead(ASYNC, OK), | |
| 8810 }; | |
| 8811 StaticSocketDataProvider second_data( | |
| 8812 data_reads, arraysize(data_reads), NULL, 0); | |
| 8813 session_deps_.socket_factory->AddSocketDataProvider(&second_data); | |
| 8814 | |
| 8815 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8816 | |
| 8817 base::WeakPtr<HttpServerProperties> http_server_properties = | |
| 8818 session->http_server_properties(); | |
| 8819 const int kUnrestrictedAlternatePort = 1024; | |
| 8820 http_server_properties->SetAlternateProtocol( | |
| 8821 HostPortPair::FromURL(unrestricted_port_request.url), | |
| 8822 kUnrestrictedAlternatePort, AlternateProtocolFromNextProto(GetParam()), | |
| 8823 1.0); | |
| 8824 | |
| 8825 scoped_ptr<HttpTransaction> trans( | |
| 8826 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8827 TestCompletionCallback callback; | |
| 8828 | |
| 8829 int rv = trans->Start( | |
| 8830 &unrestricted_port_request, callback.callback(), BoundNetLog()); | |
| 8831 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8832 // Valid change to an unrestricted port should pass. | |
| 8833 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8834 } | |
| 8835 | |
| 8836 TEST_P(HttpNetworkTransactionTest, AlternateProtocolUnsafeBlocked) { | |
| 8837 // Ensure that we're not allowed to redirect traffic via an alternate | |
| 8838 // protocol to an unsafe port, and that we resume the second | |
| 8839 // HttpStreamFactoryImpl::Job once the alternate protocol request fails. | |
| 8840 session_deps_.use_alternate_protocols = true; | |
| 8841 | |
| 8842 HttpRequestInfo request; | |
| 8843 request.method = "GET"; | |
| 8844 request.url = GURL("http://www.google.com/"); | |
| 8845 request.load_flags = 0; | |
| 8846 | |
| 8847 // The alternate protocol request will error out before we attempt to connect, | |
| 8848 // so only the standard HTTP request will try to connect. | |
| 8849 MockRead data_reads[] = { | |
| 8850 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 8851 MockRead("hello world"), | |
| 8852 MockRead(ASYNC, OK), | |
| 8853 }; | |
| 8854 StaticSocketDataProvider data( | |
| 8855 data_reads, arraysize(data_reads), NULL, 0); | |
| 8856 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 8857 | |
| 8858 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8859 | |
| 8860 base::WeakPtr<HttpServerProperties> http_server_properties = | |
| 8861 session->http_server_properties(); | |
| 8862 const int kUnsafePort = 7; | |
| 8863 http_server_properties->SetAlternateProtocol( | |
| 8864 HostPortPair::FromURL(request.url), kUnsafePort, | |
| 8865 AlternateProtocolFromNextProto(GetParam()), 1.0); | |
| 8866 | |
| 8867 scoped_ptr<HttpTransaction> trans( | |
| 8868 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8869 TestCompletionCallback callback; | |
| 8870 | |
| 8871 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8872 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8873 // The HTTP request should succeed. | |
| 8874 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8875 | |
| 8876 // Disable alternate protocol before the asserts. | |
| 8877 // HttpStreamFactory::set_use_alternate_protocols(false); | |
| 8878 | |
| 8879 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8880 ASSERT_TRUE(response != NULL); | |
| 8881 ASSERT_TRUE(response->headers.get() != NULL); | |
| 8882 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 8883 | |
| 8884 std::string response_data; | |
| 8885 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 8886 EXPECT_EQ("hello world", response_data); | |
| 8887 } | |
| 8888 | |
| 8889 TEST_P(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) { | |
| 8890 session_deps_.use_alternate_protocols = true; | |
| 8891 session_deps_.next_protos = SpdyNextProtos(); | |
| 8892 | |
| 8893 HttpRequestInfo request; | |
| 8894 request.method = "GET"; | |
| 8895 request.url = GURL("http://www.google.com/"); | |
| 8896 request.load_flags = 0; | |
| 8897 | |
| 8898 std::string alternate_protocol_http_header = | |
| 8899 GetAlternateProtocolHttpHeader(); | |
| 8900 | |
| 8901 MockRead data_reads[] = { | |
| 8902 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 8903 MockRead(alternate_protocol_http_header.c_str()), | |
| 8904 MockRead("hello world"), | |
| 8905 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 8906 MockRead(ASYNC, OK) | |
| 8907 }; | |
| 8908 | |
| 8909 StaticSocketDataProvider first_transaction( | |
| 8910 data_reads, arraysize(data_reads), NULL, 0); | |
| 8911 session_deps_.socket_factory->AddSocketDataProvider(&first_transaction); | |
| 8912 | |
| 8913 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 8914 ssl.SetNextProto(GetParam()); | |
| 8915 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 8916 | |
| 8917 scoped_ptr<SpdyFrame> req( | |
| 8918 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
| 8919 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
| 8920 | |
| 8921 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 8922 scoped_ptr<SpdyFrame> data(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 8923 MockRead spdy_reads[] = { | |
| 8924 CreateMockRead(*resp), | |
| 8925 CreateMockRead(*data), | |
| 8926 MockRead(ASYNC, 0, 0), | |
| 8927 }; | |
| 8928 | |
| 8929 DelayedSocketData spdy_data( | |
| 8930 1, // wait for one write to finish before reading. | |
| 8931 spdy_reads, arraysize(spdy_reads), | |
| 8932 spdy_writes, arraysize(spdy_writes)); | |
| 8933 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 8934 | |
| 8935 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
| 8936 StaticSocketDataProvider hanging_non_alternate_protocol_socket( | |
| 8937 NULL, 0, NULL, 0); | |
| 8938 hanging_non_alternate_protocol_socket.set_connect_data( | |
| 8939 never_finishing_connect); | |
| 8940 session_deps_.socket_factory->AddSocketDataProvider( | |
| 8941 &hanging_non_alternate_protocol_socket); | |
| 8942 | |
| 8943 TestCompletionCallback callback; | |
| 8944 | |
| 8945 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 8946 scoped_ptr<HttpTransaction> trans( | |
| 8947 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8948 | |
| 8949 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8950 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8951 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8952 | |
| 8953 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8954 ASSERT_TRUE(response != NULL); | |
| 8955 ASSERT_TRUE(response->headers.get() != NULL); | |
| 8956 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 8957 | |
| 8958 std::string response_data; | |
| 8959 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 8960 EXPECT_EQ("hello world", response_data); | |
| 8961 | |
| 8962 trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 8963 | |
| 8964 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8965 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8966 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8967 | |
| 8968 response = trans->GetResponseInfo(); | |
| 8969 ASSERT_TRUE(response != NULL); | |
| 8970 ASSERT_TRUE(response->headers.get() != NULL); | |
| 8971 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 8972 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 8973 EXPECT_TRUE(response->was_npn_negotiated); | |
| 8974 | |
| 8975 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 8976 EXPECT_EQ("hello!", response_data); | |
| 8977 } | |
| 8978 | |
| 8979 TEST_P(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) { | |
| 8980 session_deps_.use_alternate_protocols = true; | |
| 8981 session_deps_.next_protos = SpdyNextProtos(); | |
| 8982 | |
| 8983 HttpRequestInfo request; | |
| 8984 request.method = "GET"; | |
| 8985 request.url = GURL("http://www.google.com/"); | |
| 8986 request.load_flags = 0; | |
| 8987 | |
| 8988 std::string alternate_protocol_http_header = | |
| 8989 GetAlternateProtocolHttpHeader(); | |
| 8990 | |
| 8991 MockRead data_reads[] = { | |
| 8992 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 8993 MockRead(alternate_protocol_http_header.c_str()), | |
| 8994 MockRead("hello world"), | |
| 8995 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 8996 MockRead(ASYNC, OK), | |
| 8997 }; | |
| 8998 | |
| 8999 StaticSocketDataProvider first_transaction( | |
| 9000 data_reads, arraysize(data_reads), NULL, 0); | |
| 9001 // Socket 1 is the HTTP transaction with the Alternate-Protocol header. | |
| 9002 session_deps_.socket_factory->AddSocketDataProvider(&first_transaction); | |
| 9003 | |
| 9004 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
| 9005 StaticSocketDataProvider hanging_socket( | |
| 9006 NULL, 0, NULL, 0); | |
| 9007 hanging_socket.set_connect_data(never_finishing_connect); | |
| 9008 // Socket 2 and 3 are the hanging Alternate-Protocol and | |
| 9009 // non-Alternate-Protocol jobs from the 2nd transaction. | |
| 9010 session_deps_.socket_factory->AddSocketDataProvider(&hanging_socket); | |
| 9011 session_deps_.socket_factory->AddSocketDataProvider(&hanging_socket); | |
| 9012 | |
| 9013 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 9014 ssl.SetNextProto(GetParam()); | |
| 9015 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 9016 | |
| 9017 scoped_ptr<SpdyFrame> req1( | |
| 9018 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
| 9019 scoped_ptr<SpdyFrame> req2( | |
| 9020 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); | |
| 9021 MockWrite spdy_writes[] = { | |
| 9022 CreateMockWrite(*req1), | |
| 9023 CreateMockWrite(*req2), | |
| 9024 }; | |
| 9025 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 9026 scoped_ptr<SpdyFrame> data1(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 9027 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 9028 scoped_ptr<SpdyFrame> data2(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
| 9029 MockRead spdy_reads[] = { | |
| 9030 CreateMockRead(*resp1), | |
| 9031 CreateMockRead(*data1), | |
| 9032 CreateMockRead(*resp2), | |
| 9033 CreateMockRead(*data2), | |
| 9034 MockRead(ASYNC, 0, 0), | |
| 9035 }; | |
| 9036 | |
| 9037 DelayedSocketData spdy_data( | |
| 9038 2, // wait for writes to finish before reading. | |
| 9039 spdy_reads, arraysize(spdy_reads), | |
| 9040 spdy_writes, arraysize(spdy_writes)); | |
| 9041 // Socket 4 is the successful Alternate-Protocol for transaction 3. | |
| 9042 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 9043 | |
| 9044 // Socket 5 is the unsuccessful non-Alternate-Protocol for transaction 3. | |
| 9045 session_deps_.socket_factory->AddSocketDataProvider(&hanging_socket); | |
| 9046 | |
| 9047 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 9048 TestCompletionCallback callback1; | |
| 9049 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get()); | |
| 9050 | |
| 9051 int rv = trans1.Start(&request, callback1.callback(), BoundNetLog()); | |
| 9052 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9053 EXPECT_EQ(OK, callback1.WaitForResult()); | |
| 9054 | |
| 9055 const HttpResponseInfo* response = trans1.GetResponseInfo(); | |
| 9056 ASSERT_TRUE(response != NULL); | |
| 9057 ASSERT_TRUE(response->headers.get() != NULL); | |
| 9058 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9059 | |
| 9060 std::string response_data; | |
| 9061 ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); | |
| 9062 EXPECT_EQ("hello world", response_data); | |
| 9063 | |
| 9064 TestCompletionCallback callback2; | |
| 9065 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get()); | |
| 9066 rv = trans2.Start(&request, callback2.callback(), BoundNetLog()); | |
| 9067 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9068 | |
| 9069 TestCompletionCallback callback3; | |
| 9070 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, session.get()); | |
| 9071 rv = trans3.Start(&request, callback3.callback(), BoundNetLog()); | |
| 9072 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9073 | |
| 9074 EXPECT_EQ(OK, callback2.WaitForResult()); | |
| 9075 EXPECT_EQ(OK, callback3.WaitForResult()); | |
| 9076 | |
| 9077 response = trans2.GetResponseInfo(); | |
| 9078 ASSERT_TRUE(response != NULL); | |
| 9079 ASSERT_TRUE(response->headers.get() != NULL); | |
| 9080 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9081 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 9082 EXPECT_TRUE(response->was_npn_negotiated); | |
| 9083 ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); | |
| 9084 EXPECT_EQ("hello!", response_data); | |
| 9085 | |
| 9086 response = trans3.GetResponseInfo(); | |
| 9087 ASSERT_TRUE(response != NULL); | |
| 9088 ASSERT_TRUE(response->headers.get() != NULL); | |
| 9089 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9090 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 9091 EXPECT_TRUE(response->was_npn_negotiated); | |
| 9092 ASSERT_EQ(OK, ReadTransaction(&trans3, &response_data)); | |
| 9093 EXPECT_EQ("hello!", response_data); | |
| 9094 } | |
| 9095 | |
| 9096 TEST_P(HttpNetworkTransactionTest, StallAlternateProtocolForNpnSpdy) { | |
| 9097 session_deps_.use_alternate_protocols = true; | |
| 9098 session_deps_.next_protos = SpdyNextProtos(); | |
| 9099 | |
| 9100 HttpRequestInfo request; | |
| 9101 request.method = "GET"; | |
| 9102 request.url = GURL("http://www.google.com/"); | |
| 9103 request.load_flags = 0; | |
| 9104 | |
| 9105 std::string alternate_protocol_http_header = | |
| 9106 GetAlternateProtocolHttpHeader(); | |
| 9107 | |
| 9108 MockRead data_reads[] = { | |
| 9109 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 9110 MockRead(alternate_protocol_http_header.c_str()), | |
| 9111 MockRead("hello world"), | |
| 9112 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 9113 MockRead(ASYNC, OK), | |
| 9114 }; | |
| 9115 | |
| 9116 StaticSocketDataProvider first_transaction( | |
| 9117 data_reads, arraysize(data_reads), NULL, 0); | |
| 9118 session_deps_.socket_factory->AddSocketDataProvider(&first_transaction); | |
| 9119 | |
| 9120 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 9121 ssl.SetNextProto(GetParam()); | |
| 9122 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 9123 | |
| 9124 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
| 9125 StaticSocketDataProvider hanging_alternate_protocol_socket( | |
| 9126 NULL, 0, NULL, 0); | |
| 9127 hanging_alternate_protocol_socket.set_connect_data( | |
| 9128 never_finishing_connect); | |
| 9129 session_deps_.socket_factory->AddSocketDataProvider( | |
| 9130 &hanging_alternate_protocol_socket); | |
| 9131 | |
| 9132 // 2nd request is just a copy of the first one, over HTTP again. | |
| 9133 session_deps_.socket_factory->AddSocketDataProvider(&first_transaction); | |
| 9134 | |
| 9135 TestCompletionCallback callback; | |
| 9136 | |
| 9137 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 9138 scoped_ptr<HttpTransaction> trans( | |
| 9139 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 9140 | |
| 9141 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 9142 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9143 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 9144 | |
| 9145 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 9146 ASSERT_TRUE(response != NULL); | |
| 9147 ASSERT_TRUE(response->headers.get() != NULL); | |
| 9148 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9149 | |
| 9150 std::string response_data; | |
| 9151 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 9152 EXPECT_EQ("hello world", response_data); | |
| 9153 | |
| 9154 trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 9155 | |
| 9156 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 9157 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9158 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 9159 | |
| 9160 response = trans->GetResponseInfo(); | |
| 9161 ASSERT_TRUE(response != NULL); | |
| 9162 ASSERT_TRUE(response->headers.get() != NULL); | |
| 9163 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9164 EXPECT_FALSE(response->was_fetched_via_spdy); | |
| 9165 EXPECT_FALSE(response->was_npn_negotiated); | |
| 9166 | |
| 9167 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 9168 EXPECT_EQ("hello world", response_data); | |
| 9169 } | |
| 9170 | |
| 9171 class CapturingProxyResolver : public ProxyResolver { | |
| 9172 public: | |
| 9173 CapturingProxyResolver() : ProxyResolver(false /* expects_pac_bytes */) {} | |
| 9174 ~CapturingProxyResolver() override {} | |
| 9175 | |
| 9176 int GetProxyForURL(const GURL& url, | |
| 9177 ProxyInfo* results, | |
| 9178 const CompletionCallback& callback, | |
| 9179 RequestHandle* request, | |
| 9180 const BoundNetLog& net_log) override { | |
| 9181 ProxyServer proxy_server(ProxyServer::SCHEME_HTTP, | |
| 9182 HostPortPair("myproxy", 80)); | |
| 9183 results->UseProxyServer(proxy_server); | |
| 9184 resolved_.push_back(url); | |
| 9185 return OK; | |
| 9186 } | |
| 9187 | |
| 9188 void CancelRequest(RequestHandle request) override { NOTREACHED(); } | |
| 9189 | |
| 9190 LoadState GetLoadState(RequestHandle request) const override { | |
| 9191 NOTREACHED(); | |
| 9192 return LOAD_STATE_IDLE; | |
| 9193 } | |
| 9194 | |
| 9195 void CancelSetPacScript() override { NOTREACHED(); } | |
| 9196 | |
| 9197 int SetPacScript(const scoped_refptr<ProxyResolverScriptData>&, | |
| 9198 const CompletionCallback& /*callback*/) override { | |
| 9199 return OK; | |
| 9200 } | |
| 9201 | |
| 9202 const std::vector<GURL>& resolved() const { return resolved_; } | |
| 9203 | |
| 9204 private: | |
| 9205 std::vector<GURL> resolved_; | |
| 9206 | |
| 9207 DISALLOW_COPY_AND_ASSIGN(CapturingProxyResolver); | |
| 9208 }; | |
| 9209 | |
| 9210 TEST_P(HttpNetworkTransactionTest, | |
| 9211 UseAlternateProtocolForTunneledNpnSpdy) { | |
| 9212 session_deps_.use_alternate_protocols = true; | |
| 9213 session_deps_.next_protos = SpdyNextProtos(); | |
| 9214 | |
| 9215 ProxyConfig proxy_config; | |
| 9216 proxy_config.set_auto_detect(true); | |
| 9217 proxy_config.set_pac_url(GURL("http://fooproxyurl")); | |
| 9218 | |
| 9219 CapturingProxyResolver* capturing_proxy_resolver = | |
| 9220 new CapturingProxyResolver(); | |
| 9221 session_deps_.proxy_service.reset(new ProxyService( | |
| 9222 new ProxyConfigServiceFixed(proxy_config), capturing_proxy_resolver, | |
| 9223 NULL)); | |
| 9224 CapturingNetLog net_log; | |
| 9225 session_deps_.net_log = &net_log; | |
| 9226 | |
| 9227 HttpRequestInfo request; | |
| 9228 request.method = "GET"; | |
| 9229 request.url = GURL("http://www.google.com/"); | |
| 9230 request.load_flags = 0; | |
| 9231 | |
| 9232 std::string alternate_protocol_http_header = | |
| 9233 GetAlternateProtocolHttpHeader(); | |
| 9234 | |
| 9235 MockRead data_reads[] = { | |
| 9236 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 9237 MockRead(alternate_protocol_http_header.c_str()), | |
| 9238 MockRead("hello world"), | |
| 9239 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 9240 MockRead(ASYNC, OK), | |
| 9241 }; | |
| 9242 | |
| 9243 StaticSocketDataProvider first_transaction( | |
| 9244 data_reads, arraysize(data_reads), NULL, 0); | |
| 9245 session_deps_.socket_factory->AddSocketDataProvider(&first_transaction); | |
| 9246 | |
| 9247 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 9248 ssl.SetNextProto(GetParam()); | |
| 9249 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 9250 | |
| 9251 scoped_ptr<SpdyFrame> req( | |
| 9252 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
| 9253 MockWrite spdy_writes[] = { | |
| 9254 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 9255 "Host: www.google.com\r\n" | |
| 9256 "Proxy-Connection: keep-alive\r\n\r\n"), // 0 | |
| 9257 CreateMockWrite(*req), // 3 | |
| 9258 }; | |
| 9259 | |
| 9260 const char kCONNECTResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; | |
| 9261 | |
| 9262 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 9263 scoped_ptr<SpdyFrame> data(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 9264 MockRead spdy_reads[] = { | |
| 9265 MockRead(ASYNC, kCONNECTResponse, arraysize(kCONNECTResponse) - 1, 1), // 1 | |
| 9266 CreateMockRead(*resp.get(), 4), // 2, 4 | |
| 9267 CreateMockRead(*data.get(), 4), // 5 | |
| 9268 MockRead(ASYNC, 0, 0, 4), // 6 | |
| 9269 }; | |
| 9270 | |
| 9271 OrderedSocketData spdy_data( | |
| 9272 spdy_reads, arraysize(spdy_reads), | |
| 9273 spdy_writes, arraysize(spdy_writes)); | |
| 9274 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 9275 | |
| 9276 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
| 9277 StaticSocketDataProvider hanging_non_alternate_protocol_socket( | |
| 9278 NULL, 0, NULL, 0); | |
| 9279 hanging_non_alternate_protocol_socket.set_connect_data( | |
| 9280 never_finishing_connect); | |
| 9281 session_deps_.socket_factory->AddSocketDataProvider( | |
| 9282 &hanging_non_alternate_protocol_socket); | |
| 9283 | |
| 9284 TestCompletionCallback callback; | |
| 9285 | |
| 9286 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 9287 scoped_ptr<HttpTransaction> trans( | |
| 9288 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 9289 | |
| 9290 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 9291 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9292 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 9293 | |
| 9294 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 9295 ASSERT_TRUE(response != NULL); | |
| 9296 ASSERT_TRUE(response->headers.get() != NULL); | |
| 9297 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9298 EXPECT_FALSE(response->was_fetched_via_spdy); | |
| 9299 EXPECT_FALSE(response->was_npn_negotiated); | |
| 9300 | |
| 9301 std::string response_data; | |
| 9302 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 9303 EXPECT_EQ("hello world", response_data); | |
| 9304 | |
| 9305 trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 9306 | |
| 9307 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 9308 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9309 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 9310 | |
| 9311 response = trans->GetResponseInfo(); | |
| 9312 ASSERT_TRUE(response != NULL); | |
| 9313 ASSERT_TRUE(response->headers.get() != NULL); | |
| 9314 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9315 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 9316 EXPECT_TRUE(response->was_npn_negotiated); | |
| 9317 | |
| 9318 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 9319 EXPECT_EQ("hello!", response_data); | |
| 9320 ASSERT_EQ(3u, capturing_proxy_resolver->resolved().size()); | |
| 9321 EXPECT_EQ("http://www.google.com/", | |
| 9322 capturing_proxy_resolver->resolved()[0].spec()); | |
| 9323 EXPECT_EQ("https://www.google.com/", | |
| 9324 capturing_proxy_resolver->resolved()[1].spec()); | |
| 9325 | |
| 9326 LoadTimingInfo load_timing_info; | |
| 9327 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 9328 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 9329 CONNECT_TIMING_HAS_SSL_TIMES); | |
| 9330 } | |
| 9331 | |
| 9332 TEST_P(HttpNetworkTransactionTest, | |
| 9333 UseAlternateProtocolForNpnSpdyWithExistingSpdySession) { | |
| 9334 session_deps_.use_alternate_protocols = true; | |
| 9335 session_deps_.next_protos = SpdyNextProtos(); | |
| 9336 | |
| 9337 HttpRequestInfo request; | |
| 9338 request.method = "GET"; | |
| 9339 request.url = GURL("http://www.google.com/"); | |
| 9340 request.load_flags = 0; | |
| 9341 | |
| 9342 std::string alternate_protocol_http_header = | |
| 9343 GetAlternateProtocolHttpHeader(); | |
| 9344 | |
| 9345 MockRead data_reads[] = { | |
| 9346 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 9347 MockRead(alternate_protocol_http_header.c_str()), | |
| 9348 MockRead("hello world"), | |
| 9349 MockRead(ASYNC, OK), | |
| 9350 }; | |
| 9351 | |
| 9352 StaticSocketDataProvider first_transaction( | |
| 9353 data_reads, arraysize(data_reads), NULL, 0); | |
| 9354 session_deps_.socket_factory->AddSocketDataProvider(&first_transaction); | |
| 9355 | |
| 9356 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 9357 ssl.SetNextProto(GetParam()); | |
| 9358 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 9359 | |
| 9360 scoped_ptr<SpdyFrame> req( | |
| 9361 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
| 9362 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
| 9363 | |
| 9364 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 9365 scoped_ptr<SpdyFrame> data(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 9366 MockRead spdy_reads[] = { | |
| 9367 CreateMockRead(*resp), | |
| 9368 CreateMockRead(*data), | |
| 9369 MockRead(ASYNC, 0, 0), | |
| 9370 }; | |
| 9371 | |
| 9372 DelayedSocketData spdy_data( | |
| 9373 1, // wait for one write to finish before reading. | |
| 9374 spdy_reads, arraysize(spdy_reads), | |
| 9375 spdy_writes, arraysize(spdy_writes)); | |
| 9376 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 9377 | |
| 9378 TestCompletionCallback callback; | |
| 9379 | |
| 9380 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 9381 | |
| 9382 scoped_ptr<HttpTransaction> trans( | |
| 9383 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 9384 | |
| 9385 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 9386 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9387 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 9388 | |
| 9389 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 9390 ASSERT_TRUE(response != NULL); | |
| 9391 ASSERT_TRUE(response->headers.get() != NULL); | |
| 9392 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9393 | |
| 9394 std::string response_data; | |
| 9395 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 9396 EXPECT_EQ("hello world", response_data); | |
| 9397 | |
| 9398 // Set up an initial SpdySession in the pool to reuse. | |
| 9399 HostPortPair host_port_pair("www.google.com", 443); | |
| 9400 SpdySessionKey key(host_port_pair, ProxyServer::Direct(), | |
| 9401 PRIVACY_MODE_DISABLED); | |
| 9402 base::WeakPtr<SpdySession> spdy_session = | |
| 9403 CreateSecureSpdySession(session, key, BoundNetLog()); | |
| 9404 | |
| 9405 trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 9406 | |
| 9407 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 9408 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9409 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 9410 | |
| 9411 response = trans->GetResponseInfo(); | |
| 9412 ASSERT_TRUE(response != NULL); | |
| 9413 ASSERT_TRUE(response->headers.get() != NULL); | |
| 9414 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9415 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 9416 EXPECT_TRUE(response->was_npn_negotiated); | |
| 9417 | |
| 9418 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 9419 EXPECT_EQ("hello!", response_data); | |
| 9420 } | |
| 9421 | |
| 9422 // GenerateAuthToken is a mighty big test. | |
| 9423 // It tests all permutation of GenerateAuthToken behavior: | |
| 9424 // - Synchronous and Asynchronous completion. | |
| 9425 // - OK or error on completion. | |
| 9426 // - Direct connection, non-authenticating proxy, and authenticating proxy. | |
| 9427 // - HTTP or HTTPS backend (to include proxy tunneling). | |
| 9428 // - Non-authenticating and authenticating backend. | |
| 9429 // | |
| 9430 // In all, there are 44 reasonable permuations (for example, if there are | |
| 9431 // problems generating an auth token for an authenticating proxy, we don't | |
| 9432 // need to test all permutations of the backend server). | |
| 9433 // | |
| 9434 // The test proceeds by going over each of the configuration cases, and | |
| 9435 // potentially running up to three rounds in each of the tests. The TestConfig | |
| 9436 // specifies both the configuration for the test as well as the expectations | |
| 9437 // for the results. | |
| 9438 TEST_P(HttpNetworkTransactionTest, GenerateAuthToken) { | |
| 9439 static const char kServer[] = "http://www.example.com"; | |
| 9440 static const char kSecureServer[] = "https://www.example.com"; | |
| 9441 static const char kProxy[] = "myproxy:70"; | |
| 9442 const int kAuthErr = ERR_INVALID_AUTH_CREDENTIALS; | |
| 9443 | |
| 9444 enum AuthTiming { | |
| 9445 AUTH_NONE, | |
| 9446 AUTH_SYNC, | |
| 9447 AUTH_ASYNC, | |
| 9448 }; | |
| 9449 | |
| 9450 const MockWrite kGet( | |
| 9451 "GET / HTTP/1.1\r\n" | |
| 9452 "Host: www.example.com\r\n" | |
| 9453 "Connection: keep-alive\r\n\r\n"); | |
| 9454 const MockWrite kGetProxy( | |
| 9455 "GET http://www.example.com/ HTTP/1.1\r\n" | |
| 9456 "Host: www.example.com\r\n" | |
| 9457 "Proxy-Connection: keep-alive\r\n\r\n"); | |
| 9458 const MockWrite kGetAuth( | |
| 9459 "GET / HTTP/1.1\r\n" | |
| 9460 "Host: www.example.com\r\n" | |
| 9461 "Connection: keep-alive\r\n" | |
| 9462 "Authorization: auth_token\r\n\r\n"); | |
| 9463 const MockWrite kGetProxyAuth( | |
| 9464 "GET http://www.example.com/ HTTP/1.1\r\n" | |
| 9465 "Host: www.example.com\r\n" | |
| 9466 "Proxy-Connection: keep-alive\r\n" | |
| 9467 "Proxy-Authorization: auth_token\r\n\r\n"); | |
| 9468 const MockWrite kGetAuthThroughProxy( | |
| 9469 "GET http://www.example.com/ HTTP/1.1\r\n" | |
| 9470 "Host: www.example.com\r\n" | |
| 9471 "Proxy-Connection: keep-alive\r\n" | |
| 9472 "Authorization: auth_token\r\n\r\n"); | |
| 9473 const MockWrite kGetAuthWithProxyAuth( | |
| 9474 "GET http://www.example.com/ HTTP/1.1\r\n" | |
| 9475 "Host: www.example.com\r\n" | |
| 9476 "Proxy-Connection: keep-alive\r\n" | |
| 9477 "Proxy-Authorization: auth_token\r\n" | |
| 9478 "Authorization: auth_token\r\n\r\n"); | |
| 9479 const MockWrite kConnect( | |
| 9480 "CONNECT www.example.com:443 HTTP/1.1\r\n" | |
| 9481 "Host: www.example.com\r\n" | |
| 9482 "Proxy-Connection: keep-alive\r\n\r\n"); | |
| 9483 const MockWrite kConnectProxyAuth( | |
| 9484 "CONNECT www.example.com:443 HTTP/1.1\r\n" | |
| 9485 "Host: www.example.com\r\n" | |
| 9486 "Proxy-Connection: keep-alive\r\n" | |
| 9487 "Proxy-Authorization: auth_token\r\n\r\n"); | |
| 9488 | |
| 9489 const MockRead kSuccess( | |
| 9490 "HTTP/1.1 200 OK\r\n" | |
| 9491 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 9492 "Content-Length: 3\r\n\r\n" | |
| 9493 "Yes"); | |
| 9494 const MockRead kFailure( | |
| 9495 "Should not be called."); | |
| 9496 const MockRead kServerChallenge( | |
| 9497 "HTTP/1.1 401 Unauthorized\r\n" | |
| 9498 "WWW-Authenticate: Mock realm=server\r\n" | |
| 9499 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 9500 "Content-Length: 14\r\n\r\n" | |
| 9501 "Unauthorized\r\n"); | |
| 9502 const MockRead kProxyChallenge( | |
| 9503 "HTTP/1.1 407 Unauthorized\r\n" | |
| 9504 "Proxy-Authenticate: Mock realm=proxy\r\n" | |
| 9505 "Proxy-Connection: close\r\n" | |
| 9506 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 9507 "Content-Length: 14\r\n\r\n" | |
| 9508 "Unauthorized\r\n"); | |
| 9509 const MockRead kProxyConnected( | |
| 9510 "HTTP/1.1 200 Connection Established\r\n\r\n"); | |
| 9511 | |
| 9512 // NOTE(cbentzel): I wanted TestReadWriteRound to be a simple struct with | |
| 9513 // no constructors, but the C++ compiler on Windows warns about | |
| 9514 // unspecified data in compound literals. So, moved to using constructors, | |
| 9515 // and TestRound's created with the default constructor should not be used. | |
| 9516 struct TestRound { | |
| 9517 TestRound() | |
| 9518 : expected_rv(ERR_UNEXPECTED), | |
| 9519 extra_write(NULL), | |
| 9520 extra_read(NULL) { | |
| 9521 } | |
| 9522 TestRound(const MockWrite& write_arg, const MockRead& read_arg, | |
| 9523 int expected_rv_arg) | |
| 9524 : write(write_arg), | |
| 9525 read(read_arg), | |
| 9526 expected_rv(expected_rv_arg), | |
| 9527 extra_write(NULL), | |
| 9528 extra_read(NULL) { | |
| 9529 } | |
| 9530 TestRound(const MockWrite& write_arg, const MockRead& read_arg, | |
| 9531 int expected_rv_arg, const MockWrite* extra_write_arg, | |
| 9532 const MockRead* extra_read_arg) | |
| 9533 : write(write_arg), | |
| 9534 read(read_arg), | |
| 9535 expected_rv(expected_rv_arg), | |
| 9536 extra_write(extra_write_arg), | |
| 9537 extra_read(extra_read_arg) { | |
| 9538 } | |
| 9539 MockWrite write; | |
| 9540 MockRead read; | |
| 9541 int expected_rv; | |
| 9542 const MockWrite* extra_write; | |
| 9543 const MockRead* extra_read; | |
| 9544 }; | |
| 9545 | |
| 9546 static const int kNoSSL = 500; | |
| 9547 | |
| 9548 struct TestConfig { | |
| 9549 const char* const proxy_url; | |
| 9550 AuthTiming proxy_auth_timing; | |
| 9551 int proxy_auth_rv; | |
| 9552 const char* const server_url; | |
| 9553 AuthTiming server_auth_timing; | |
| 9554 int server_auth_rv; | |
| 9555 int num_auth_rounds; | |
| 9556 int first_ssl_round; | |
| 9557 TestRound rounds[3]; | |
| 9558 } test_configs[] = { | |
| 9559 // Non-authenticating HTTP server with a direct connection. | |
| 9560 { NULL, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL, | |
| 9561 { TestRound(kGet, kSuccess, OK)}}, | |
| 9562 // Authenticating HTTP server with a direct connection. | |
| 9563 { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL, | |
| 9564 { TestRound(kGet, kServerChallenge, OK), | |
| 9565 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 9566 { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL, | |
| 9567 { TestRound(kGet, kServerChallenge, OK), | |
| 9568 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 9569 { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL, | |
| 9570 { TestRound(kGet, kServerChallenge, OK), | |
| 9571 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 9572 { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL, | |
| 9573 { TestRound(kGet, kServerChallenge, OK), | |
| 9574 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 9575 // Non-authenticating HTTP server through a non-authenticating proxy. | |
| 9576 { kProxy, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL, | |
| 9577 { TestRound(kGetProxy, kSuccess, OK)}}, | |
| 9578 // Authenticating HTTP server through a non-authenticating proxy. | |
| 9579 { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL, | |
| 9580 { TestRound(kGetProxy, kServerChallenge, OK), | |
| 9581 TestRound(kGetAuthThroughProxy, kSuccess, OK)}}, | |
| 9582 { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL, | |
| 9583 { TestRound(kGetProxy, kServerChallenge, OK), | |
| 9584 TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}}, | |
| 9585 { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL, | |
| 9586 { TestRound(kGetProxy, kServerChallenge, OK), | |
| 9587 TestRound(kGetAuthThroughProxy, kSuccess, OK)}}, | |
| 9588 { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL, | |
| 9589 { TestRound(kGetProxy, kServerChallenge, OK), | |
| 9590 TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}}, | |
| 9591 // Non-authenticating HTTP server through an authenticating proxy. | |
| 9592 { kProxy, AUTH_SYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 9593 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9594 TestRound(kGetProxyAuth, kSuccess, OK)}}, | |
| 9595 { kProxy, AUTH_SYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 9596 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9597 TestRound(kGetProxyAuth, kFailure, kAuthErr)}}, | |
| 9598 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 9599 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9600 TestRound(kGetProxyAuth, kSuccess, OK)}}, | |
| 9601 { kProxy, AUTH_ASYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 9602 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9603 TestRound(kGetProxyAuth, kFailure, kAuthErr)}}, | |
| 9604 // Authenticating HTTP server through an authenticating proxy. | |
| 9605 { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL, | |
| 9606 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9607 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 9608 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
| 9609 { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL, | |
| 9610 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9611 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 9612 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
| 9613 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL, | |
| 9614 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9615 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 9616 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
| 9617 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL, | |
| 9618 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9619 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 9620 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
| 9621 { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL, | |
| 9622 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9623 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 9624 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
| 9625 { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL, | |
| 9626 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9627 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 9628 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
| 9629 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL, | |
| 9630 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9631 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 9632 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
| 9633 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL, | |
| 9634 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 9635 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 9636 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
| 9637 // Non-authenticating HTTPS server with a direct connection. | |
| 9638 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0, | |
| 9639 { TestRound(kGet, kSuccess, OK)}}, | |
| 9640 // Authenticating HTTPS server with a direct connection. | |
| 9641 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0, | |
| 9642 { TestRound(kGet, kServerChallenge, OK), | |
| 9643 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 9644 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0, | |
| 9645 { TestRound(kGet, kServerChallenge, OK), | |
| 9646 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 9647 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0, | |
| 9648 { TestRound(kGet, kServerChallenge, OK), | |
| 9649 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 9650 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0, | |
| 9651 { TestRound(kGet, kServerChallenge, OK), | |
| 9652 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 9653 // Non-authenticating HTTPS server with a non-authenticating proxy. | |
| 9654 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0, | |
| 9655 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}}, | |
| 9656 // Authenticating HTTPS server through a non-authenticating proxy. | |
| 9657 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0, | |
| 9658 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
| 9659 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 9660 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0, | |
| 9661 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
| 9662 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 9663 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0, | |
| 9664 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
| 9665 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 9666 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0, | |
| 9667 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
| 9668 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 9669 // Non-Authenticating HTTPS server through an authenticating proxy. | |
| 9670 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1, | |
| 9671 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9672 TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}}, | |
| 9673 { kProxy, AUTH_SYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 9674 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9675 TestRound(kConnectProxyAuth, kFailure, kAuthErr)}}, | |
| 9676 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1, | |
| 9677 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9678 TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}}, | |
| 9679 { kProxy, AUTH_ASYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 9680 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9681 TestRound(kConnectProxyAuth, kFailure, kAuthErr)}}, | |
| 9682 // Authenticating HTTPS server through an authenticating proxy. | |
| 9683 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1, | |
| 9684 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9685 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 9686 &kGet, &kServerChallenge), | |
| 9687 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 9688 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1, | |
| 9689 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9690 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 9691 &kGet, &kServerChallenge), | |
| 9692 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 9693 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1, | |
| 9694 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9695 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 9696 &kGet, &kServerChallenge), | |
| 9697 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 9698 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1, | |
| 9699 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9700 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 9701 &kGet, &kServerChallenge), | |
| 9702 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 9703 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1, | |
| 9704 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9705 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 9706 &kGet, &kServerChallenge), | |
| 9707 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 9708 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1, | |
| 9709 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9710 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 9711 &kGet, &kServerChallenge), | |
| 9712 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 9713 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1, | |
| 9714 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9715 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 9716 &kGet, &kServerChallenge), | |
| 9717 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 9718 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1, | |
| 9719 { TestRound(kConnect, kProxyChallenge, OK), | |
| 9720 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 9721 &kGet, &kServerChallenge), | |
| 9722 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 9723 }; | |
| 9724 | |
| 9725 for (size_t i = 0; i < arraysize(test_configs); ++i) { | |
| 9726 HttpAuthHandlerMock::Factory* auth_factory( | |
| 9727 new HttpAuthHandlerMock::Factory()); | |
| 9728 session_deps_.http_auth_handler_factory.reset(auth_factory); | |
| 9729 const TestConfig& test_config = test_configs[i]; | |
| 9730 | |
| 9731 // Set up authentication handlers as necessary. | |
| 9732 if (test_config.proxy_auth_timing != AUTH_NONE) { | |
| 9733 for (int n = 0; n < 2; n++) { | |
| 9734 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); | |
| 9735 std::string auth_challenge = "Mock realm=proxy"; | |
| 9736 GURL origin(test_config.proxy_url); | |
| 9737 HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(), | |
| 9738 auth_challenge.end()); | |
| 9739 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_PROXY, | |
| 9740 origin, BoundNetLog()); | |
| 9741 auth_handler->SetGenerateExpectation( | |
| 9742 test_config.proxy_auth_timing == AUTH_ASYNC, | |
| 9743 test_config.proxy_auth_rv); | |
| 9744 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); | |
| 9745 } | |
| 9746 } | |
| 9747 if (test_config.server_auth_timing != AUTH_NONE) { | |
| 9748 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); | |
| 9749 std::string auth_challenge = "Mock realm=server"; | |
| 9750 GURL origin(test_config.server_url); | |
| 9751 HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(), | |
| 9752 auth_challenge.end()); | |
| 9753 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER, | |
| 9754 origin, BoundNetLog()); | |
| 9755 auth_handler->SetGenerateExpectation( | |
| 9756 test_config.server_auth_timing == AUTH_ASYNC, | |
| 9757 test_config.server_auth_rv); | |
| 9758 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER); | |
| 9759 } | |
| 9760 if (test_config.proxy_url) { | |
| 9761 session_deps_.proxy_service.reset( | |
| 9762 ProxyService::CreateFixed(test_config.proxy_url)); | |
| 9763 } else { | |
| 9764 session_deps_.proxy_service.reset(ProxyService::CreateDirect()); | |
| 9765 } | |
| 9766 | |
| 9767 HttpRequestInfo request; | |
| 9768 request.method = "GET"; | |
| 9769 request.url = GURL(test_config.server_url); | |
| 9770 request.load_flags = 0; | |
| 9771 | |
| 9772 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 9773 HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get()); | |
| 9774 | |
| 9775 for (int round = 0; round < test_config.num_auth_rounds; ++round) { | |
| 9776 const TestRound& read_write_round = test_config.rounds[round]; | |
| 9777 | |
| 9778 // Set up expected reads and writes. | |
| 9779 MockRead reads[2]; | |
| 9780 reads[0] = read_write_round.read; | |
| 9781 size_t length_reads = 1; | |
| 9782 if (read_write_round.extra_read) { | |
| 9783 reads[1] = *read_write_round.extra_read; | |
| 9784 length_reads = 2; | |
| 9785 } | |
| 9786 | |
| 9787 MockWrite writes[2]; | |
| 9788 writes[0] = read_write_round.write; | |
| 9789 size_t length_writes = 1; | |
| 9790 if (read_write_round.extra_write) { | |
| 9791 writes[1] = *read_write_round.extra_write; | |
| 9792 length_writes = 2; | |
| 9793 } | |
| 9794 StaticSocketDataProvider data_provider( | |
| 9795 reads, length_reads, writes, length_writes); | |
| 9796 session_deps_.socket_factory->AddSocketDataProvider(&data_provider); | |
| 9797 | |
| 9798 // Add an SSL sequence if necessary. | |
| 9799 SSLSocketDataProvider ssl_socket_data_provider(SYNCHRONOUS, OK); | |
| 9800 if (round >= test_config.first_ssl_round) | |
| 9801 session_deps_.socket_factory->AddSSLSocketDataProvider( | |
| 9802 &ssl_socket_data_provider); | |
| 9803 | |
| 9804 // Start or restart the transaction. | |
| 9805 TestCompletionCallback callback; | |
| 9806 int rv; | |
| 9807 if (round == 0) { | |
| 9808 rv = trans.Start(&request, callback.callback(), BoundNetLog()); | |
| 9809 } else { | |
| 9810 rv = trans.RestartWithAuth( | |
| 9811 AuthCredentials(kFoo, kBar), callback.callback()); | |
| 9812 } | |
| 9813 if (rv == ERR_IO_PENDING) | |
| 9814 rv = callback.WaitForResult(); | |
| 9815 | |
| 9816 // Compare results with expected data. | |
| 9817 EXPECT_EQ(read_write_round.expected_rv, rv); | |
| 9818 const HttpResponseInfo* response = trans.GetResponseInfo(); | |
| 9819 if (read_write_round.expected_rv == OK) { | |
| 9820 ASSERT_TRUE(response != NULL); | |
| 9821 } else { | |
| 9822 EXPECT_TRUE(response == NULL); | |
| 9823 EXPECT_EQ(round + 1, test_config.num_auth_rounds); | |
| 9824 continue; | |
| 9825 } | |
| 9826 if (round + 1 < test_config.num_auth_rounds) { | |
| 9827 EXPECT_FALSE(response->auth_challenge.get() == NULL); | |
| 9828 } else { | |
| 9829 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 9830 } | |
| 9831 } | |
| 9832 } | |
| 9833 } | |
| 9834 | |
| 9835 TEST_P(HttpNetworkTransactionTest, MultiRoundAuth) { | |
| 9836 // Do multi-round authentication and make sure it works correctly. | |
| 9837 HttpAuthHandlerMock::Factory* auth_factory( | |
| 9838 new HttpAuthHandlerMock::Factory()); | |
| 9839 session_deps_.http_auth_handler_factory.reset(auth_factory); | |
| 9840 session_deps_.proxy_service.reset(ProxyService::CreateDirect()); | |
| 9841 session_deps_.host_resolver->rules()->AddRule("www.example.com", "10.0.0.1"); | |
| 9842 session_deps_.host_resolver->set_synchronous_mode(true); | |
| 9843 | |
| 9844 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); | |
| 9845 auth_handler->set_connection_based(true); | |
| 9846 std::string auth_challenge = "Mock realm=server"; | |
| 9847 GURL origin("http://www.example.com"); | |
| 9848 HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(), | |
| 9849 auth_challenge.end()); | |
| 9850 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER, | |
| 9851 origin, BoundNetLog()); | |
| 9852 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER); | |
| 9853 | |
| 9854 int rv = OK; | |
| 9855 const HttpResponseInfo* response = NULL; | |
| 9856 HttpRequestInfo request; | |
| 9857 request.method = "GET"; | |
| 9858 request.url = origin; | |
| 9859 request.load_flags = 0; | |
| 9860 | |
| 9861 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 9862 | |
| 9863 // Use a TCP Socket Pool with only one connection per group. This is used | |
| 9864 // to validate that the TCP socket is not released to the pool between | |
| 9865 // each round of multi-round authentication. | |
| 9866 HttpNetworkSessionPeer session_peer(session); | |
| 9867 ClientSocketPoolHistograms transport_pool_histograms("SmallTCP"); | |
| 9868 TransportClientSocketPool* transport_pool = new TransportClientSocketPool( | |
| 9869 50, // Max sockets for pool | |
| 9870 1, // Max sockets per group | |
| 9871 &transport_pool_histograms, | |
| 9872 session_deps_.host_resolver.get(), | |
| 9873 session_deps_.socket_factory.get(), | |
| 9874 session_deps_.net_log); | |
| 9875 scoped_ptr<MockClientSocketPoolManager> mock_pool_manager( | |
| 9876 new MockClientSocketPoolManager); | |
| 9877 mock_pool_manager->SetTransportSocketPool(transport_pool); | |
| 9878 session_peer.SetClientSocketPoolManager(mock_pool_manager.Pass()); | |
| 9879 | |
| 9880 scoped_ptr<HttpTransaction> trans( | |
| 9881 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 9882 TestCompletionCallback callback; | |
| 9883 | |
| 9884 const MockWrite kGet( | |
| 9885 "GET / HTTP/1.1\r\n" | |
| 9886 "Host: www.example.com\r\n" | |
| 9887 "Connection: keep-alive\r\n\r\n"); | |
| 9888 const MockWrite kGetAuth( | |
| 9889 "GET / HTTP/1.1\r\n" | |
| 9890 "Host: www.example.com\r\n" | |
| 9891 "Connection: keep-alive\r\n" | |
| 9892 "Authorization: auth_token\r\n\r\n"); | |
| 9893 | |
| 9894 const MockRead kServerChallenge( | |
| 9895 "HTTP/1.1 401 Unauthorized\r\n" | |
| 9896 "WWW-Authenticate: Mock realm=server\r\n" | |
| 9897 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 9898 "Content-Length: 14\r\n\r\n" | |
| 9899 "Unauthorized\r\n"); | |
| 9900 const MockRead kSuccess( | |
| 9901 "HTTP/1.1 200 OK\r\n" | |
| 9902 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 9903 "Content-Length: 3\r\n\r\n" | |
| 9904 "Yes"); | |
| 9905 | |
| 9906 MockWrite writes[] = { | |
| 9907 // First round | |
| 9908 kGet, | |
| 9909 // Second round | |
| 9910 kGetAuth, | |
| 9911 // Third round | |
| 9912 kGetAuth, | |
| 9913 // Fourth round | |
| 9914 kGetAuth, | |
| 9915 // Competing request | |
| 9916 kGet, | |
| 9917 }; | |
| 9918 MockRead reads[] = { | |
| 9919 // First round | |
| 9920 kServerChallenge, | |
| 9921 // Second round | |
| 9922 kServerChallenge, | |
| 9923 // Third round | |
| 9924 kServerChallenge, | |
| 9925 // Fourth round | |
| 9926 kSuccess, | |
| 9927 // Competing response | |
| 9928 kSuccess, | |
| 9929 }; | |
| 9930 StaticSocketDataProvider data_provider(reads, arraysize(reads), | |
| 9931 writes, arraysize(writes)); | |
| 9932 session_deps_.socket_factory->AddSocketDataProvider(&data_provider); | |
| 9933 | |
| 9934 const char kSocketGroup[] = "www.example.com:80"; | |
| 9935 | |
| 9936 // First round of authentication. | |
| 9937 auth_handler->SetGenerateExpectation(false, OK); | |
| 9938 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 9939 if (rv == ERR_IO_PENDING) | |
| 9940 rv = callback.WaitForResult(); | |
| 9941 EXPECT_EQ(OK, rv); | |
| 9942 response = trans->GetResponseInfo(); | |
| 9943 ASSERT_TRUE(response != NULL); | |
| 9944 EXPECT_FALSE(response->auth_challenge.get() == NULL); | |
| 9945 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 9946 | |
| 9947 // In between rounds, another request comes in for the same domain. | |
| 9948 // It should not be able to grab the TCP socket that trans has already | |
| 9949 // claimed. | |
| 9950 scoped_ptr<HttpTransaction> trans_compete( | |
| 9951 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 9952 TestCompletionCallback callback_compete; | |
| 9953 rv = trans_compete->Start( | |
| 9954 &request, callback_compete.callback(), BoundNetLog()); | |
| 9955 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9956 // callback_compete.WaitForResult at this point would stall forever, | |
| 9957 // since the HttpNetworkTransaction does not release the request back to | |
| 9958 // the pool until after authentication completes. | |
| 9959 | |
| 9960 // Second round of authentication. | |
| 9961 auth_handler->SetGenerateExpectation(false, OK); | |
| 9962 rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback()); | |
| 9963 if (rv == ERR_IO_PENDING) | |
| 9964 rv = callback.WaitForResult(); | |
| 9965 EXPECT_EQ(OK, rv); | |
| 9966 response = trans->GetResponseInfo(); | |
| 9967 ASSERT_TRUE(response != NULL); | |
| 9968 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 9969 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 9970 | |
| 9971 // Third round of authentication. | |
| 9972 auth_handler->SetGenerateExpectation(false, OK); | |
| 9973 rv = trans->RestartWithAuth(AuthCredentials(), callback.callback()); | |
| 9974 if (rv == ERR_IO_PENDING) | |
| 9975 rv = callback.WaitForResult(); | |
| 9976 EXPECT_EQ(OK, rv); | |
| 9977 response = trans->GetResponseInfo(); | |
| 9978 ASSERT_TRUE(response != NULL); | |
| 9979 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 9980 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 9981 | |
| 9982 // Fourth round of authentication, which completes successfully. | |
| 9983 auth_handler->SetGenerateExpectation(false, OK); | |
| 9984 rv = trans->RestartWithAuth(AuthCredentials(), callback.callback()); | |
| 9985 if (rv == ERR_IO_PENDING) | |
| 9986 rv = callback.WaitForResult(); | |
| 9987 EXPECT_EQ(OK, rv); | |
| 9988 response = trans->GetResponseInfo(); | |
| 9989 ASSERT_TRUE(response != NULL); | |
| 9990 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 9991 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 9992 | |
| 9993 // Read the body since the fourth round was successful. This will also | |
| 9994 // release the socket back to the pool. | |
| 9995 scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(50)); | |
| 9996 rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback()); | |
| 9997 if (rv == ERR_IO_PENDING) | |
| 9998 rv = callback.WaitForResult(); | |
| 9999 EXPECT_EQ(3, rv); | |
| 10000 rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback()); | |
| 10001 EXPECT_EQ(0, rv); | |
| 10002 // There are still 0 idle sockets, since the trans_compete transaction | |
| 10003 // will be handed it immediately after trans releases it to the group. | |
| 10004 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 10005 | |
| 10006 // The competing request can now finish. Wait for the headers and then | |
| 10007 // read the body. | |
| 10008 rv = callback_compete.WaitForResult(); | |
| 10009 EXPECT_EQ(OK, rv); | |
| 10010 rv = trans_compete->Read(io_buf.get(), io_buf->size(), callback.callback()); | |
| 10011 if (rv == ERR_IO_PENDING) | |
| 10012 rv = callback.WaitForResult(); | |
| 10013 EXPECT_EQ(3, rv); | |
| 10014 rv = trans_compete->Read(io_buf.get(), io_buf->size(), callback.callback()); | |
| 10015 EXPECT_EQ(0, rv); | |
| 10016 | |
| 10017 // Finally, the socket is released to the group. | |
| 10018 EXPECT_EQ(1, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 10019 } | |
| 10020 | |
| 10021 // This tests the case that a request is issued via http instead of spdy after | |
| 10022 // npn is negotiated. | |
| 10023 TEST_P(HttpNetworkTransactionTest, NpnWithHttpOverSSL) { | |
| 10024 session_deps_.use_alternate_protocols = true; | |
| 10025 NextProtoVector next_protos; | |
| 10026 next_protos.push_back(kProtoHTTP11); | |
| 10027 session_deps_.next_protos = next_protos; | |
| 10028 | |
| 10029 HttpRequestInfo request; | |
| 10030 request.method = "GET"; | |
| 10031 request.url = GURL("https://www.google.com/"); | |
| 10032 request.load_flags = 0; | |
| 10033 | |
| 10034 MockWrite data_writes[] = { | |
| 10035 MockWrite("GET / HTTP/1.1\r\n" | |
| 10036 "Host: www.google.com\r\n" | |
| 10037 "Connection: keep-alive\r\n\r\n"), | |
| 10038 }; | |
| 10039 | |
| 10040 std::string alternate_protocol_http_header = | |
| 10041 GetAlternateProtocolHttpHeader(); | |
| 10042 | |
| 10043 MockRead data_reads[] = { | |
| 10044 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 10045 MockRead(alternate_protocol_http_header.c_str()), | |
| 10046 MockRead("hello world"), | |
| 10047 MockRead(SYNCHRONOUS, OK), | |
| 10048 }; | |
| 10049 | |
| 10050 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 10051 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; | |
| 10052 ssl.next_proto = "http/1.1"; | |
| 10053 ssl.protocol_negotiated = kProtoHTTP11; | |
| 10054 | |
| 10055 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 10056 | |
| 10057 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 10058 data_writes, arraysize(data_writes)); | |
| 10059 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 10060 | |
| 10061 TestCompletionCallback callback; | |
| 10062 | |
| 10063 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10064 scoped_ptr<HttpTransaction> trans( | |
| 10065 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10066 | |
| 10067 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 10068 | |
| 10069 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 10070 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 10071 | |
| 10072 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 10073 ASSERT_TRUE(response != NULL); | |
| 10074 ASSERT_TRUE(response->headers.get() != NULL); | |
| 10075 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 10076 | |
| 10077 std::string response_data; | |
| 10078 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 10079 EXPECT_EQ("hello world", response_data); | |
| 10080 | |
| 10081 EXPECT_FALSE(response->was_fetched_via_spdy); | |
| 10082 EXPECT_TRUE(response->was_npn_negotiated); | |
| 10083 } | |
| 10084 | |
| 10085 TEST_P(HttpNetworkTransactionTest, SpdyPostNPNServerHangup) { | |
| 10086 // Simulate the SSL handshake completing with an NPN negotiation | |
| 10087 // followed by an immediate server closing of the socket. | |
| 10088 // Fix crash: http://crbug.com/46369 | |
| 10089 session_deps_.use_alternate_protocols = true; | |
| 10090 session_deps_.next_protos = SpdyNextProtos(); | |
| 10091 | |
| 10092 HttpRequestInfo request; | |
| 10093 request.method = "GET"; | |
| 10094 request.url = GURL("https://www.google.com/"); | |
| 10095 request.load_flags = 0; | |
| 10096 | |
| 10097 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 10098 ssl.SetNextProto(GetParam()); | |
| 10099 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 10100 | |
| 10101 scoped_ptr<SpdyFrame> req( | |
| 10102 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
| 10103 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
| 10104 | |
| 10105 MockRead spdy_reads[] = { | |
| 10106 MockRead(SYNCHRONOUS, 0, 0) // Not async - return 0 immediately. | |
| 10107 }; | |
| 10108 | |
| 10109 DelayedSocketData spdy_data( | |
| 10110 0, // don't wait in this case, immediate hangup. | |
| 10111 spdy_reads, arraysize(spdy_reads), | |
| 10112 spdy_writes, arraysize(spdy_writes)); | |
| 10113 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 10114 | |
| 10115 TestCompletionCallback callback; | |
| 10116 | |
| 10117 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10118 scoped_ptr<HttpTransaction> trans( | |
| 10119 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10120 | |
| 10121 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 10122 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 10123 EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult()); | |
| 10124 } | |
| 10125 | |
| 10126 // A subclass of HttpAuthHandlerMock that records the request URL when | |
| 10127 // it gets it. This is needed since the auth handler may get destroyed | |
| 10128 // before we get a chance to query it. | |
| 10129 class UrlRecordingHttpAuthHandlerMock : public HttpAuthHandlerMock { | |
| 10130 public: | |
| 10131 explicit UrlRecordingHttpAuthHandlerMock(GURL* url) : url_(url) {} | |
| 10132 | |
| 10133 ~UrlRecordingHttpAuthHandlerMock() override {} | |
| 10134 | |
| 10135 protected: | |
| 10136 int GenerateAuthTokenImpl(const AuthCredentials* credentials, | |
| 10137 const HttpRequestInfo* request, | |
| 10138 const CompletionCallback& callback, | |
| 10139 std::string* auth_token) override { | |
| 10140 *url_ = request->url; | |
| 10141 return HttpAuthHandlerMock::GenerateAuthTokenImpl( | |
| 10142 credentials, request, callback, auth_token); | |
| 10143 } | |
| 10144 | |
| 10145 private: | |
| 10146 GURL* url_; | |
| 10147 }; | |
| 10148 | |
| 10149 TEST_P(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) { | |
| 10150 // This test ensures that the URL passed into the proxy is upgraded | |
| 10151 // to https when doing an Alternate Protocol upgrade. | |
| 10152 session_deps_.use_alternate_protocols = true; | |
| 10153 session_deps_.next_protos = SpdyNextProtos(); | |
| 10154 | |
| 10155 session_deps_.proxy_service.reset( | |
| 10156 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); | |
| 10157 CapturingNetLog net_log; | |
| 10158 session_deps_.net_log = &net_log; | |
| 10159 GURL request_url; | |
| 10160 { | |
| 10161 HttpAuthHandlerMock::Factory* auth_factory = | |
| 10162 new HttpAuthHandlerMock::Factory(); | |
| 10163 UrlRecordingHttpAuthHandlerMock* auth_handler = | |
| 10164 new UrlRecordingHttpAuthHandlerMock(&request_url); | |
| 10165 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); | |
| 10166 auth_factory->set_do_init_from_challenge(true); | |
| 10167 session_deps_.http_auth_handler_factory.reset(auth_factory); | |
| 10168 } | |
| 10169 | |
| 10170 HttpRequestInfo request; | |
| 10171 request.method = "GET"; | |
| 10172 request.url = GURL("http://www.google.com"); | |
| 10173 request.load_flags = 0; | |
| 10174 | |
| 10175 // First round goes unauthenticated through the proxy. | |
| 10176 MockWrite data_writes_1[] = { | |
| 10177 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 10178 "Host: www.google.com\r\n" | |
| 10179 "Proxy-Connection: keep-alive\r\n" | |
| 10180 "\r\n"), | |
| 10181 }; | |
| 10182 MockRead data_reads_1[] = { | |
| 10183 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 10184 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 10185 MockRead("Alternate-Protocol: 443:"), | |
| 10186 MockRead(GetAlternateProtocolFromParam()), | |
| 10187 MockRead("\r\n"), | |
| 10188 MockRead("Proxy-Connection: close\r\n"), | |
| 10189 MockRead("\r\n"), | |
| 10190 }; | |
| 10191 StaticSocketDataProvider data_1(data_reads_1, arraysize(data_reads_1), | |
| 10192 data_writes_1, arraysize(data_writes_1)); | |
| 10193 | |
| 10194 // Second round tries to tunnel to www.google.com due to the | |
| 10195 // Alternate-Protocol announcement in the first round. It fails due | |
| 10196 // to a proxy authentication challenge. | |
| 10197 // After the failure, a tunnel is established to www.google.com using | |
| 10198 // Proxy-Authorization headers. There is then a SPDY request round. | |
| 10199 // | |
| 10200 // NOTE: Despite the "Proxy-Connection: Close", these are done on the | |
| 10201 // same MockTCPClientSocket since the underlying HttpNetworkClientSocket | |
| 10202 // does a Disconnect and Connect on the same socket, rather than trying | |
| 10203 // to obtain a new one. | |
| 10204 // | |
| 10205 // NOTE: Originally, the proxy response to the second CONNECT request | |
| 10206 // simply returned another 407 so the unit test could skip the SSL connection | |
| 10207 // establishment and SPDY framing issues. Alas, the | |
| 10208 // retry-http-when-alternate-protocol fails logic kicks in, which was more | |
| 10209 // complicated to set up expectations for than the SPDY session. | |
| 10210 | |
| 10211 scoped_ptr<SpdyFrame> req( | |
| 10212 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
| 10213 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 10214 scoped_ptr<SpdyFrame> data(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 10215 | |
| 10216 MockWrite data_writes_2[] = { | |
| 10217 // First connection attempt without Proxy-Authorization. | |
| 10218 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 10219 "Host: www.google.com\r\n" | |
| 10220 "Proxy-Connection: keep-alive\r\n" | |
| 10221 "\r\n"), | |
| 10222 | |
| 10223 // Second connection attempt with Proxy-Authorization. | |
| 10224 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 10225 "Host: www.google.com\r\n" | |
| 10226 "Proxy-Connection: keep-alive\r\n" | |
| 10227 "Proxy-Authorization: auth_token\r\n" | |
| 10228 "\r\n"), | |
| 10229 | |
| 10230 // SPDY request | |
| 10231 CreateMockWrite(*req), | |
| 10232 }; | |
| 10233 const char kRejectConnectResponse[] = ("HTTP/1.1 407 Unauthorized\r\n" | |
| 10234 "Proxy-Authenticate: Mock\r\n" | |
| 10235 "Proxy-Connection: close\r\n" | |
| 10236 "\r\n"); | |
| 10237 const char kAcceptConnectResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; | |
| 10238 MockRead data_reads_2[] = { | |
| 10239 // First connection attempt fails | |
| 10240 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ, 1), | |
| 10241 MockRead(ASYNC, kRejectConnectResponse, | |
| 10242 arraysize(kRejectConnectResponse) - 1, 1), | |
| 10243 | |
| 10244 // Second connection attempt passes | |
| 10245 MockRead(ASYNC, kAcceptConnectResponse, | |
| 10246 arraysize(kAcceptConnectResponse) -1, 4), | |
| 10247 | |
| 10248 // SPDY response | |
| 10249 CreateMockRead(*resp.get(), 6), | |
| 10250 CreateMockRead(*data.get(), 6), | |
| 10251 MockRead(ASYNC, 0, 0, 6), | |
| 10252 }; | |
| 10253 OrderedSocketData data_2( | |
| 10254 data_reads_2, arraysize(data_reads_2), | |
| 10255 data_writes_2, arraysize(data_writes_2)); | |
| 10256 | |
| 10257 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 10258 ssl.SetNextProto(GetParam()); | |
| 10259 | |
| 10260 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
| 10261 StaticSocketDataProvider hanging_non_alternate_protocol_socket( | |
| 10262 NULL, 0, NULL, 0); | |
| 10263 hanging_non_alternate_protocol_socket.set_connect_data( | |
| 10264 never_finishing_connect); | |
| 10265 | |
| 10266 session_deps_.socket_factory->AddSocketDataProvider(&data_1); | |
| 10267 session_deps_.socket_factory->AddSocketDataProvider(&data_2); | |
| 10268 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 10269 session_deps_.socket_factory->AddSocketDataProvider( | |
| 10270 &hanging_non_alternate_protocol_socket); | |
| 10271 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10272 | |
| 10273 // First round should work and provide the Alternate-Protocol state. | |
| 10274 TestCompletionCallback callback_1; | |
| 10275 scoped_ptr<HttpTransaction> trans_1( | |
| 10276 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10277 int rv = trans_1->Start(&request, callback_1.callback(), BoundNetLog()); | |
| 10278 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 10279 EXPECT_EQ(OK, callback_1.WaitForResult()); | |
| 10280 | |
| 10281 // Second round should attempt a tunnel connect and get an auth challenge. | |
| 10282 TestCompletionCallback callback_2; | |
| 10283 scoped_ptr<HttpTransaction> trans_2( | |
| 10284 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10285 rv = trans_2->Start(&request, callback_2.callback(), BoundNetLog()); | |
| 10286 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 10287 EXPECT_EQ(OK, callback_2.WaitForResult()); | |
| 10288 const HttpResponseInfo* response = trans_2->GetResponseInfo(); | |
| 10289 ASSERT_TRUE(response != NULL); | |
| 10290 ASSERT_FALSE(response->auth_challenge.get() == NULL); | |
| 10291 | |
| 10292 // Restart with auth. Tunnel should work and response received. | |
| 10293 TestCompletionCallback callback_3; | |
| 10294 rv = trans_2->RestartWithAuth( | |
| 10295 AuthCredentials(kFoo, kBar), callback_3.callback()); | |
| 10296 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 10297 EXPECT_EQ(OK, callback_3.WaitForResult()); | |
| 10298 | |
| 10299 // After all that work, these two lines (or actually, just the scheme) are | |
| 10300 // what this test is all about. Make sure it happens correctly. | |
| 10301 EXPECT_EQ("https", request_url.scheme()); | |
| 10302 EXPECT_EQ("www.google.com", request_url.host()); | |
| 10303 | |
| 10304 LoadTimingInfo load_timing_info; | |
| 10305 EXPECT_TRUE(trans_2->GetLoadTimingInfo(&load_timing_info)); | |
| 10306 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 10307 CONNECT_TIMING_HAS_SSL_TIMES); | |
| 10308 } | |
| 10309 | |
| 10310 // Test that if we cancel the transaction as the connection is completing, that | |
| 10311 // everything tears down correctly. | |
| 10312 TEST_P(HttpNetworkTransactionTest, SimpleCancel) { | |
| 10313 // Setup everything about the connection to complete synchronously, so that | |
| 10314 // after calling HttpNetworkTransaction::Start, the only thing we're waiting | |
| 10315 // for is the callback from the HttpStreamRequest. | |
| 10316 // Then cancel the transaction. | |
| 10317 // Verify that we don't crash. | |
| 10318 MockConnect mock_connect(SYNCHRONOUS, OK); | |
| 10319 MockRead data_reads[] = { | |
| 10320 MockRead(SYNCHRONOUS, "HTTP/1.0 200 OK\r\n\r\n"), | |
| 10321 MockRead(SYNCHRONOUS, "hello world"), | |
| 10322 MockRead(SYNCHRONOUS, OK), | |
| 10323 }; | |
| 10324 | |
| 10325 HttpRequestInfo request; | |
| 10326 request.method = "GET"; | |
| 10327 request.url = GURL("http://www.google.com/"); | |
| 10328 request.load_flags = 0; | |
| 10329 | |
| 10330 session_deps_.host_resolver->set_synchronous_mode(true); | |
| 10331 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10332 scoped_ptr<HttpTransaction> trans( | |
| 10333 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10334 | |
| 10335 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 10336 data.set_connect_data(mock_connect); | |
| 10337 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 10338 | |
| 10339 TestCompletionCallback callback; | |
| 10340 | |
| 10341 CapturingBoundNetLog log; | |
| 10342 int rv = trans->Start(&request, callback.callback(), log.bound()); | |
| 10343 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 10344 trans.reset(); // Cancel the transaction here. | |
| 10345 | |
| 10346 base::MessageLoop::current()->RunUntilIdle(); | |
| 10347 } | |
| 10348 | |
| 10349 // Test that if a transaction is cancelled after receiving the headers, the | |
| 10350 // stream is drained properly and added back to the socket pool. The main | |
| 10351 // purpose of this test is to make sure that an HttpStreamParser can be read | |
| 10352 // from after the HttpNetworkTransaction and the objects it owns have been | |
| 10353 // deleted. | |
| 10354 // See http://crbug.com/368418 | |
| 10355 TEST_P(HttpNetworkTransactionTest, CancelAfterHeaders) { | |
| 10356 MockRead data_reads[] = { | |
| 10357 MockRead(ASYNC, "HTTP/1.1 200 OK\r\n"), | |
| 10358 MockRead(ASYNC, "Content-Length: 2\r\n"), | |
| 10359 MockRead(ASYNC, "Connection: Keep-Alive\r\n\r\n"), | |
| 10360 MockRead(ASYNC, "1"), | |
| 10361 // 2 async reads are necessary to trigger a ReadResponseBody call after the | |
| 10362 // HttpNetworkTransaction has been deleted. | |
| 10363 MockRead(ASYNC, "2"), | |
| 10364 MockRead(SYNCHRONOUS, ERR_IO_PENDING), // Should never read this. | |
| 10365 }; | |
| 10366 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 10367 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 10368 | |
| 10369 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10370 | |
| 10371 { | |
| 10372 HttpRequestInfo request; | |
| 10373 request.method = "GET"; | |
| 10374 request.url = GURL("http://www.google.com/"); | |
| 10375 request.load_flags = 0; | |
| 10376 | |
| 10377 HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get()); | |
| 10378 TestCompletionCallback callback; | |
| 10379 | |
| 10380 int rv = trans.Start(&request, callback.callback(), BoundNetLog()); | |
| 10381 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 10382 callback.WaitForResult(); | |
| 10383 | |
| 10384 const HttpResponseInfo* response = trans.GetResponseInfo(); | |
| 10385 ASSERT_TRUE(response != NULL); | |
| 10386 EXPECT_TRUE(response->headers.get() != NULL); | |
| 10387 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 10388 | |
| 10389 // The transaction and HttpRequestInfo are deleted. | |
| 10390 } | |
| 10391 | |
| 10392 // Let the HttpResponseBodyDrainer drain the socket. | |
| 10393 base::MessageLoop::current()->RunUntilIdle(); | |
| 10394 | |
| 10395 // Socket should now be idle, waiting to be reused. | |
| 10396 EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 10397 } | |
| 10398 | |
| 10399 // Test a basic GET request through a proxy. | |
| 10400 TEST_P(HttpNetworkTransactionTest, ProxyGet) { | |
| 10401 session_deps_.proxy_service.reset( | |
| 10402 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); | |
| 10403 CapturingBoundNetLog log; | |
| 10404 session_deps_.net_log = log.bound().net_log(); | |
| 10405 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10406 | |
| 10407 HttpRequestInfo request; | |
| 10408 request.method = "GET"; | |
| 10409 request.url = GURL("http://www.google.com/"); | |
| 10410 | |
| 10411 MockWrite data_writes1[] = { | |
| 10412 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 10413 "Host: www.google.com\r\n" | |
| 10414 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 10415 }; | |
| 10416 | |
| 10417 MockRead data_reads1[] = { | |
| 10418 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 10419 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 10420 MockRead("Content-Length: 100\r\n\r\n"), | |
| 10421 MockRead(SYNCHRONOUS, OK), | |
| 10422 }; | |
| 10423 | |
| 10424 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 10425 data_writes1, arraysize(data_writes1)); | |
| 10426 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 10427 | |
| 10428 TestCompletionCallback callback1; | |
| 10429 | |
| 10430 scoped_ptr<HttpTransaction> trans( | |
| 10431 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10432 BeforeProxyHeadersSentHandler proxy_headers_handler; | |
| 10433 trans->SetBeforeProxyHeadersSentCallback( | |
| 10434 base::Bind(&BeforeProxyHeadersSentHandler::OnBeforeProxyHeadersSent, | |
| 10435 base::Unretained(&proxy_headers_handler))); | |
| 10436 | |
| 10437 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 10438 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 10439 | |
| 10440 rv = callback1.WaitForResult(); | |
| 10441 EXPECT_EQ(OK, rv); | |
| 10442 | |
| 10443 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 10444 ASSERT_TRUE(response != NULL); | |
| 10445 | |
| 10446 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 10447 EXPECT_EQ(200, response->headers->response_code()); | |
| 10448 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 10449 EXPECT_TRUE(response->was_fetched_via_proxy); | |
| 10450 EXPECT_TRUE( | |
| 10451 response->proxy_server.Equals(HostPortPair::FromString("myproxy:70"))); | |
| 10452 EXPECT_TRUE(proxy_headers_handler.observed_before_proxy_headers_sent()); | |
| 10453 EXPECT_EQ("myproxy:70", proxy_headers_handler.observed_proxy_server_uri()); | |
| 10454 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 10455 | |
| 10456 LoadTimingInfo load_timing_info; | |
| 10457 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 10458 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 10459 CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); | |
| 10460 } | |
| 10461 | |
| 10462 // Test a basic HTTPS GET request through a proxy. | |
| 10463 TEST_P(HttpNetworkTransactionTest, ProxyTunnelGet) { | |
| 10464 session_deps_.proxy_service.reset( | |
| 10465 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); | |
| 10466 CapturingBoundNetLog log; | |
| 10467 session_deps_.net_log = log.bound().net_log(); | |
| 10468 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10469 | |
| 10470 HttpRequestInfo request; | |
| 10471 request.method = "GET"; | |
| 10472 request.url = GURL("https://www.google.com/"); | |
| 10473 | |
| 10474 // Since we have proxy, should try to establish tunnel. | |
| 10475 MockWrite data_writes1[] = { | |
| 10476 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 10477 "Host: www.google.com\r\n" | |
| 10478 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 10479 | |
| 10480 MockWrite("GET / HTTP/1.1\r\n" | |
| 10481 "Host: www.google.com\r\n" | |
| 10482 "Connection: keep-alive\r\n\r\n"), | |
| 10483 }; | |
| 10484 | |
| 10485 MockRead data_reads1[] = { | |
| 10486 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 10487 | |
| 10488 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 10489 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 10490 MockRead("Content-Length: 100\r\n\r\n"), | |
| 10491 MockRead(SYNCHRONOUS, OK), | |
| 10492 }; | |
| 10493 | |
| 10494 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 10495 data_writes1, arraysize(data_writes1)); | |
| 10496 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 10497 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 10498 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 10499 | |
| 10500 TestCompletionCallback callback1; | |
| 10501 | |
| 10502 scoped_ptr<HttpTransaction> trans( | |
| 10503 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10504 | |
| 10505 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 10506 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 10507 | |
| 10508 rv = callback1.WaitForResult(); | |
| 10509 EXPECT_EQ(OK, rv); | |
| 10510 net::CapturingNetLog::CapturedEntryList entries; | |
| 10511 log.GetEntries(&entries); | |
| 10512 size_t pos = ExpectLogContainsSomewhere( | |
| 10513 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 10514 NetLog::PHASE_NONE); | |
| 10515 ExpectLogContainsSomewhere( | |
| 10516 entries, pos, | |
| 10517 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 10518 NetLog::PHASE_NONE); | |
| 10519 | |
| 10520 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 10521 ASSERT_TRUE(response != NULL); | |
| 10522 | |
| 10523 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 10524 EXPECT_EQ(200, response->headers->response_code()); | |
| 10525 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 10526 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 10527 EXPECT_TRUE(response->was_fetched_via_proxy); | |
| 10528 EXPECT_TRUE( | |
| 10529 response->proxy_server.Equals(HostPortPair::FromString("myproxy:70"))); | |
| 10530 | |
| 10531 LoadTimingInfo load_timing_info; | |
| 10532 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info)); | |
| 10533 TestLoadTimingNotReusedWithPac(load_timing_info, | |
| 10534 CONNECT_TIMING_HAS_SSL_TIMES); | |
| 10535 } | |
| 10536 | |
| 10537 // Test a basic HTTPS GET request through a proxy, but the server hangs up | |
| 10538 // while establishing the tunnel. | |
| 10539 TEST_P(HttpNetworkTransactionTest, ProxyTunnelGetHangup) { | |
| 10540 session_deps_.proxy_service.reset(ProxyService::CreateFixed("myproxy:70")); | |
| 10541 CapturingBoundNetLog log; | |
| 10542 session_deps_.net_log = log.bound().net_log(); | |
| 10543 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10544 | |
| 10545 HttpRequestInfo request; | |
| 10546 request.method = "GET"; | |
| 10547 request.url = GURL("https://www.google.com/"); | |
| 10548 | |
| 10549 // Since we have proxy, should try to establish tunnel. | |
| 10550 MockWrite data_writes1[] = { | |
| 10551 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 10552 "Host: www.google.com\r\n" | |
| 10553 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 10554 | |
| 10555 MockWrite("GET / HTTP/1.1\r\n" | |
| 10556 "Host: www.google.com\r\n" | |
| 10557 "Connection: keep-alive\r\n\r\n"), | |
| 10558 }; | |
| 10559 | |
| 10560 MockRead data_reads1[] = { | |
| 10561 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 10562 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 10563 MockRead(ASYNC, 0, 0), // EOF | |
| 10564 }; | |
| 10565 | |
| 10566 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 10567 data_writes1, arraysize(data_writes1)); | |
| 10568 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 10569 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 10570 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 10571 | |
| 10572 TestCompletionCallback callback1; | |
| 10573 | |
| 10574 scoped_ptr<HttpTransaction> trans( | |
| 10575 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10576 | |
| 10577 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 10578 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 10579 | |
| 10580 rv = callback1.WaitForResult(); | |
| 10581 EXPECT_EQ(ERR_EMPTY_RESPONSE, rv); | |
| 10582 net::CapturingNetLog::CapturedEntryList entries; | |
| 10583 log.GetEntries(&entries); | |
| 10584 size_t pos = ExpectLogContainsSomewhere( | |
| 10585 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 10586 NetLog::PHASE_NONE); | |
| 10587 ExpectLogContainsSomewhere( | |
| 10588 entries, pos, | |
| 10589 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 10590 NetLog::PHASE_NONE); | |
| 10591 } | |
| 10592 | |
| 10593 // Test for crbug.com/55424. | |
| 10594 TEST_P(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) { | |
| 10595 scoped_ptr<SpdyFrame> req( | |
| 10596 spdy_util_.ConstructSpdyGet("https://www.google.com", false, 1, LOWEST)); | |
| 10597 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
| 10598 | |
| 10599 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 10600 scoped_ptr<SpdyFrame> data(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 10601 MockRead spdy_reads[] = { | |
| 10602 CreateMockRead(*resp), | |
| 10603 CreateMockRead(*data), | |
| 10604 MockRead(ASYNC, 0, 0), | |
| 10605 }; | |
| 10606 | |
| 10607 DelayedSocketData spdy_data( | |
| 10608 1, // wait for one write to finish before reading. | |
| 10609 spdy_reads, arraysize(spdy_reads), | |
| 10610 spdy_writes, arraysize(spdy_writes)); | |
| 10611 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 10612 | |
| 10613 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 10614 ssl.SetNextProto(GetParam()); | |
| 10615 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 10616 | |
| 10617 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10618 | |
| 10619 // Set up an initial SpdySession in the pool to reuse. | |
| 10620 HostPortPair host_port_pair("www.google.com", 443); | |
| 10621 SpdySessionKey key(host_port_pair, ProxyServer::Direct(), | |
| 10622 PRIVACY_MODE_DISABLED); | |
| 10623 base::WeakPtr<SpdySession> spdy_session = | |
| 10624 CreateInsecureSpdySession(session, key, BoundNetLog()); | |
| 10625 | |
| 10626 HttpRequestInfo request; | |
| 10627 request.method = "GET"; | |
| 10628 request.url = GURL("https://www.google.com/"); | |
| 10629 request.load_flags = 0; | |
| 10630 | |
| 10631 // This is the important line that marks this as a preconnect. | |
| 10632 request.motivation = HttpRequestInfo::PRECONNECT_MOTIVATED; | |
| 10633 | |
| 10634 scoped_ptr<HttpTransaction> trans( | |
| 10635 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10636 | |
| 10637 TestCompletionCallback callback; | |
| 10638 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 10639 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 10640 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 10641 } | |
| 10642 | |
| 10643 // Given a net error, cause that error to be returned from the first Write() | |
| 10644 // call and verify that the HttpTransaction fails with that error. | |
| 10645 void HttpNetworkTransactionTest::CheckErrorIsPassedBack( | |
| 10646 int error, IoMode mode) { | |
| 10647 net::HttpRequestInfo request_info; | |
| 10648 request_info.url = GURL("https://www.example.com/"); | |
| 10649 request_info.method = "GET"; | |
| 10650 request_info.load_flags = net::LOAD_NORMAL; | |
| 10651 | |
| 10652 SSLSocketDataProvider ssl_data(mode, OK); | |
| 10653 net::MockWrite data_writes[] = { | |
| 10654 net::MockWrite(mode, error), | |
| 10655 }; | |
| 10656 net::StaticSocketDataProvider data(NULL, 0, | |
| 10657 data_writes, arraysize(data_writes)); | |
| 10658 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 10659 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data); | |
| 10660 | |
| 10661 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10662 scoped_ptr<HttpTransaction> trans( | |
| 10663 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10664 | |
| 10665 TestCompletionCallback callback; | |
| 10666 int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); | |
| 10667 if (rv == net::ERR_IO_PENDING) | |
| 10668 rv = callback.WaitForResult(); | |
| 10669 ASSERT_EQ(error, rv); | |
| 10670 } | |
| 10671 | |
| 10672 TEST_P(HttpNetworkTransactionTest, SSLWriteCertError) { | |
| 10673 // Just check a grab bag of cert errors. | |
| 10674 static const int kErrors[] = { | |
| 10675 ERR_CERT_COMMON_NAME_INVALID, | |
| 10676 ERR_CERT_AUTHORITY_INVALID, | |
| 10677 ERR_CERT_DATE_INVALID, | |
| 10678 }; | |
| 10679 for (size_t i = 0; i < arraysize(kErrors); i++) { | |
| 10680 CheckErrorIsPassedBack(kErrors[i], ASYNC); | |
| 10681 CheckErrorIsPassedBack(kErrors[i], SYNCHRONOUS); | |
| 10682 } | |
| 10683 } | |
| 10684 | |
| 10685 // Ensure that a client certificate is removed from the SSL client auth | |
| 10686 // cache when: | |
| 10687 // 1) No proxy is involved. | |
| 10688 // 2) TLS False Start is disabled. | |
| 10689 // 3) The initial TLS handshake requests a client certificate. | |
| 10690 // 4) The client supplies an invalid/unacceptable certificate. | |
| 10691 TEST_P(HttpNetworkTransactionTest, | |
| 10692 ClientAuthCertCache_Direct_NoFalseStart) { | |
| 10693 net::HttpRequestInfo request_info; | |
| 10694 request_info.url = GURL("https://www.example.com/"); | |
| 10695 request_info.method = "GET"; | |
| 10696 request_info.load_flags = net::LOAD_NORMAL; | |
| 10697 | |
| 10698 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); | |
| 10699 cert_request->host_and_port = HostPortPair("www.example.com", 443); | |
| 10700 | |
| 10701 // [ssl_]data1 contains the data for the first SSL handshake. When a | |
| 10702 // CertificateRequest is received for the first time, the handshake will | |
| 10703 // be aborted to allow the caller to provide a certificate. | |
| 10704 SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); | |
| 10705 ssl_data1.cert_request_info = cert_request.get(); | |
| 10706 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1); | |
| 10707 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); | |
| 10708 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 10709 | |
| 10710 // [ssl_]data2 contains the data for the second SSL handshake. When TLS | |
| 10711 // False Start is not being used, the result of the SSL handshake will be | |
| 10712 // returned as part of the SSLClientSocket::Connect() call. This test | |
| 10713 // matches the result of a server sending a handshake_failure alert, | |
| 10714 // rather than a Finished message, because it requires a client | |
| 10715 // certificate and none was supplied. | |
| 10716 SSLSocketDataProvider ssl_data2(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
| 10717 ssl_data2.cert_request_info = cert_request.get(); | |
| 10718 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data2); | |
| 10719 net::StaticSocketDataProvider data2(NULL, 0, NULL, 0); | |
| 10720 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 10721 | |
| 10722 // [ssl_]data3 contains the data for the third SSL handshake. When a | |
| 10723 // connection to a server fails during an SSL handshake, | |
| 10724 // HttpNetworkTransaction will attempt to fallback to TLSv1 if the previous | |
| 10725 // connection was attempted with TLSv1.1. This is transparent to the caller | |
| 10726 // of the HttpNetworkTransaction. Because this test failure is due to | |
| 10727 // requiring a client certificate, this fallback handshake should also | |
| 10728 // fail. | |
| 10729 SSLSocketDataProvider ssl_data3(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
| 10730 ssl_data3.cert_request_info = cert_request.get(); | |
| 10731 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data3); | |
| 10732 net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); | |
| 10733 session_deps_.socket_factory->AddSocketDataProvider(&data3); | |
| 10734 | |
| 10735 // [ssl_]data4 contains the data for the fourth SSL handshake. When a | |
| 10736 // connection to a server fails during an SSL handshake, | |
| 10737 // HttpNetworkTransaction will attempt to fallback to SSLv3 if the previous | |
| 10738 // connection was attempted with TLSv1. This is transparent to the caller | |
| 10739 // of the HttpNetworkTransaction. Because this test failure is due to | |
| 10740 // requiring a client certificate, this fallback handshake should also | |
| 10741 // fail. | |
| 10742 SSLSocketDataProvider ssl_data4(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
| 10743 ssl_data4.cert_request_info = cert_request.get(); | |
| 10744 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data4); | |
| 10745 net::StaticSocketDataProvider data4(NULL, 0, NULL, 0); | |
| 10746 session_deps_.socket_factory->AddSocketDataProvider(&data4); | |
| 10747 | |
| 10748 // Need one more if TLSv1.2 is enabled. | |
| 10749 SSLSocketDataProvider ssl_data5(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
| 10750 ssl_data5.cert_request_info = cert_request.get(); | |
| 10751 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data5); | |
| 10752 net::StaticSocketDataProvider data5(NULL, 0, NULL, 0); | |
| 10753 session_deps_.socket_factory->AddSocketDataProvider(&data5); | |
| 10754 | |
| 10755 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10756 scoped_ptr<HttpTransaction> trans( | |
| 10757 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10758 | |
| 10759 // Begin the SSL handshake with the peer. This consumes ssl_data1. | |
| 10760 TestCompletionCallback callback; | |
| 10761 int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); | |
| 10762 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 10763 | |
| 10764 // Complete the SSL handshake, which should abort due to requiring a | |
| 10765 // client certificate. | |
| 10766 rv = callback.WaitForResult(); | |
| 10767 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); | |
| 10768 | |
| 10769 // Indicate that no certificate should be supplied. From the perspective | |
| 10770 // of SSLClientCertCache, NULL is just as meaningful as a real | |
| 10771 // certificate, so this is the same as supply a | |
| 10772 // legitimate-but-unacceptable certificate. | |
| 10773 rv = trans->RestartWithCertificate(NULL, callback.callback()); | |
| 10774 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 10775 | |
| 10776 // Ensure the certificate was added to the client auth cache before | |
| 10777 // allowing the connection to continue restarting. | |
| 10778 scoped_refptr<X509Certificate> client_cert; | |
| 10779 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup( | |
| 10780 HostPortPair("www.example.com", 443), &client_cert)); | |
| 10781 ASSERT_EQ(NULL, client_cert.get()); | |
| 10782 | |
| 10783 // Restart the handshake. This will consume ssl_data2, which fails, and | |
| 10784 // then consume ssl_data3 and ssl_data4, both of which should also fail. | |
| 10785 // The result code is checked against what ssl_data4 should return. | |
| 10786 rv = callback.WaitForResult(); | |
| 10787 ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); | |
| 10788 | |
| 10789 // Ensure that the client certificate is removed from the cache on a | |
| 10790 // handshake failure. | |
| 10791 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup( | |
| 10792 HostPortPair("www.example.com", 443), &client_cert)); | |
| 10793 } | |
| 10794 | |
| 10795 // Ensure that a client certificate is removed from the SSL client auth | |
| 10796 // cache when: | |
| 10797 // 1) No proxy is involved. | |
| 10798 // 2) TLS False Start is enabled. | |
| 10799 // 3) The initial TLS handshake requests a client certificate. | |
| 10800 // 4) The client supplies an invalid/unacceptable certificate. | |
| 10801 TEST_P(HttpNetworkTransactionTest, | |
| 10802 ClientAuthCertCache_Direct_FalseStart) { | |
| 10803 net::HttpRequestInfo request_info; | |
| 10804 request_info.url = GURL("https://www.example.com/"); | |
| 10805 request_info.method = "GET"; | |
| 10806 request_info.load_flags = net::LOAD_NORMAL; | |
| 10807 | |
| 10808 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); | |
| 10809 cert_request->host_and_port = HostPortPair("www.example.com", 443); | |
| 10810 | |
| 10811 // When TLS False Start is used, SSLClientSocket::Connect() calls will | |
| 10812 // return successfully after reading up to the peer's Certificate message. | |
| 10813 // This is to allow the caller to call SSLClientSocket::Write(), which can | |
| 10814 // enqueue application data to be sent in the same packet as the | |
| 10815 // ChangeCipherSpec and Finished messages. | |
| 10816 // The actual handshake will be finished when SSLClientSocket::Read() is | |
| 10817 // called, which expects to process the peer's ChangeCipherSpec and | |
| 10818 // Finished messages. If there was an error negotiating with the peer, | |
| 10819 // such as due to the peer requiring a client certificate when none was | |
| 10820 // supplied, the alert sent by the peer won't be processed until Read() is | |
| 10821 // called. | |
| 10822 | |
| 10823 // Like the non-False Start case, when a client certificate is requested by | |
| 10824 // the peer, the handshake is aborted during the Connect() call. | |
| 10825 // [ssl_]data1 represents the initial SSL handshake with the peer. | |
| 10826 SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); | |
| 10827 ssl_data1.cert_request_info = cert_request.get(); | |
| 10828 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1); | |
| 10829 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); | |
| 10830 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 10831 | |
| 10832 // When a client certificate is supplied, Connect() will not be aborted | |
| 10833 // when the peer requests the certificate. Instead, the handshake will | |
| 10834 // artificially succeed, allowing the caller to write the HTTP request to | |
| 10835 // the socket. The handshake messages are not processed until Read() is | |
| 10836 // called, which then detects that the handshake was aborted, due to the | |
| 10837 // peer sending a handshake_failure because it requires a client | |
| 10838 // certificate. | |
| 10839 SSLSocketDataProvider ssl_data2(ASYNC, net::OK); | |
| 10840 ssl_data2.cert_request_info = cert_request.get(); | |
| 10841 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data2); | |
| 10842 net::MockRead data2_reads[] = { | |
| 10843 net::MockRead(ASYNC /* async */, net::ERR_SSL_PROTOCOL_ERROR), | |
| 10844 }; | |
| 10845 net::StaticSocketDataProvider data2( | |
| 10846 data2_reads, arraysize(data2_reads), NULL, 0); | |
| 10847 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 10848 | |
| 10849 // As described in ClientAuthCertCache_Direct_NoFalseStart, [ssl_]data3 is | |
| 10850 // the data for the SSL handshake once the TLSv1.1 connection falls back to | |
| 10851 // TLSv1. It has the same behaviour as [ssl_]data2. | |
| 10852 SSLSocketDataProvider ssl_data3(ASYNC, net::OK); | |
| 10853 ssl_data3.cert_request_info = cert_request.get(); | |
| 10854 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data3); | |
| 10855 net::StaticSocketDataProvider data3( | |
| 10856 data2_reads, arraysize(data2_reads), NULL, 0); | |
| 10857 session_deps_.socket_factory->AddSocketDataProvider(&data3); | |
| 10858 | |
| 10859 // [ssl_]data4 is the data for the SSL handshake once the TLSv1 connection | |
| 10860 // falls back to SSLv3. It has the same behaviour as [ssl_]data2. | |
| 10861 SSLSocketDataProvider ssl_data4(ASYNC, net::OK); | |
| 10862 ssl_data4.cert_request_info = cert_request.get(); | |
| 10863 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data4); | |
| 10864 net::StaticSocketDataProvider data4( | |
| 10865 data2_reads, arraysize(data2_reads), NULL, 0); | |
| 10866 session_deps_.socket_factory->AddSocketDataProvider(&data4); | |
| 10867 | |
| 10868 // Need one more if TLSv1.2 is enabled. | |
| 10869 SSLSocketDataProvider ssl_data5(ASYNC, net::OK); | |
| 10870 ssl_data5.cert_request_info = cert_request.get(); | |
| 10871 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data5); | |
| 10872 net::StaticSocketDataProvider data5( | |
| 10873 data2_reads, arraysize(data2_reads), NULL, 0); | |
| 10874 session_deps_.socket_factory->AddSocketDataProvider(&data5); | |
| 10875 | |
| 10876 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10877 scoped_ptr<HttpTransaction> trans( | |
| 10878 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10879 | |
| 10880 // Begin the initial SSL handshake. | |
| 10881 TestCompletionCallback callback; | |
| 10882 int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); | |
| 10883 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 10884 | |
| 10885 // Complete the SSL handshake, which should abort due to requiring a | |
| 10886 // client certificate. | |
| 10887 rv = callback.WaitForResult(); | |
| 10888 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); | |
| 10889 | |
| 10890 // Indicate that no certificate should be supplied. From the perspective | |
| 10891 // of SSLClientCertCache, NULL is just as meaningful as a real | |
| 10892 // certificate, so this is the same as supply a | |
| 10893 // legitimate-but-unacceptable certificate. | |
| 10894 rv = trans->RestartWithCertificate(NULL, callback.callback()); | |
| 10895 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 10896 | |
| 10897 // Ensure the certificate was added to the client auth cache before | |
| 10898 // allowing the connection to continue restarting. | |
| 10899 scoped_refptr<X509Certificate> client_cert; | |
| 10900 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup( | |
| 10901 HostPortPair("www.example.com", 443), &client_cert)); | |
| 10902 ASSERT_EQ(NULL, client_cert.get()); | |
| 10903 | |
| 10904 // Restart the handshake. This will consume ssl_data2, which fails, and | |
| 10905 // then consume ssl_data3 and ssl_data4, both of which should also fail. | |
| 10906 // The result code is checked against what ssl_data4 should return. | |
| 10907 rv = callback.WaitForResult(); | |
| 10908 ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); | |
| 10909 | |
| 10910 // Ensure that the client certificate is removed from the cache on a | |
| 10911 // handshake failure. | |
| 10912 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup( | |
| 10913 HostPortPair("www.example.com", 443), &client_cert)); | |
| 10914 } | |
| 10915 | |
| 10916 // Ensure that a client certificate is removed from the SSL client auth | |
| 10917 // cache when: | |
| 10918 // 1) An HTTPS proxy is involved. | |
| 10919 // 3) The HTTPS proxy requests a client certificate. | |
| 10920 // 4) The client supplies an invalid/unacceptable certificate for the | |
| 10921 // proxy. | |
| 10922 // The test is repeated twice, first for connecting to an HTTPS endpoint, | |
| 10923 // then for connecting to an HTTP endpoint. | |
| 10924 TEST_P(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) { | |
| 10925 session_deps_.proxy_service.reset( | |
| 10926 ProxyService::CreateFixed("https://proxy:70")); | |
| 10927 CapturingBoundNetLog log; | |
| 10928 session_deps_.net_log = log.bound().net_log(); | |
| 10929 | |
| 10930 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); | |
| 10931 cert_request->host_and_port = HostPortPair("proxy", 70); | |
| 10932 | |
| 10933 // See ClientAuthCertCache_Direct_NoFalseStart for the explanation of | |
| 10934 // [ssl_]data[1-3]. Rather than represending the endpoint | |
| 10935 // (www.example.com:443), they represent failures with the HTTPS proxy | |
| 10936 // (proxy:70). | |
| 10937 SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); | |
| 10938 ssl_data1.cert_request_info = cert_request.get(); | |
| 10939 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1); | |
| 10940 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); | |
| 10941 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 10942 | |
| 10943 SSLSocketDataProvider ssl_data2(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
| 10944 ssl_data2.cert_request_info = cert_request.get(); | |
| 10945 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data2); | |
| 10946 net::StaticSocketDataProvider data2(NULL, 0, NULL, 0); | |
| 10947 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 10948 | |
| 10949 // TODO(wtc): find out why this unit test doesn't need [ssl_]data3. | |
| 10950 #if 0 | |
| 10951 SSLSocketDataProvider ssl_data3(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
| 10952 ssl_data3.cert_request_info = cert_request.get(); | |
| 10953 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data3); | |
| 10954 net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); | |
| 10955 session_deps_.socket_factory->AddSocketDataProvider(&data3); | |
| 10956 #endif | |
| 10957 | |
| 10958 net::HttpRequestInfo requests[2]; | |
| 10959 requests[0].url = GURL("https://www.example.com/"); | |
| 10960 requests[0].method = "GET"; | |
| 10961 requests[0].load_flags = net::LOAD_NORMAL; | |
| 10962 | |
| 10963 requests[1].url = GURL("http://www.example.com/"); | |
| 10964 requests[1].method = "GET"; | |
| 10965 requests[1].load_flags = net::LOAD_NORMAL; | |
| 10966 | |
| 10967 for (size_t i = 0; i < arraysize(requests); ++i) { | |
| 10968 session_deps_.socket_factory->ResetNextMockIndexes(); | |
| 10969 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 10970 scoped_ptr<HttpNetworkTransaction> trans( | |
| 10971 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 10972 | |
| 10973 // Begin the SSL handshake with the proxy. | |
| 10974 TestCompletionCallback callback; | |
| 10975 int rv = trans->Start( | |
| 10976 &requests[i], callback.callback(), net::BoundNetLog()); | |
| 10977 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 10978 | |
| 10979 // Complete the SSL handshake, which should abort due to requiring a | |
| 10980 // client certificate. | |
| 10981 rv = callback.WaitForResult(); | |
| 10982 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); | |
| 10983 | |
| 10984 // Indicate that no certificate should be supplied. From the perspective | |
| 10985 // of SSLClientCertCache, NULL is just as meaningful as a real | |
| 10986 // certificate, so this is the same as supply a | |
| 10987 // legitimate-but-unacceptable certificate. | |
| 10988 rv = trans->RestartWithCertificate(NULL, callback.callback()); | |
| 10989 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 10990 | |
| 10991 // Ensure the certificate was added to the client auth cache before | |
| 10992 // allowing the connection to continue restarting. | |
| 10993 scoped_refptr<X509Certificate> client_cert; | |
| 10994 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup( | |
| 10995 HostPortPair("proxy", 70), &client_cert)); | |
| 10996 ASSERT_EQ(NULL, client_cert.get()); | |
| 10997 // Ensure the certificate was NOT cached for the endpoint. This only | |
| 10998 // applies to HTTPS requests, but is fine to check for HTTP requests. | |
| 10999 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup( | |
| 11000 HostPortPair("www.example.com", 443), &client_cert)); | |
| 11001 | |
| 11002 // Restart the handshake. This will consume ssl_data2, which fails, and | |
| 11003 // then consume ssl_data3, which should also fail. The result code is | |
| 11004 // checked against what ssl_data3 should return. | |
| 11005 rv = callback.WaitForResult(); | |
| 11006 ASSERT_EQ(net::ERR_PROXY_CONNECTION_FAILED, rv); | |
| 11007 | |
| 11008 // Now that the new handshake has failed, ensure that the client | |
| 11009 // certificate was removed from the client auth cache. | |
| 11010 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup( | |
| 11011 HostPortPair("proxy", 70), &client_cert)); | |
| 11012 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup( | |
| 11013 HostPortPair("www.example.com", 443), &client_cert)); | |
| 11014 } | |
| 11015 } | |
| 11016 | |
| 11017 // Unlike TEST/TEST_F, which are macros that expand to further macros, | |
| 11018 // TEST_P is a macro that expands directly to code that stringizes the | |
| 11019 // arguments. As a result, macros passed as parameters (such as prefix | |
| 11020 // or test_case_name) will not be expanded by the preprocessor. To | |
| 11021 // work around this, indirect the macro for TEST_P, so that the | |
| 11022 // pre-processor will expand macros such as MAYBE_test_name before | |
| 11023 // instantiating the test. | |
| 11024 #define WRAPPED_TEST_P(test_case_name, test_name) \ | |
| 11025 TEST_P(test_case_name, test_name) | |
| 11026 | |
| 11027 // Times out on Win7 dbg(2) bot. http://crbug.com/124776 | |
| 11028 #if defined(OS_WIN) | |
| 11029 #define MAYBE_UseIPConnectionPooling DISABLED_UseIPConnectionPooling | |
| 11030 #else | |
| 11031 #define MAYBE_UseIPConnectionPooling UseIPConnectionPooling | |
| 11032 #endif | |
| 11033 WRAPPED_TEST_P(HttpNetworkTransactionTest, MAYBE_UseIPConnectionPooling) { | |
| 11034 session_deps_.use_alternate_protocols = true; | |
| 11035 session_deps_.next_protos = SpdyNextProtos(); | |
| 11036 | |
| 11037 // Set up a special HttpNetworkSession with a MockCachingHostResolver. | |
| 11038 session_deps_.host_resolver.reset(new MockCachingHostResolver()); | |
| 11039 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 11040 SpdySessionPoolPeer pool_peer(session->spdy_session_pool()); | |
| 11041 pool_peer.DisableDomainAuthenticationVerification(); | |
| 11042 | |
| 11043 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 11044 ssl.SetNextProto(GetParam()); | |
| 11045 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 11046 | |
| 11047 scoped_ptr<SpdyFrame> host1_req( | |
| 11048 spdy_util_.ConstructSpdyGet("https://www.google.com", false, 1, LOWEST)); | |
| 11049 scoped_ptr<SpdyFrame> host2_req( | |
| 11050 spdy_util_.ConstructSpdyGet("https://www.gmail.com", false, 3, LOWEST)); | |
| 11051 MockWrite spdy_writes[] = { | |
| 11052 CreateMockWrite(*host1_req, 1), | |
| 11053 CreateMockWrite(*host2_req, 4), | |
| 11054 }; | |
| 11055 scoped_ptr<SpdyFrame> host1_resp( | |
| 11056 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11057 scoped_ptr<SpdyFrame> host1_resp_body( | |
| 11058 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 11059 scoped_ptr<SpdyFrame> host2_resp( | |
| 11060 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 11061 scoped_ptr<SpdyFrame> host2_resp_body( | |
| 11062 spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
| 11063 MockRead spdy_reads[] = { | |
| 11064 CreateMockRead(*host1_resp, 2), | |
| 11065 CreateMockRead(*host1_resp_body, 3), | |
| 11066 CreateMockRead(*host2_resp, 5), | |
| 11067 CreateMockRead(*host2_resp_body, 6), | |
| 11068 MockRead(ASYNC, 0, 7), | |
| 11069 }; | |
| 11070 | |
| 11071 IPAddressNumber ip; | |
| 11072 ASSERT_TRUE(ParseIPLiteralToNumber("127.0.0.1", &ip)); | |
| 11073 IPEndPoint peer_addr = IPEndPoint(ip, 443); | |
| 11074 MockConnect connect(ASYNC, OK, peer_addr); | |
| 11075 OrderedSocketData spdy_data( | |
| 11076 connect, | |
| 11077 spdy_reads, arraysize(spdy_reads), | |
| 11078 spdy_writes, arraysize(spdy_writes)); | |
| 11079 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 11080 | |
| 11081 TestCompletionCallback callback; | |
| 11082 HttpRequestInfo request1; | |
| 11083 request1.method = "GET"; | |
| 11084 request1.url = GURL("https://www.google.com/"); | |
| 11085 request1.load_flags = 0; | |
| 11086 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get()); | |
| 11087 | |
| 11088 int rv = trans1.Start(&request1, callback.callback(), BoundNetLog()); | |
| 11089 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 11090 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 11091 | |
| 11092 const HttpResponseInfo* response = trans1.GetResponseInfo(); | |
| 11093 ASSERT_TRUE(response != NULL); | |
| 11094 ASSERT_TRUE(response->headers.get() != NULL); | |
| 11095 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 11096 | |
| 11097 std::string response_data; | |
| 11098 ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); | |
| 11099 EXPECT_EQ("hello!", response_data); | |
| 11100 | |
| 11101 // Preload www.gmail.com into HostCache. | |
| 11102 HostPortPair host_port("www.gmail.com", 443); | |
| 11103 HostResolver::RequestInfo resolve_info(host_port); | |
| 11104 AddressList ignored; | |
| 11105 rv = session_deps_.host_resolver->Resolve(resolve_info, | |
| 11106 DEFAULT_PRIORITY, | |
| 11107 &ignored, | |
| 11108 callback.callback(), | |
| 11109 NULL, | |
| 11110 BoundNetLog()); | |
| 11111 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 11112 rv = callback.WaitForResult(); | |
| 11113 EXPECT_EQ(OK, rv); | |
| 11114 | |
| 11115 HttpRequestInfo request2; | |
| 11116 request2.method = "GET"; | |
| 11117 request2.url = GURL("https://www.gmail.com/"); | |
| 11118 request2.load_flags = 0; | |
| 11119 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get()); | |
| 11120 | |
| 11121 rv = trans2.Start(&request2, callback.callback(), BoundNetLog()); | |
| 11122 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 11123 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 11124 | |
| 11125 response = trans2.GetResponseInfo(); | |
| 11126 ASSERT_TRUE(response != NULL); | |
| 11127 ASSERT_TRUE(response->headers.get() != NULL); | |
| 11128 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 11129 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 11130 EXPECT_TRUE(response->was_npn_negotiated); | |
| 11131 ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); | |
| 11132 EXPECT_EQ("hello!", response_data); | |
| 11133 } | |
| 11134 #undef MAYBE_UseIPConnectionPooling | |
| 11135 | |
| 11136 TEST_P(HttpNetworkTransactionTest, UseIPConnectionPoolingAfterResolution) { | |
| 11137 session_deps_.use_alternate_protocols = true; | |
| 11138 session_deps_.next_protos = SpdyNextProtos(); | |
| 11139 | |
| 11140 // Set up a special HttpNetworkSession with a MockCachingHostResolver. | |
| 11141 session_deps_.host_resolver.reset(new MockCachingHostResolver()); | |
| 11142 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 11143 SpdySessionPoolPeer pool_peer(session->spdy_session_pool()); | |
| 11144 pool_peer.DisableDomainAuthenticationVerification(); | |
| 11145 | |
| 11146 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 11147 ssl.SetNextProto(GetParam()); | |
| 11148 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 11149 | |
| 11150 scoped_ptr<SpdyFrame> host1_req( | |
| 11151 spdy_util_.ConstructSpdyGet("https://www.google.com", false, 1, LOWEST)); | |
| 11152 scoped_ptr<SpdyFrame> host2_req( | |
| 11153 spdy_util_.ConstructSpdyGet("https://www.gmail.com", false, 3, LOWEST)); | |
| 11154 MockWrite spdy_writes[] = { | |
| 11155 CreateMockWrite(*host1_req, 1), | |
| 11156 CreateMockWrite(*host2_req, 4), | |
| 11157 }; | |
| 11158 scoped_ptr<SpdyFrame> host1_resp( | |
| 11159 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11160 scoped_ptr<SpdyFrame> host1_resp_body( | |
| 11161 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 11162 scoped_ptr<SpdyFrame> host2_resp( | |
| 11163 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 11164 scoped_ptr<SpdyFrame> host2_resp_body( | |
| 11165 spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
| 11166 MockRead spdy_reads[] = { | |
| 11167 CreateMockRead(*host1_resp, 2), | |
| 11168 CreateMockRead(*host1_resp_body, 3), | |
| 11169 CreateMockRead(*host2_resp, 5), | |
| 11170 CreateMockRead(*host2_resp_body, 6), | |
| 11171 MockRead(ASYNC, 0, 7), | |
| 11172 }; | |
| 11173 | |
| 11174 IPAddressNumber ip; | |
| 11175 ASSERT_TRUE(ParseIPLiteralToNumber("127.0.0.1", &ip)); | |
| 11176 IPEndPoint peer_addr = IPEndPoint(ip, 443); | |
| 11177 MockConnect connect(ASYNC, OK, peer_addr); | |
| 11178 OrderedSocketData spdy_data( | |
| 11179 connect, | |
| 11180 spdy_reads, arraysize(spdy_reads), | |
| 11181 spdy_writes, arraysize(spdy_writes)); | |
| 11182 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 11183 | |
| 11184 TestCompletionCallback callback; | |
| 11185 HttpRequestInfo request1; | |
| 11186 request1.method = "GET"; | |
| 11187 request1.url = GURL("https://www.google.com/"); | |
| 11188 request1.load_flags = 0; | |
| 11189 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get()); | |
| 11190 | |
| 11191 int rv = trans1.Start(&request1, callback.callback(), BoundNetLog()); | |
| 11192 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 11193 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 11194 | |
| 11195 const HttpResponseInfo* response = trans1.GetResponseInfo(); | |
| 11196 ASSERT_TRUE(response != NULL); | |
| 11197 ASSERT_TRUE(response->headers.get() != NULL); | |
| 11198 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 11199 | |
| 11200 std::string response_data; | |
| 11201 ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); | |
| 11202 EXPECT_EQ("hello!", response_data); | |
| 11203 | |
| 11204 HttpRequestInfo request2; | |
| 11205 request2.method = "GET"; | |
| 11206 request2.url = GURL("https://www.gmail.com/"); | |
| 11207 request2.load_flags = 0; | |
| 11208 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get()); | |
| 11209 | |
| 11210 rv = trans2.Start(&request2, callback.callback(), BoundNetLog()); | |
| 11211 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 11212 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 11213 | |
| 11214 response = trans2.GetResponseInfo(); | |
| 11215 ASSERT_TRUE(response != NULL); | |
| 11216 ASSERT_TRUE(response->headers.get() != NULL); | |
| 11217 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 11218 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 11219 EXPECT_TRUE(response->was_npn_negotiated); | |
| 11220 ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); | |
| 11221 EXPECT_EQ("hello!", response_data); | |
| 11222 } | |
| 11223 | |
| 11224 class OneTimeCachingHostResolver : public net::HostResolver { | |
| 11225 public: | |
| 11226 explicit OneTimeCachingHostResolver(const HostPortPair& host_port) | |
| 11227 : host_port_(host_port) {} | |
| 11228 ~OneTimeCachingHostResolver() override {} | |
| 11229 | |
| 11230 RuleBasedHostResolverProc* rules() { return host_resolver_.rules(); } | |
| 11231 | |
| 11232 // HostResolver methods: | |
| 11233 int Resolve(const RequestInfo& info, | |
| 11234 RequestPriority priority, | |
| 11235 AddressList* addresses, | |
| 11236 const CompletionCallback& callback, | |
| 11237 RequestHandle* out_req, | |
| 11238 const BoundNetLog& net_log) override { | |
| 11239 return host_resolver_.Resolve( | |
| 11240 info, priority, addresses, callback, out_req, net_log); | |
| 11241 } | |
| 11242 | |
| 11243 int ResolveFromCache(const RequestInfo& info, | |
| 11244 AddressList* addresses, | |
| 11245 const BoundNetLog& net_log) override { | |
| 11246 int rv = host_resolver_.ResolveFromCache(info, addresses, net_log); | |
| 11247 if (rv == OK && info.host_port_pair().Equals(host_port_)) | |
| 11248 host_resolver_.GetHostCache()->clear(); | |
| 11249 return rv; | |
| 11250 } | |
| 11251 | |
| 11252 void CancelRequest(RequestHandle req) override { | |
| 11253 host_resolver_.CancelRequest(req); | |
| 11254 } | |
| 11255 | |
| 11256 MockCachingHostResolver* GetMockHostResolver() { | |
| 11257 return &host_resolver_; | |
| 11258 } | |
| 11259 | |
| 11260 private: | |
| 11261 MockCachingHostResolver host_resolver_; | |
| 11262 const HostPortPair host_port_; | |
| 11263 }; | |
| 11264 | |
| 11265 // Times out on Win7 dbg(2) bot. http://crbug.com/124776 | |
| 11266 #if defined(OS_WIN) | |
| 11267 #define MAYBE_UseIPConnectionPoolingWithHostCacheExpiration \ | |
| 11268 DISABLED_UseIPConnectionPoolingWithHostCacheExpiration | |
| 11269 #else | |
| 11270 #define MAYBE_UseIPConnectionPoolingWithHostCacheExpiration \ | |
| 11271 UseIPConnectionPoolingWithHostCacheExpiration | |
| 11272 #endif | |
| 11273 WRAPPED_TEST_P(HttpNetworkTransactionTest, | |
| 11274 MAYBE_UseIPConnectionPoolingWithHostCacheExpiration) { | |
| 11275 // Times out on Win7 dbg(2) bot. http://crbug.com/124776 . (MAYBE_ | |
| 11276 // prefix doesn't work with parametrized tests). | |
| 11277 #if defined(OS_WIN) | |
| 11278 return; | |
| 11279 #else | |
| 11280 session_deps_.use_alternate_protocols = true; | |
| 11281 session_deps_.next_protos = SpdyNextProtos(); | |
| 11282 | |
| 11283 // Set up a special HttpNetworkSession with a OneTimeCachingHostResolver. | |
| 11284 OneTimeCachingHostResolver host_resolver(HostPortPair("www.gmail.com", 443)); | |
| 11285 HttpNetworkSession::Params params = | |
| 11286 SpdySessionDependencies::CreateSessionParams(&session_deps_); | |
| 11287 params.host_resolver = &host_resolver; | |
| 11288 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 11289 SpdySessionPoolPeer pool_peer(session->spdy_session_pool()); | |
| 11290 pool_peer.DisableDomainAuthenticationVerification(); | |
| 11291 | |
| 11292 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 11293 ssl.SetNextProto(GetParam()); | |
| 11294 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 11295 | |
| 11296 scoped_ptr<SpdyFrame> host1_req( | |
| 11297 spdy_util_.ConstructSpdyGet("https://www.google.com", false, 1, LOWEST)); | |
| 11298 scoped_ptr<SpdyFrame> host2_req( | |
| 11299 spdy_util_.ConstructSpdyGet("https://www.gmail.com", false, 3, LOWEST)); | |
| 11300 MockWrite spdy_writes[] = { | |
| 11301 CreateMockWrite(*host1_req, 1), | |
| 11302 CreateMockWrite(*host2_req, 4), | |
| 11303 }; | |
| 11304 scoped_ptr<SpdyFrame> host1_resp( | |
| 11305 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11306 scoped_ptr<SpdyFrame> host1_resp_body( | |
| 11307 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 11308 scoped_ptr<SpdyFrame> host2_resp( | |
| 11309 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 11310 scoped_ptr<SpdyFrame> host2_resp_body( | |
| 11311 spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
| 11312 MockRead spdy_reads[] = { | |
| 11313 CreateMockRead(*host1_resp, 2), | |
| 11314 CreateMockRead(*host1_resp_body, 3), | |
| 11315 CreateMockRead(*host2_resp, 5), | |
| 11316 CreateMockRead(*host2_resp_body, 6), | |
| 11317 MockRead(ASYNC, 0, 7), | |
| 11318 }; | |
| 11319 | |
| 11320 IPAddressNumber ip; | |
| 11321 ASSERT_TRUE(ParseIPLiteralToNumber("127.0.0.1", &ip)); | |
| 11322 IPEndPoint peer_addr = IPEndPoint(ip, 443); | |
| 11323 MockConnect connect(ASYNC, OK, peer_addr); | |
| 11324 OrderedSocketData spdy_data( | |
| 11325 connect, | |
| 11326 spdy_reads, arraysize(spdy_reads), | |
| 11327 spdy_writes, arraysize(spdy_writes)); | |
| 11328 session_deps_.socket_factory->AddSocketDataProvider(&spdy_data); | |
| 11329 | |
| 11330 TestCompletionCallback callback; | |
| 11331 HttpRequestInfo request1; | |
| 11332 request1.method = "GET"; | |
| 11333 request1.url = GURL("https://www.google.com/"); | |
| 11334 request1.load_flags = 0; | |
| 11335 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get()); | |
| 11336 | |
| 11337 int rv = trans1.Start(&request1, callback.callback(), BoundNetLog()); | |
| 11338 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 11339 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 11340 | |
| 11341 const HttpResponseInfo* response = trans1.GetResponseInfo(); | |
| 11342 ASSERT_TRUE(response != NULL); | |
| 11343 ASSERT_TRUE(response->headers.get() != NULL); | |
| 11344 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 11345 | |
| 11346 std::string response_data; | |
| 11347 ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); | |
| 11348 EXPECT_EQ("hello!", response_data); | |
| 11349 | |
| 11350 // Preload cache entries into HostCache. | |
| 11351 HostResolver::RequestInfo resolve_info(HostPortPair("www.gmail.com", 443)); | |
| 11352 AddressList ignored; | |
| 11353 rv = host_resolver.Resolve(resolve_info, | |
| 11354 DEFAULT_PRIORITY, | |
| 11355 &ignored, | |
| 11356 callback.callback(), | |
| 11357 NULL, | |
| 11358 BoundNetLog()); | |
| 11359 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 11360 rv = callback.WaitForResult(); | |
| 11361 EXPECT_EQ(OK, rv); | |
| 11362 | |
| 11363 HttpRequestInfo request2; | |
| 11364 request2.method = "GET"; | |
| 11365 request2.url = GURL("https://www.gmail.com/"); | |
| 11366 request2.load_flags = 0; | |
| 11367 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get()); | |
| 11368 | |
| 11369 rv = trans2.Start(&request2, callback.callback(), BoundNetLog()); | |
| 11370 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 11371 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 11372 | |
| 11373 response = trans2.GetResponseInfo(); | |
| 11374 ASSERT_TRUE(response != NULL); | |
| 11375 ASSERT_TRUE(response->headers.get() != NULL); | |
| 11376 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 11377 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 11378 EXPECT_TRUE(response->was_npn_negotiated); | |
| 11379 ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); | |
| 11380 EXPECT_EQ("hello!", response_data); | |
| 11381 #endif | |
| 11382 } | |
| 11383 #undef MAYBE_UseIPConnectionPoolingWithHostCacheExpiration | |
| 11384 | |
| 11385 TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttp) { | |
| 11386 const std::string https_url = "https://www.google.com:8080/"; | |
| 11387 const std::string http_url = "http://www.google.com:8080/"; | |
| 11388 | |
| 11389 // SPDY GET for HTTPS URL | |
| 11390 scoped_ptr<SpdyFrame> req1( | |
| 11391 spdy_util_.ConstructSpdyGet(https_url.c_str(), false, 1, LOWEST)); | |
| 11392 | |
| 11393 MockWrite writes1[] = { | |
| 11394 CreateMockWrite(*req1, 0), | |
| 11395 }; | |
| 11396 | |
| 11397 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11398 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 11399 MockRead reads1[] = { | |
| 11400 CreateMockRead(*resp1, 1), | |
| 11401 CreateMockRead(*body1, 2), | |
| 11402 MockRead(ASYNC, ERR_IO_PENDING, 3) | |
| 11403 }; | |
| 11404 | |
| 11405 DelayedSocketData data1( | |
| 11406 1, reads1, arraysize(reads1), | |
| 11407 writes1, arraysize(writes1)); | |
| 11408 MockConnect connect_data1(ASYNC, OK); | |
| 11409 data1.set_connect_data(connect_data1); | |
| 11410 | |
| 11411 // HTTP GET for the HTTP URL | |
| 11412 MockWrite writes2[] = { | |
| 11413 MockWrite(ASYNC, 4, | |
| 11414 "GET / HTTP/1.1\r\n" | |
| 11415 "Host: www.google.com:8080\r\n" | |
| 11416 "Connection: keep-alive\r\n\r\n"), | |
| 11417 }; | |
| 11418 | |
| 11419 MockRead reads2[] = { | |
| 11420 MockRead(ASYNC, 5, "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
| 11421 MockRead(ASYNC, 6, "hello"), | |
| 11422 MockRead(ASYNC, 7, OK), | |
| 11423 }; | |
| 11424 | |
| 11425 DelayedSocketData data2( | |
| 11426 1, reads2, arraysize(reads2), | |
| 11427 writes2, arraysize(writes2)); | |
| 11428 | |
| 11429 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 11430 ssl.SetNextProto(GetParam()); | |
| 11431 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 11432 session_deps_.socket_factory->AddSocketDataProvider(&data1); | |
| 11433 session_deps_.socket_factory->AddSocketDataProvider(&data2); | |
| 11434 | |
| 11435 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 11436 | |
| 11437 // Start the first transaction to set up the SpdySession | |
| 11438 HttpRequestInfo request1; | |
| 11439 request1.method = "GET"; | |
| 11440 request1.url = GURL(https_url); | |
| 11441 request1.load_flags = 0; | |
| 11442 HttpNetworkTransaction trans1(LOWEST, session.get()); | |
| 11443 TestCompletionCallback callback1; | |
| 11444 EXPECT_EQ(ERR_IO_PENDING, | |
| 11445 trans1.Start(&request1, callback1.callback(), BoundNetLog())); | |
| 11446 base::MessageLoop::current()->RunUntilIdle(); | |
| 11447 | |
| 11448 EXPECT_EQ(OK, callback1.WaitForResult()); | |
| 11449 EXPECT_TRUE(trans1.GetResponseInfo()->was_fetched_via_spdy); | |
| 11450 | |
| 11451 // Now, start the HTTP request | |
| 11452 HttpRequestInfo request2; | |
| 11453 request2.method = "GET"; | |
| 11454 request2.url = GURL(http_url); | |
| 11455 request2.load_flags = 0; | |
| 11456 HttpNetworkTransaction trans2(MEDIUM, session.get()); | |
| 11457 TestCompletionCallback callback2; | |
| 11458 EXPECT_EQ(ERR_IO_PENDING, | |
| 11459 trans2.Start(&request2, callback2.callback(), BoundNetLog())); | |
| 11460 base::MessageLoop::current()->RunUntilIdle(); | |
| 11461 | |
| 11462 EXPECT_EQ(OK, callback2.WaitForResult()); | |
| 11463 EXPECT_FALSE(trans2.GetResponseInfo()->was_fetched_via_spdy); | |
| 11464 } | |
| 11465 | |
| 11466 TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) { | |
| 11467 const std::string https_url = "https://www.google.com:8080/"; | |
| 11468 const std::string http_url = "http://www.google.com:8080/"; | |
| 11469 | |
| 11470 // SPDY GET for HTTPS URL (through CONNECT tunnel) | |
| 11471 const HostPortPair host_port_pair("www.google.com", 8080); | |
| 11472 scoped_ptr<SpdyFrame> connect( | |
| 11473 spdy_util_.ConstructSpdyConnect(NULL, 0, 1, LOWEST, host_port_pair)); | |
| 11474 scoped_ptr<SpdyFrame> req1( | |
| 11475 spdy_util_.ConstructSpdyGet(https_url.c_str(), false, 1, LOWEST)); | |
| 11476 scoped_ptr<SpdyFrame> wrapped_req1( | |
| 11477 spdy_util_.ConstructWrappedSpdyFrame(req1, 1)); | |
| 11478 | |
| 11479 // SPDY GET for HTTP URL (through the proxy, but not the tunnel). | |
| 11480 SpdyHeaderBlock req2_block; | |
| 11481 req2_block[spdy_util_.GetMethodKey()] = "GET"; | |
| 11482 req2_block[spdy_util_.GetPathKey()] = "/"; | |
| 11483 req2_block[spdy_util_.GetHostKey()] = "www.google.com:8080"; | |
| 11484 req2_block[spdy_util_.GetSchemeKey()] = "http"; | |
| 11485 spdy_util_.MaybeAddVersionHeader(&req2_block); | |
| 11486 scoped_ptr<SpdyFrame> req2( | |
| 11487 spdy_util_.ConstructSpdySyn(3, req2_block, MEDIUM, false, true)); | |
| 11488 | |
| 11489 MockWrite writes1[] = { | |
| 11490 CreateMockWrite(*connect, 0), | |
| 11491 CreateMockWrite(*wrapped_req1, 2), | |
| 11492 CreateMockWrite(*req2, 5), | |
| 11493 }; | |
| 11494 | |
| 11495 scoped_ptr<SpdyFrame> conn_resp( | |
| 11496 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11497 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11498 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 11499 scoped_ptr<SpdyFrame> wrapped_resp1( | |
| 11500 spdy_util_.ConstructWrappedSpdyFrame(resp1, 1)); | |
| 11501 scoped_ptr<SpdyFrame> wrapped_body1( | |
| 11502 spdy_util_.ConstructWrappedSpdyFrame(body1, 1)); | |
| 11503 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 11504 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
| 11505 MockRead reads1[] = { | |
| 11506 CreateMockRead(*conn_resp, 1), | |
| 11507 CreateMockRead(*wrapped_resp1, 3), | |
| 11508 CreateMockRead(*wrapped_body1, 4), | |
| 11509 CreateMockRead(*resp2, 6), | |
| 11510 CreateMockRead(*body2, 7), | |
| 11511 MockRead(ASYNC, ERR_IO_PENDING, 8) | |
| 11512 }; | |
| 11513 | |
| 11514 DeterministicSocketData data1(reads1, arraysize(reads1), | |
| 11515 writes1, arraysize(writes1)); | |
| 11516 MockConnect connect_data1(ASYNC, OK); | |
| 11517 data1.set_connect_data(connect_data1); | |
| 11518 | |
| 11519 session_deps_.proxy_service.reset( | |
| 11520 ProxyService::CreateFixedFromPacResult("HTTPS proxy:70")); | |
| 11521 CapturingNetLog log; | |
| 11522 session_deps_.net_log = &log; | |
| 11523 SSLSocketDataProvider ssl1(ASYNC, OK); // to the proxy | |
| 11524 ssl1.SetNextProto(GetParam()); | |
| 11525 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl1); | |
| 11526 SSLSocketDataProvider ssl2(ASYNC, OK); // to the server | |
| 11527 ssl2.SetNextProto(GetParam()); | |
| 11528 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl2); | |
| 11529 session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data1); | |
| 11530 | |
| 11531 scoped_refptr<HttpNetworkSession> session( | |
| 11532 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_)); | |
| 11533 | |
| 11534 // Start the first transaction to set up the SpdySession | |
| 11535 HttpRequestInfo request1; | |
| 11536 request1.method = "GET"; | |
| 11537 request1.url = GURL(https_url); | |
| 11538 request1.load_flags = 0; | |
| 11539 HttpNetworkTransaction trans1(LOWEST, session.get()); | |
| 11540 TestCompletionCallback callback1; | |
| 11541 EXPECT_EQ(ERR_IO_PENDING, | |
| 11542 trans1.Start(&request1, callback1.callback(), BoundNetLog())); | |
| 11543 base::MessageLoop::current()->RunUntilIdle(); | |
| 11544 data1.RunFor(4); | |
| 11545 | |
| 11546 EXPECT_EQ(OK, callback1.WaitForResult()); | |
| 11547 EXPECT_TRUE(trans1.GetResponseInfo()->was_fetched_via_spdy); | |
| 11548 | |
| 11549 LoadTimingInfo load_timing_info1; | |
| 11550 EXPECT_TRUE(trans1.GetLoadTimingInfo(&load_timing_info1)); | |
| 11551 TestLoadTimingNotReusedWithPac(load_timing_info1, | |
| 11552 CONNECT_TIMING_HAS_SSL_TIMES); | |
| 11553 | |
| 11554 // Now, start the HTTP request | |
| 11555 HttpRequestInfo request2; | |
| 11556 request2.method = "GET"; | |
| 11557 request2.url = GURL(http_url); | |
| 11558 request2.load_flags = 0; | |
| 11559 HttpNetworkTransaction trans2(MEDIUM, session.get()); | |
| 11560 TestCompletionCallback callback2; | |
| 11561 EXPECT_EQ(ERR_IO_PENDING, | |
| 11562 trans2.Start(&request2, callback2.callback(), BoundNetLog())); | |
| 11563 base::MessageLoop::current()->RunUntilIdle(); | |
| 11564 data1.RunFor(3); | |
| 11565 | |
| 11566 EXPECT_EQ(OK, callback2.WaitForResult()); | |
| 11567 EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy); | |
| 11568 | |
| 11569 LoadTimingInfo load_timing_info2; | |
| 11570 EXPECT_TRUE(trans2.GetLoadTimingInfo(&load_timing_info2)); | |
| 11571 // The established SPDY sessions is considered reused by the HTTP request. | |
| 11572 TestLoadTimingReusedWithPac(load_timing_info2); | |
| 11573 // HTTP requests over a SPDY session should have a different connection | |
| 11574 // socket_log_id than requests over a tunnel. | |
| 11575 EXPECT_NE(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id); | |
| 11576 } | |
| 11577 | |
| 11578 TEST_P(HttpNetworkTransactionTest, UseSpdySessionForHttpWhenForced) { | |
| 11579 session_deps_.force_spdy_always = true; | |
| 11580 const std::string https_url = "https://www.google.com:8080/"; | |
| 11581 const std::string http_url = "http://www.google.com:8080/"; | |
| 11582 | |
| 11583 // SPDY GET for HTTPS URL | |
| 11584 scoped_ptr<SpdyFrame> req1( | |
| 11585 spdy_util_.ConstructSpdyGet(https_url.c_str(), false, 1, LOWEST)); | |
| 11586 // SPDY GET for the HTTP URL | |
| 11587 scoped_ptr<SpdyFrame> req2( | |
| 11588 spdy_util_.ConstructSpdyGet(http_url.c_str(), false, 3, MEDIUM)); | |
| 11589 | |
| 11590 MockWrite writes[] = { | |
| 11591 CreateMockWrite(*req1, 1), | |
| 11592 CreateMockWrite(*req2, 4), | |
| 11593 }; | |
| 11594 | |
| 11595 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11596 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 11597 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 11598 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
| 11599 MockRead reads[] = { | |
| 11600 CreateMockRead(*resp1, 2), | |
| 11601 CreateMockRead(*body1, 3), | |
| 11602 CreateMockRead(*resp2, 5), | |
| 11603 CreateMockRead(*body2, 6), | |
| 11604 MockRead(ASYNC, ERR_IO_PENDING, 7) | |
| 11605 }; | |
| 11606 | |
| 11607 OrderedSocketData data(reads, arraysize(reads), | |
| 11608 writes, arraysize(writes)); | |
| 11609 | |
| 11610 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 11611 ssl.SetNextProto(GetParam()); | |
| 11612 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 11613 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 11614 | |
| 11615 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 11616 | |
| 11617 // Start the first transaction to set up the SpdySession | |
| 11618 HttpRequestInfo request1; | |
| 11619 request1.method = "GET"; | |
| 11620 request1.url = GURL(https_url); | |
| 11621 request1.load_flags = 0; | |
| 11622 HttpNetworkTransaction trans1(LOWEST, session.get()); | |
| 11623 TestCompletionCallback callback1; | |
| 11624 EXPECT_EQ(ERR_IO_PENDING, | |
| 11625 trans1.Start(&request1, callback1.callback(), BoundNetLog())); | |
| 11626 base::MessageLoop::current()->RunUntilIdle(); | |
| 11627 | |
| 11628 EXPECT_EQ(OK, callback1.WaitForResult()); | |
| 11629 EXPECT_TRUE(trans1.GetResponseInfo()->was_fetched_via_spdy); | |
| 11630 | |
| 11631 // Now, start the HTTP request | |
| 11632 HttpRequestInfo request2; | |
| 11633 request2.method = "GET"; | |
| 11634 request2.url = GURL(http_url); | |
| 11635 request2.load_flags = 0; | |
| 11636 HttpNetworkTransaction trans2(MEDIUM, session.get()); | |
| 11637 TestCompletionCallback callback2; | |
| 11638 EXPECT_EQ(ERR_IO_PENDING, | |
| 11639 trans2.Start(&request2, callback2.callback(), BoundNetLog())); | |
| 11640 base::MessageLoop::current()->RunUntilIdle(); | |
| 11641 | |
| 11642 EXPECT_EQ(OK, callback2.WaitForResult()); | |
| 11643 EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy); | |
| 11644 } | |
| 11645 | |
| 11646 // Test that in the case where we have a SPDY session to a SPDY proxy | |
| 11647 // that we do not pool other origins that resolve to the same IP when | |
| 11648 // the certificate does not match the new origin. | |
| 11649 // http://crbug.com/134690 | |
| 11650 TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionIfCertDoesNotMatch) { | |
| 11651 const std::string url1 = "http://www.google.com/"; | |
| 11652 const std::string url2 = "https://mail.google.com/"; | |
| 11653 const std::string ip_addr = "1.2.3.4"; | |
| 11654 | |
| 11655 // SPDY GET for HTTP URL (through SPDY proxy) | |
| 11656 scoped_ptr<SpdyHeaderBlock> headers( | |
| 11657 spdy_util_.ConstructGetHeaderBlockForProxy("http://www.google.com/")); | |
| 11658 scoped_ptr<SpdyFrame> req1( | |
| 11659 spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true)); | |
| 11660 | |
| 11661 MockWrite writes1[] = { | |
| 11662 CreateMockWrite(*req1, 0), | |
| 11663 }; | |
| 11664 | |
| 11665 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11666 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 11667 MockRead reads1[] = { | |
| 11668 CreateMockRead(*resp1, 1), | |
| 11669 CreateMockRead(*body1, 2), | |
| 11670 MockRead(ASYNC, OK, 3) // EOF | |
| 11671 }; | |
| 11672 | |
| 11673 scoped_ptr<DeterministicSocketData> data1( | |
| 11674 new DeterministicSocketData(reads1, arraysize(reads1), | |
| 11675 writes1, arraysize(writes1))); | |
| 11676 IPAddressNumber ip; | |
| 11677 ASSERT_TRUE(ParseIPLiteralToNumber(ip_addr, &ip)); | |
| 11678 IPEndPoint peer_addr = IPEndPoint(ip, 443); | |
| 11679 MockConnect connect_data1(ASYNC, OK, peer_addr); | |
| 11680 data1->set_connect_data(connect_data1); | |
| 11681 | |
| 11682 // SPDY GET for HTTPS URL (direct) | |
| 11683 scoped_ptr<SpdyFrame> req2( | |
| 11684 spdy_util_.ConstructSpdyGet(url2.c_str(), false, 1, MEDIUM)); | |
| 11685 | |
| 11686 MockWrite writes2[] = { | |
| 11687 CreateMockWrite(*req2, 0), | |
| 11688 }; | |
| 11689 | |
| 11690 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11691 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 11692 MockRead reads2[] = { | |
| 11693 CreateMockRead(*resp2, 1), | |
| 11694 CreateMockRead(*body2, 2), | |
| 11695 MockRead(ASYNC, OK, 3) // EOF | |
| 11696 }; | |
| 11697 | |
| 11698 scoped_ptr<DeterministicSocketData> data2( | |
| 11699 new DeterministicSocketData(reads2, arraysize(reads2), | |
| 11700 writes2, arraysize(writes2))); | |
| 11701 MockConnect connect_data2(ASYNC, OK); | |
| 11702 data2->set_connect_data(connect_data2); | |
| 11703 | |
| 11704 // Set up a proxy config that sends HTTP requests to a proxy, and | |
| 11705 // all others direct. | |
| 11706 ProxyConfig proxy_config; | |
| 11707 proxy_config.proxy_rules().ParseFromString("http=https://proxy:443"); | |
| 11708 CapturingProxyResolver* capturing_proxy_resolver = | |
| 11709 new CapturingProxyResolver(); | |
| 11710 session_deps_.proxy_service.reset(new ProxyService( | |
| 11711 new ProxyConfigServiceFixed(proxy_config), capturing_proxy_resolver, | |
| 11712 NULL)); | |
| 11713 | |
| 11714 // Load a valid cert. Note, that this does not need to | |
| 11715 // be valid for proxy because the MockSSLClientSocket does | |
| 11716 // not actually verify it. But SpdySession will use this | |
| 11717 // to see if it is valid for the new origin | |
| 11718 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 11719 scoped_refptr<X509Certificate> server_cert( | |
| 11720 ImportCertFromFile(certs_dir, "ok_cert.pem")); | |
| 11721 ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert.get()); | |
| 11722 | |
| 11723 SSLSocketDataProvider ssl1(ASYNC, OK); // to the proxy | |
| 11724 ssl1.SetNextProto(GetParam()); | |
| 11725 ssl1.cert = server_cert; | |
| 11726 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl1); | |
| 11727 session_deps_.deterministic_socket_factory->AddSocketDataProvider( | |
| 11728 data1.get()); | |
| 11729 | |
| 11730 SSLSocketDataProvider ssl2(ASYNC, OK); // to the server | |
| 11731 ssl2.SetNextProto(GetParam()); | |
| 11732 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl2); | |
| 11733 session_deps_.deterministic_socket_factory->AddSocketDataProvider( | |
| 11734 data2.get()); | |
| 11735 | |
| 11736 session_deps_.host_resolver.reset(new MockCachingHostResolver()); | |
| 11737 session_deps_.host_resolver->rules()->AddRule("mail.google.com", ip_addr); | |
| 11738 session_deps_.host_resolver->rules()->AddRule("proxy", ip_addr); | |
| 11739 | |
| 11740 scoped_refptr<HttpNetworkSession> session( | |
| 11741 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_)); | |
| 11742 | |
| 11743 // Start the first transaction to set up the SpdySession | |
| 11744 HttpRequestInfo request1; | |
| 11745 request1.method = "GET"; | |
| 11746 request1.url = GURL(url1); | |
| 11747 request1.load_flags = 0; | |
| 11748 HttpNetworkTransaction trans1(LOWEST, session.get()); | |
| 11749 TestCompletionCallback callback1; | |
| 11750 ASSERT_EQ(ERR_IO_PENDING, | |
| 11751 trans1.Start(&request1, callback1.callback(), BoundNetLog())); | |
| 11752 data1->RunFor(3); | |
| 11753 | |
| 11754 ASSERT_TRUE(callback1.have_result()); | |
| 11755 EXPECT_EQ(OK, callback1.WaitForResult()); | |
| 11756 EXPECT_TRUE(trans1.GetResponseInfo()->was_fetched_via_spdy); | |
| 11757 | |
| 11758 // Now, start the HTTP request | |
| 11759 HttpRequestInfo request2; | |
| 11760 request2.method = "GET"; | |
| 11761 request2.url = GURL(url2); | |
| 11762 request2.load_flags = 0; | |
| 11763 HttpNetworkTransaction trans2(MEDIUM, session.get()); | |
| 11764 TestCompletionCallback callback2; | |
| 11765 EXPECT_EQ(ERR_IO_PENDING, | |
| 11766 trans2.Start(&request2, callback2.callback(), BoundNetLog())); | |
| 11767 base::MessageLoop::current()->RunUntilIdle(); | |
| 11768 data2->RunFor(3); | |
| 11769 | |
| 11770 ASSERT_TRUE(callback2.have_result()); | |
| 11771 EXPECT_EQ(OK, callback2.WaitForResult()); | |
| 11772 EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy); | |
| 11773 } | |
| 11774 | |
| 11775 // Test to verify that a failed socket read (due to an ERR_CONNECTION_CLOSED | |
| 11776 // error) in SPDY session, removes the socket from pool and closes the SPDY | |
| 11777 // session. Verify that new url's from the same HttpNetworkSession (and a new | |
| 11778 // SpdySession) do work. http://crbug.com/224701 | |
| 11779 TEST_P(HttpNetworkTransactionTest, ErrorSocketNotConnected) { | |
| 11780 const std::string https_url = "https://www.google.com/"; | |
| 11781 | |
| 11782 MockRead reads1[] = { | |
| 11783 MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED, 0) | |
| 11784 }; | |
| 11785 | |
| 11786 scoped_ptr<DeterministicSocketData> data1( | |
| 11787 new DeterministicSocketData(reads1, arraysize(reads1), NULL, 0)); | |
| 11788 data1->SetStop(1); | |
| 11789 | |
| 11790 scoped_ptr<SpdyFrame> req2( | |
| 11791 spdy_util_.ConstructSpdyGet(https_url.c_str(), false, 1, MEDIUM)); | |
| 11792 MockWrite writes2[] = { | |
| 11793 CreateMockWrite(*req2, 0), | |
| 11794 }; | |
| 11795 | |
| 11796 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11797 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 11798 MockRead reads2[] = { | |
| 11799 CreateMockRead(*resp2, 1), | |
| 11800 CreateMockRead(*body2, 2), | |
| 11801 MockRead(ASYNC, OK, 3) // EOF | |
| 11802 }; | |
| 11803 | |
| 11804 scoped_ptr<DeterministicSocketData> data2( | |
| 11805 new DeterministicSocketData(reads2, arraysize(reads2), | |
| 11806 writes2, arraysize(writes2))); | |
| 11807 | |
| 11808 SSLSocketDataProvider ssl1(ASYNC, OK); | |
| 11809 ssl1.SetNextProto(GetParam()); | |
| 11810 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl1); | |
| 11811 session_deps_.deterministic_socket_factory->AddSocketDataProvider( | |
| 11812 data1.get()); | |
| 11813 | |
| 11814 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 11815 ssl2.SetNextProto(GetParam()); | |
| 11816 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl2); | |
| 11817 session_deps_.deterministic_socket_factory->AddSocketDataProvider( | |
| 11818 data2.get()); | |
| 11819 | |
| 11820 scoped_refptr<HttpNetworkSession> session( | |
| 11821 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_)); | |
| 11822 | |
| 11823 // Start the first transaction to set up the SpdySession and verify that | |
| 11824 // connection was closed. | |
| 11825 HttpRequestInfo request1; | |
| 11826 request1.method = "GET"; | |
| 11827 request1.url = GURL(https_url); | |
| 11828 request1.load_flags = 0; | |
| 11829 HttpNetworkTransaction trans1(MEDIUM, session.get()); | |
| 11830 TestCompletionCallback callback1; | |
| 11831 EXPECT_EQ(ERR_IO_PENDING, | |
| 11832 trans1.Start(&request1, callback1.callback(), BoundNetLog())); | |
| 11833 base::MessageLoop::current()->RunUntilIdle(); | |
| 11834 EXPECT_EQ(ERR_CONNECTION_CLOSED, callback1.WaitForResult()); | |
| 11835 | |
| 11836 // Now, start the second request and make sure it succeeds. | |
| 11837 HttpRequestInfo request2; | |
| 11838 request2.method = "GET"; | |
| 11839 request2.url = GURL(https_url); | |
| 11840 request2.load_flags = 0; | |
| 11841 HttpNetworkTransaction trans2(MEDIUM, session.get()); | |
| 11842 TestCompletionCallback callback2; | |
| 11843 EXPECT_EQ(ERR_IO_PENDING, | |
| 11844 trans2.Start(&request2, callback2.callback(), BoundNetLog())); | |
| 11845 base::MessageLoop::current()->RunUntilIdle(); | |
| 11846 data2->RunFor(3); | |
| 11847 | |
| 11848 ASSERT_TRUE(callback2.have_result()); | |
| 11849 EXPECT_EQ(OK, callback2.WaitForResult()); | |
| 11850 EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy); | |
| 11851 } | |
| 11852 | |
| 11853 TEST_P(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) { | |
| 11854 session_deps_.next_protos = SpdyNextProtos(); | |
| 11855 ClientSocketPoolManager::set_max_sockets_per_group( | |
| 11856 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
| 11857 ClientSocketPoolManager::set_max_sockets_per_pool( | |
| 11858 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
| 11859 | |
| 11860 // Use two different hosts with different IPs so they don't get pooled. | |
| 11861 session_deps_.host_resolver->rules()->AddRule("www.a.com", "10.0.0.1"); | |
| 11862 session_deps_.host_resolver->rules()->AddRule("www.b.com", "10.0.0.2"); | |
| 11863 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 11864 | |
| 11865 SSLSocketDataProvider ssl1(ASYNC, OK); | |
| 11866 ssl1.SetNextProto(GetParam()); | |
| 11867 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 11868 ssl2.SetNextProto(GetParam()); | |
| 11869 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1); | |
| 11870 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2); | |
| 11871 | |
| 11872 scoped_ptr<SpdyFrame> host1_req(spdy_util_.ConstructSpdyGet( | |
| 11873 "https://www.a.com", false, 1, DEFAULT_PRIORITY)); | |
| 11874 MockWrite spdy1_writes[] = { | |
| 11875 CreateMockWrite(*host1_req, 1), | |
| 11876 }; | |
| 11877 scoped_ptr<SpdyFrame> host1_resp( | |
| 11878 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11879 scoped_ptr<SpdyFrame> host1_resp_body( | |
| 11880 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 11881 MockRead spdy1_reads[] = { | |
| 11882 CreateMockRead(*host1_resp, 2), | |
| 11883 CreateMockRead(*host1_resp_body, 3), | |
| 11884 MockRead(ASYNC, ERR_IO_PENDING, 4), | |
| 11885 }; | |
| 11886 | |
| 11887 scoped_ptr<OrderedSocketData> spdy1_data( | |
| 11888 new OrderedSocketData( | |
| 11889 spdy1_reads, arraysize(spdy1_reads), | |
| 11890 spdy1_writes, arraysize(spdy1_writes))); | |
| 11891 session_deps_.socket_factory->AddSocketDataProvider(spdy1_data.get()); | |
| 11892 | |
| 11893 scoped_ptr<SpdyFrame> host2_req(spdy_util_.ConstructSpdyGet( | |
| 11894 "https://www.b.com", false, 1, DEFAULT_PRIORITY)); | |
| 11895 MockWrite spdy2_writes[] = { | |
| 11896 CreateMockWrite(*host2_req, 1), | |
| 11897 }; | |
| 11898 scoped_ptr<SpdyFrame> host2_resp( | |
| 11899 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 11900 scoped_ptr<SpdyFrame> host2_resp_body( | |
| 11901 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
| 11902 MockRead spdy2_reads[] = { | |
| 11903 CreateMockRead(*host2_resp, 2), | |
| 11904 CreateMockRead(*host2_resp_body, 3), | |
| 11905 MockRead(ASYNC, ERR_IO_PENDING, 4), | |
| 11906 }; | |
| 11907 | |
| 11908 scoped_ptr<OrderedSocketData> spdy2_data( | |
| 11909 new OrderedSocketData( | |
| 11910 spdy2_reads, arraysize(spdy2_reads), | |
| 11911 spdy2_writes, arraysize(spdy2_writes))); | |
| 11912 session_deps_.socket_factory->AddSocketDataProvider(spdy2_data.get()); | |
| 11913 | |
| 11914 MockWrite http_write[] = { | |
| 11915 MockWrite("GET / HTTP/1.1\r\n" | |
| 11916 "Host: www.a.com\r\n" | |
| 11917 "Connection: keep-alive\r\n\r\n"), | |
| 11918 }; | |
| 11919 | |
| 11920 MockRead http_read[] = { | |
| 11921 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 11922 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 11923 MockRead("Content-Length: 6\r\n\r\n"), | |
| 11924 MockRead("hello!"), | |
| 11925 }; | |
| 11926 StaticSocketDataProvider http_data(http_read, arraysize(http_read), | |
| 11927 http_write, arraysize(http_write)); | |
| 11928 session_deps_.socket_factory->AddSocketDataProvider(&http_data); | |
| 11929 | |
| 11930 HostPortPair host_port_pair_a("www.a.com", 443); | |
| 11931 SpdySessionKey spdy_session_key_a( | |
| 11932 host_port_pair_a, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); | |
| 11933 EXPECT_FALSE( | |
| 11934 HasSpdySession(session->spdy_session_pool(), spdy_session_key_a)); | |
| 11935 | |
| 11936 TestCompletionCallback callback; | |
| 11937 HttpRequestInfo request1; | |
| 11938 request1.method = "GET"; | |
| 11939 request1.url = GURL("https://www.a.com/"); | |
| 11940 request1.load_flags = 0; | |
| 11941 scoped_ptr<HttpNetworkTransaction> trans( | |
| 11942 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 11943 | |
| 11944 int rv = trans->Start(&request1, callback.callback(), BoundNetLog()); | |
| 11945 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 11946 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 11947 | |
| 11948 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 11949 ASSERT_TRUE(response != NULL); | |
| 11950 ASSERT_TRUE(response->headers.get() != NULL); | |
| 11951 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 11952 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 11953 EXPECT_TRUE(response->was_npn_negotiated); | |
| 11954 | |
| 11955 std::string response_data; | |
| 11956 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 11957 EXPECT_EQ("hello!", response_data); | |
| 11958 trans.reset(); | |
| 11959 EXPECT_TRUE( | |
| 11960 HasSpdySession(session->spdy_session_pool(), spdy_session_key_a)); | |
| 11961 | |
| 11962 HostPortPair host_port_pair_b("www.b.com", 443); | |
| 11963 SpdySessionKey spdy_session_key_b( | |
| 11964 host_port_pair_b, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); | |
| 11965 EXPECT_FALSE( | |
| 11966 HasSpdySession(session->spdy_session_pool(), spdy_session_key_b)); | |
| 11967 HttpRequestInfo request2; | |
| 11968 request2.method = "GET"; | |
| 11969 request2.url = GURL("https://www.b.com/"); | |
| 11970 request2.load_flags = 0; | |
| 11971 trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 11972 | |
| 11973 rv = trans->Start(&request2, callback.callback(), BoundNetLog()); | |
| 11974 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 11975 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 11976 | |
| 11977 response = trans->GetResponseInfo(); | |
| 11978 ASSERT_TRUE(response != NULL); | |
| 11979 ASSERT_TRUE(response->headers.get() != NULL); | |
| 11980 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 11981 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 11982 EXPECT_TRUE(response->was_npn_negotiated); | |
| 11983 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 11984 EXPECT_EQ("hello!", response_data); | |
| 11985 EXPECT_FALSE( | |
| 11986 HasSpdySession(session->spdy_session_pool(), spdy_session_key_a)); | |
| 11987 EXPECT_TRUE( | |
| 11988 HasSpdySession(session->spdy_session_pool(), spdy_session_key_b)); | |
| 11989 | |
| 11990 HostPortPair host_port_pair_a1("www.a.com", 80); | |
| 11991 SpdySessionKey spdy_session_key_a1( | |
| 11992 host_port_pair_a1, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); | |
| 11993 EXPECT_FALSE( | |
| 11994 HasSpdySession(session->spdy_session_pool(), spdy_session_key_a1)); | |
| 11995 HttpRequestInfo request3; | |
| 11996 request3.method = "GET"; | |
| 11997 request3.url = GURL("http://www.a.com/"); | |
| 11998 request3.load_flags = 0; | |
| 11999 trans.reset(new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12000 | |
| 12001 rv = trans->Start(&request3, callback.callback(), BoundNetLog()); | |
| 12002 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 12003 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 12004 | |
| 12005 response = trans->GetResponseInfo(); | |
| 12006 ASSERT_TRUE(response != NULL); | |
| 12007 ASSERT_TRUE(response->headers.get() != NULL); | |
| 12008 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 12009 EXPECT_FALSE(response->was_fetched_via_spdy); | |
| 12010 EXPECT_FALSE(response->was_npn_negotiated); | |
| 12011 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 12012 EXPECT_EQ("hello!", response_data); | |
| 12013 EXPECT_FALSE( | |
| 12014 HasSpdySession(session->spdy_session_pool(), spdy_session_key_a)); | |
| 12015 EXPECT_FALSE( | |
| 12016 HasSpdySession(session->spdy_session_pool(), spdy_session_key_b)); | |
| 12017 } | |
| 12018 | |
| 12019 TEST_P(HttpNetworkTransactionTest, HttpSyncConnectError) { | |
| 12020 HttpRequestInfo request; | |
| 12021 request.method = "GET"; | |
| 12022 request.url = GURL("http://www.google.com/"); | |
| 12023 request.load_flags = 0; | |
| 12024 | |
| 12025 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12026 scoped_ptr<HttpTransaction> trans( | |
| 12027 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12028 | |
| 12029 MockConnect mock_connect(SYNCHRONOUS, ERR_CONNECTION_REFUSED); | |
| 12030 StaticSocketDataProvider data; | |
| 12031 data.set_connect_data(mock_connect); | |
| 12032 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 12033 | |
| 12034 TestCompletionCallback callback; | |
| 12035 | |
| 12036 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 12037 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 12038 | |
| 12039 rv = callback.WaitForResult(); | |
| 12040 EXPECT_EQ(ERR_CONNECTION_REFUSED, rv); | |
| 12041 | |
| 12042 EXPECT_EQ(NULL, trans->GetResponseInfo()); | |
| 12043 | |
| 12044 // We don't care whether this succeeds or fails, but it shouldn't crash. | |
| 12045 HttpRequestHeaders request_headers; | |
| 12046 trans->GetFullRequestHeaders(&request_headers); | |
| 12047 } | |
| 12048 | |
| 12049 TEST_P(HttpNetworkTransactionTest, HttpAsyncConnectError) { | |
| 12050 HttpRequestInfo request; | |
| 12051 request.method = "GET"; | |
| 12052 request.url = GURL("http://www.google.com/"); | |
| 12053 request.load_flags = 0; | |
| 12054 | |
| 12055 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12056 scoped_ptr<HttpTransaction> trans( | |
| 12057 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12058 | |
| 12059 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 12060 StaticSocketDataProvider data; | |
| 12061 data.set_connect_data(mock_connect); | |
| 12062 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 12063 | |
| 12064 TestCompletionCallback callback; | |
| 12065 | |
| 12066 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 12067 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 12068 | |
| 12069 rv = callback.WaitForResult(); | |
| 12070 EXPECT_EQ(ERR_CONNECTION_REFUSED, rv); | |
| 12071 | |
| 12072 EXPECT_EQ(NULL, trans->GetResponseInfo()); | |
| 12073 | |
| 12074 // We don't care whether this succeeds or fails, but it shouldn't crash. | |
| 12075 HttpRequestHeaders request_headers; | |
| 12076 trans->GetFullRequestHeaders(&request_headers); | |
| 12077 } | |
| 12078 | |
| 12079 TEST_P(HttpNetworkTransactionTest, HttpSyncWriteError) { | |
| 12080 HttpRequestInfo request; | |
| 12081 request.method = "GET"; | |
| 12082 request.url = GURL("http://www.google.com/"); | |
| 12083 request.load_flags = 0; | |
| 12084 | |
| 12085 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12086 scoped_ptr<HttpTransaction> trans( | |
| 12087 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12088 | |
| 12089 MockWrite data_writes[] = { | |
| 12090 MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), | |
| 12091 }; | |
| 12092 MockRead data_reads[] = { | |
| 12093 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 12094 }; | |
| 12095 | |
| 12096 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 12097 data_writes, arraysize(data_writes)); | |
| 12098 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 12099 | |
| 12100 TestCompletionCallback callback; | |
| 12101 | |
| 12102 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 12103 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 12104 | |
| 12105 rv = callback.WaitForResult(); | |
| 12106 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 12107 | |
| 12108 EXPECT_EQ(NULL, trans->GetResponseInfo()); | |
| 12109 | |
| 12110 HttpRequestHeaders request_headers; | |
| 12111 EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); | |
| 12112 EXPECT_TRUE(request_headers.HasHeader("Host")); | |
| 12113 } | |
| 12114 | |
| 12115 TEST_P(HttpNetworkTransactionTest, HttpAsyncWriteError) { | |
| 12116 HttpRequestInfo request; | |
| 12117 request.method = "GET"; | |
| 12118 request.url = GURL("http://www.google.com/"); | |
| 12119 request.load_flags = 0; | |
| 12120 | |
| 12121 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12122 scoped_ptr<HttpTransaction> trans( | |
| 12123 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12124 | |
| 12125 MockWrite data_writes[] = { | |
| 12126 MockWrite(ASYNC, ERR_CONNECTION_RESET), | |
| 12127 }; | |
| 12128 MockRead data_reads[] = { | |
| 12129 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 12130 }; | |
| 12131 | |
| 12132 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 12133 data_writes, arraysize(data_writes)); | |
| 12134 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 12135 | |
| 12136 TestCompletionCallback callback; | |
| 12137 | |
| 12138 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 12139 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 12140 | |
| 12141 rv = callback.WaitForResult(); | |
| 12142 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 12143 | |
| 12144 EXPECT_EQ(NULL, trans->GetResponseInfo()); | |
| 12145 | |
| 12146 HttpRequestHeaders request_headers; | |
| 12147 EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); | |
| 12148 EXPECT_TRUE(request_headers.HasHeader("Host")); | |
| 12149 } | |
| 12150 | |
| 12151 TEST_P(HttpNetworkTransactionTest, HttpSyncReadError) { | |
| 12152 HttpRequestInfo request; | |
| 12153 request.method = "GET"; | |
| 12154 request.url = GURL("http://www.google.com/"); | |
| 12155 request.load_flags = 0; | |
| 12156 | |
| 12157 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12158 scoped_ptr<HttpTransaction> trans( | |
| 12159 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12160 | |
| 12161 MockWrite data_writes[] = { | |
| 12162 MockWrite("GET / HTTP/1.1\r\n" | |
| 12163 "Host: www.google.com\r\n" | |
| 12164 "Connection: keep-alive\r\n\r\n"), | |
| 12165 }; | |
| 12166 MockRead data_reads[] = { | |
| 12167 MockRead(SYNCHRONOUS, ERR_CONNECTION_RESET), | |
| 12168 }; | |
| 12169 | |
| 12170 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 12171 data_writes, arraysize(data_writes)); | |
| 12172 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 12173 | |
| 12174 TestCompletionCallback callback; | |
| 12175 | |
| 12176 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 12177 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 12178 | |
| 12179 rv = callback.WaitForResult(); | |
| 12180 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 12181 | |
| 12182 EXPECT_EQ(NULL, trans->GetResponseInfo()); | |
| 12183 | |
| 12184 HttpRequestHeaders request_headers; | |
| 12185 EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); | |
| 12186 EXPECT_TRUE(request_headers.HasHeader("Host")); | |
| 12187 } | |
| 12188 | |
| 12189 TEST_P(HttpNetworkTransactionTest, HttpAsyncReadError) { | |
| 12190 HttpRequestInfo request; | |
| 12191 request.method = "GET"; | |
| 12192 request.url = GURL("http://www.google.com/"); | |
| 12193 request.load_flags = 0; | |
| 12194 | |
| 12195 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12196 scoped_ptr<HttpTransaction> trans( | |
| 12197 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12198 | |
| 12199 MockWrite data_writes[] = { | |
| 12200 MockWrite("GET / HTTP/1.1\r\n" | |
| 12201 "Host: www.google.com\r\n" | |
| 12202 "Connection: keep-alive\r\n\r\n"), | |
| 12203 }; | |
| 12204 MockRead data_reads[] = { | |
| 12205 MockRead(ASYNC, ERR_CONNECTION_RESET), | |
| 12206 }; | |
| 12207 | |
| 12208 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 12209 data_writes, arraysize(data_writes)); | |
| 12210 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 12211 | |
| 12212 TestCompletionCallback callback; | |
| 12213 | |
| 12214 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 12215 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 12216 | |
| 12217 rv = callback.WaitForResult(); | |
| 12218 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 12219 | |
| 12220 EXPECT_EQ(NULL, trans->GetResponseInfo()); | |
| 12221 | |
| 12222 HttpRequestHeaders request_headers; | |
| 12223 EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); | |
| 12224 EXPECT_TRUE(request_headers.HasHeader("Host")); | |
| 12225 } | |
| 12226 | |
| 12227 TEST_P(HttpNetworkTransactionTest, GetFullRequestHeadersIncludesExtraHeader) { | |
| 12228 HttpRequestInfo request; | |
| 12229 request.method = "GET"; | |
| 12230 request.url = GURL("http://www.google.com/"); | |
| 12231 request.load_flags = 0; | |
| 12232 request.extra_headers.SetHeader("X-Foo", "bar"); | |
| 12233 | |
| 12234 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12235 scoped_ptr<HttpTransaction> trans( | |
| 12236 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12237 | |
| 12238 MockWrite data_writes[] = { | |
| 12239 MockWrite("GET / HTTP/1.1\r\n" | |
| 12240 "Host: www.google.com\r\n" | |
| 12241 "Connection: keep-alive\r\n" | |
| 12242 "X-Foo: bar\r\n\r\n"), | |
| 12243 }; | |
| 12244 MockRead data_reads[] = { | |
| 12245 MockRead("HTTP/1.1 200 OK\r\n" | |
| 12246 "Content-Length: 5\r\n\r\n" | |
| 12247 "hello"), | |
| 12248 MockRead(ASYNC, ERR_UNEXPECTED), | |
| 12249 }; | |
| 12250 | |
| 12251 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 12252 data_writes, arraysize(data_writes)); | |
| 12253 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 12254 | |
| 12255 TestCompletionCallback callback; | |
| 12256 | |
| 12257 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 12258 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 12259 | |
| 12260 rv = callback.WaitForResult(); | |
| 12261 EXPECT_EQ(OK, rv); | |
| 12262 | |
| 12263 HttpRequestHeaders request_headers; | |
| 12264 EXPECT_TRUE(trans->GetFullRequestHeaders(&request_headers)); | |
| 12265 std::string foo; | |
| 12266 EXPECT_TRUE(request_headers.GetHeader("X-Foo", &foo)); | |
| 12267 EXPECT_EQ("bar", foo); | |
| 12268 } | |
| 12269 | |
| 12270 namespace { | |
| 12271 | |
| 12272 // Fake HttpStream that simply records calls to SetPriority(). | |
| 12273 class FakeStream : public HttpStream, | |
| 12274 public base::SupportsWeakPtr<FakeStream> { | |
| 12275 public: | |
| 12276 explicit FakeStream(RequestPriority priority) : priority_(priority) {} | |
| 12277 ~FakeStream() override {} | |
| 12278 | |
| 12279 RequestPriority priority() const { return priority_; } | |
| 12280 | |
| 12281 int InitializeStream(const HttpRequestInfo* request_info, | |
| 12282 RequestPriority priority, | |
| 12283 const BoundNetLog& net_log, | |
| 12284 const CompletionCallback& callback) override { | |
| 12285 return ERR_IO_PENDING; | |
| 12286 } | |
| 12287 | |
| 12288 int SendRequest(const HttpRequestHeaders& request_headers, | |
| 12289 HttpResponseInfo* response, | |
| 12290 const CompletionCallback& callback) override { | |
| 12291 ADD_FAILURE(); | |
| 12292 return ERR_UNEXPECTED; | |
| 12293 } | |
| 12294 | |
| 12295 int ReadResponseHeaders(const CompletionCallback& callback) override { | |
| 12296 ADD_FAILURE(); | |
| 12297 return ERR_UNEXPECTED; | |
| 12298 } | |
| 12299 | |
| 12300 int ReadResponseBody(IOBuffer* buf, | |
| 12301 int buf_len, | |
| 12302 const CompletionCallback& callback) override { | |
| 12303 ADD_FAILURE(); | |
| 12304 return ERR_UNEXPECTED; | |
| 12305 } | |
| 12306 | |
| 12307 void Close(bool not_reusable) override {} | |
| 12308 | |
| 12309 bool IsResponseBodyComplete() const override { | |
| 12310 ADD_FAILURE(); | |
| 12311 return false; | |
| 12312 } | |
| 12313 | |
| 12314 bool CanFindEndOfResponse() const override { return false; } | |
| 12315 | |
| 12316 bool IsConnectionReused() const override { | |
| 12317 ADD_FAILURE(); | |
| 12318 return false; | |
| 12319 } | |
| 12320 | |
| 12321 void SetConnectionReused() override { ADD_FAILURE(); } | |
| 12322 | |
| 12323 bool IsConnectionReusable() const override { | |
| 12324 ADD_FAILURE(); | |
| 12325 return false; | |
| 12326 } | |
| 12327 | |
| 12328 int64 GetTotalReceivedBytes() const override { | |
| 12329 ADD_FAILURE(); | |
| 12330 return 0; | |
| 12331 } | |
| 12332 | |
| 12333 bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override { | |
| 12334 ADD_FAILURE(); | |
| 12335 return false; | |
| 12336 } | |
| 12337 | |
| 12338 void GetSSLInfo(SSLInfo* ssl_info) override { ADD_FAILURE(); } | |
| 12339 | |
| 12340 void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override { | |
| 12341 ADD_FAILURE(); | |
| 12342 } | |
| 12343 | |
| 12344 bool IsSpdyHttpStream() const override { | |
| 12345 ADD_FAILURE(); | |
| 12346 return false; | |
| 12347 } | |
| 12348 | |
| 12349 void Drain(HttpNetworkSession* session) override { ADD_FAILURE(); } | |
| 12350 | |
| 12351 void SetPriority(RequestPriority priority) override { priority_ = priority; } | |
| 12352 | |
| 12353 UploadProgress GetUploadProgress() const override { return UploadProgress(); } | |
| 12354 | |
| 12355 HttpStream* RenewStreamForAuth() override { return NULL; } | |
| 12356 | |
| 12357 private: | |
| 12358 RequestPriority priority_; | |
| 12359 | |
| 12360 DISALLOW_COPY_AND_ASSIGN(FakeStream); | |
| 12361 }; | |
| 12362 | |
| 12363 // Fake HttpStreamRequest that simply records calls to SetPriority() | |
| 12364 // and vends FakeStreams with its current priority. | |
| 12365 class FakeStreamRequest : public HttpStreamRequest, | |
| 12366 public base::SupportsWeakPtr<FakeStreamRequest> { | |
| 12367 public: | |
| 12368 FakeStreamRequest(RequestPriority priority, | |
| 12369 HttpStreamRequest::Delegate* delegate) | |
| 12370 : priority_(priority), | |
| 12371 delegate_(delegate), | |
| 12372 websocket_stream_create_helper_(NULL) {} | |
| 12373 | |
| 12374 FakeStreamRequest(RequestPriority priority, | |
| 12375 HttpStreamRequest::Delegate* delegate, | |
| 12376 WebSocketHandshakeStreamBase::CreateHelper* create_helper) | |
| 12377 : priority_(priority), | |
| 12378 delegate_(delegate), | |
| 12379 websocket_stream_create_helper_(create_helper) {} | |
| 12380 | |
| 12381 ~FakeStreamRequest() override {} | |
| 12382 | |
| 12383 RequestPriority priority() const { return priority_; } | |
| 12384 | |
| 12385 const WebSocketHandshakeStreamBase::CreateHelper* | |
| 12386 websocket_stream_create_helper() const { | |
| 12387 return websocket_stream_create_helper_; | |
| 12388 } | |
| 12389 | |
| 12390 // Create a new FakeStream and pass it to the request's | |
| 12391 // delegate. Returns a weak pointer to the FakeStream. | |
| 12392 base::WeakPtr<FakeStream> FinishStreamRequest() { | |
| 12393 FakeStream* fake_stream = new FakeStream(priority_); | |
| 12394 // Do this before calling OnStreamReady() as OnStreamReady() may | |
| 12395 // immediately delete |fake_stream|. | |
| 12396 base::WeakPtr<FakeStream> weak_stream = fake_stream->AsWeakPtr(); | |
| 12397 delegate_->OnStreamReady(SSLConfig(), ProxyInfo(), fake_stream); | |
| 12398 return weak_stream; | |
| 12399 } | |
| 12400 | |
| 12401 int RestartTunnelWithProxyAuth(const AuthCredentials& credentials) override { | |
| 12402 ADD_FAILURE(); | |
| 12403 return ERR_UNEXPECTED; | |
| 12404 } | |
| 12405 | |
| 12406 LoadState GetLoadState() const override { | |
| 12407 ADD_FAILURE(); | |
| 12408 return LoadState(); | |
| 12409 } | |
| 12410 | |
| 12411 void SetPriority(RequestPriority priority) override { priority_ = priority; } | |
| 12412 | |
| 12413 bool was_npn_negotiated() const override { return false; } | |
| 12414 | |
| 12415 NextProto protocol_negotiated() const override { return kProtoUnknown; } | |
| 12416 | |
| 12417 bool using_spdy() const override { return false; } | |
| 12418 | |
| 12419 private: | |
| 12420 RequestPriority priority_; | |
| 12421 HttpStreamRequest::Delegate* const delegate_; | |
| 12422 WebSocketHandshakeStreamBase::CreateHelper* websocket_stream_create_helper_; | |
| 12423 | |
| 12424 DISALLOW_COPY_AND_ASSIGN(FakeStreamRequest); | |
| 12425 }; | |
| 12426 | |
| 12427 // Fake HttpStreamFactory that vends FakeStreamRequests. | |
| 12428 class FakeStreamFactory : public HttpStreamFactory { | |
| 12429 public: | |
| 12430 FakeStreamFactory() {} | |
| 12431 ~FakeStreamFactory() override {} | |
| 12432 | |
| 12433 // Returns a WeakPtr<> to the last HttpStreamRequest returned by | |
| 12434 // RequestStream() (which may be NULL if it was destroyed already). | |
| 12435 base::WeakPtr<FakeStreamRequest> last_stream_request() { | |
| 12436 return last_stream_request_; | |
| 12437 } | |
| 12438 | |
| 12439 HttpStreamRequest* RequestStream(const HttpRequestInfo& info, | |
| 12440 RequestPriority priority, | |
| 12441 const SSLConfig& server_ssl_config, | |
| 12442 const SSLConfig& proxy_ssl_config, | |
| 12443 HttpStreamRequest::Delegate* delegate, | |
| 12444 const BoundNetLog& net_log) override { | |
| 12445 FakeStreamRequest* fake_request = new FakeStreamRequest(priority, delegate); | |
| 12446 last_stream_request_ = fake_request->AsWeakPtr(); | |
| 12447 return fake_request; | |
| 12448 } | |
| 12449 | |
| 12450 HttpStreamRequest* RequestWebSocketHandshakeStream( | |
| 12451 const HttpRequestInfo& info, | |
| 12452 RequestPriority priority, | |
| 12453 const SSLConfig& server_ssl_config, | |
| 12454 const SSLConfig& proxy_ssl_config, | |
| 12455 HttpStreamRequest::Delegate* delegate, | |
| 12456 WebSocketHandshakeStreamBase::CreateHelper* create_helper, | |
| 12457 const BoundNetLog& net_log) override { | |
| 12458 FakeStreamRequest* fake_request = | |
| 12459 new FakeStreamRequest(priority, delegate, create_helper); | |
| 12460 last_stream_request_ = fake_request->AsWeakPtr(); | |
| 12461 return fake_request; | |
| 12462 } | |
| 12463 | |
| 12464 void PreconnectStreams(int num_streams, | |
| 12465 const HttpRequestInfo& info, | |
| 12466 RequestPriority priority, | |
| 12467 const SSLConfig& server_ssl_config, | |
| 12468 const SSLConfig& proxy_ssl_config) override { | |
| 12469 ADD_FAILURE(); | |
| 12470 } | |
| 12471 | |
| 12472 const HostMappingRules* GetHostMappingRules() const override { | |
| 12473 ADD_FAILURE(); | |
| 12474 return NULL; | |
| 12475 } | |
| 12476 | |
| 12477 private: | |
| 12478 base::WeakPtr<FakeStreamRequest> last_stream_request_; | |
| 12479 | |
| 12480 DISALLOW_COPY_AND_ASSIGN(FakeStreamFactory); | |
| 12481 }; | |
| 12482 | |
| 12483 // TODO(ricea): Maybe unify this with the one in | |
| 12484 // url_request_http_job_unittest.cc ? | |
| 12485 class FakeWebSocketBasicHandshakeStream : public WebSocketHandshakeStreamBase { | |
| 12486 public: | |
| 12487 FakeWebSocketBasicHandshakeStream(scoped_ptr<ClientSocketHandle> connection, | |
| 12488 bool using_proxy) | |
| 12489 : state_(connection.release(), using_proxy) {} | |
| 12490 | |
| 12491 // Fake implementation of HttpStreamBase methods. | |
| 12492 // This ends up being quite "real" because this object has to really send data | |
| 12493 // on the mock socket. It might be easier to use the real implementation, but | |
| 12494 // the fact that the WebSocket code is not compiled on iOS makes that | |
| 12495 // difficult. | |
| 12496 int InitializeStream(const HttpRequestInfo* request_info, | |
| 12497 RequestPriority priority, | |
| 12498 const BoundNetLog& net_log, | |
| 12499 const CompletionCallback& callback) override { | |
| 12500 state_.Initialize(request_info, priority, net_log, callback); | |
| 12501 return OK; | |
| 12502 } | |
| 12503 | |
| 12504 int SendRequest(const HttpRequestHeaders& request_headers, | |
| 12505 HttpResponseInfo* response, | |
| 12506 const CompletionCallback& callback) override { | |
| 12507 return parser()->SendRequest(state_.GenerateRequestLine(), request_headers, | |
| 12508 response, callback); | |
| 12509 } | |
| 12510 | |
| 12511 int ReadResponseHeaders(const CompletionCallback& callback) override { | |
| 12512 return parser()->ReadResponseHeaders(callback); | |
| 12513 } | |
| 12514 | |
| 12515 int ReadResponseBody(IOBuffer* buf, | |
| 12516 int buf_len, | |
| 12517 const CompletionCallback& callback) override { | |
| 12518 NOTREACHED(); | |
| 12519 return ERR_IO_PENDING; | |
| 12520 } | |
| 12521 | |
| 12522 void Close(bool not_reusable) override { | |
| 12523 if (parser()) | |
| 12524 parser()->Close(true); | |
| 12525 } | |
| 12526 | |
| 12527 bool IsResponseBodyComplete() const override { | |
| 12528 NOTREACHED(); | |
| 12529 return false; | |
| 12530 } | |
| 12531 | |
| 12532 bool CanFindEndOfResponse() const override { | |
| 12533 return parser()->CanFindEndOfResponse(); | |
| 12534 } | |
| 12535 | |
| 12536 bool IsConnectionReused() const override { | |
| 12537 NOTREACHED(); | |
| 12538 return false; | |
| 12539 } | |
| 12540 void SetConnectionReused() override { NOTREACHED(); } | |
| 12541 | |
| 12542 bool IsConnectionReusable() const override { | |
| 12543 NOTREACHED(); | |
| 12544 return false; | |
| 12545 } | |
| 12546 | |
| 12547 int64 GetTotalReceivedBytes() const override { | |
| 12548 NOTREACHED(); | |
| 12549 return 0; | |
| 12550 } | |
| 12551 | |
| 12552 bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override { | |
| 12553 NOTREACHED(); | |
| 12554 return false; | |
| 12555 } | |
| 12556 | |
| 12557 void GetSSLInfo(SSLInfo* ssl_info) override { NOTREACHED(); } | |
| 12558 | |
| 12559 void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override { | |
| 12560 NOTREACHED(); | |
| 12561 } | |
| 12562 | |
| 12563 bool IsSpdyHttpStream() const override { | |
| 12564 NOTREACHED(); | |
| 12565 return false; | |
| 12566 } | |
| 12567 | |
| 12568 void Drain(HttpNetworkSession* session) override { NOTREACHED(); } | |
| 12569 | |
| 12570 void SetPriority(RequestPriority priority) override { NOTREACHED(); } | |
| 12571 | |
| 12572 UploadProgress GetUploadProgress() const override { | |
| 12573 NOTREACHED(); | |
| 12574 return UploadProgress(); | |
| 12575 } | |
| 12576 | |
| 12577 HttpStream* RenewStreamForAuth() override { | |
| 12578 NOTREACHED(); | |
| 12579 return nullptr; | |
| 12580 } | |
| 12581 | |
| 12582 // Fake implementation of WebSocketHandshakeStreamBase method(s) | |
| 12583 scoped_ptr<WebSocketStream> Upgrade() override { | |
| 12584 NOTREACHED(); | |
| 12585 return scoped_ptr<WebSocketStream>(); | |
| 12586 } | |
| 12587 | |
| 12588 private: | |
| 12589 HttpStreamParser* parser() const { return state_.parser(); } | |
| 12590 HttpBasicState state_; | |
| 12591 | |
| 12592 DISALLOW_COPY_AND_ASSIGN(FakeWebSocketBasicHandshakeStream); | |
| 12593 }; | |
| 12594 | |
| 12595 // TODO(yhirano): Split this class out into a net/websockets file, if it is | |
| 12596 // worth doing. | |
| 12597 class FakeWebSocketStreamCreateHelper : | |
| 12598 public WebSocketHandshakeStreamBase::CreateHelper { | |
| 12599 public: | |
| 12600 WebSocketHandshakeStreamBase* CreateBasicStream( | |
| 12601 scoped_ptr<ClientSocketHandle> connection, | |
| 12602 bool using_proxy) override { | |
| 12603 return new FakeWebSocketBasicHandshakeStream(connection.Pass(), | |
| 12604 using_proxy); | |
| 12605 } | |
| 12606 | |
| 12607 WebSocketHandshakeStreamBase* CreateSpdyStream( | |
| 12608 const base::WeakPtr<SpdySession>& session, | |
| 12609 bool use_relative_url) override { | |
| 12610 NOTREACHED(); | |
| 12611 return NULL; | |
| 12612 }; | |
| 12613 | |
| 12614 ~FakeWebSocketStreamCreateHelper() override {} | |
| 12615 | |
| 12616 virtual scoped_ptr<WebSocketStream> Upgrade() { | |
| 12617 NOTREACHED(); | |
| 12618 return scoped_ptr<WebSocketStream>(); | |
| 12619 } | |
| 12620 }; | |
| 12621 | |
| 12622 } // namespace | |
| 12623 | |
| 12624 // Make sure that HttpNetworkTransaction passes on its priority to its | |
| 12625 // stream request on start. | |
| 12626 TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriorityOnStart) { | |
| 12627 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12628 HttpNetworkSessionPeer peer(session); | |
| 12629 FakeStreamFactory* fake_factory = new FakeStreamFactory(); | |
| 12630 peer.SetHttpStreamFactory(scoped_ptr<HttpStreamFactory>(fake_factory)); | |
| 12631 | |
| 12632 HttpNetworkTransaction trans(LOW, session.get()); | |
| 12633 | |
| 12634 ASSERT_TRUE(fake_factory->last_stream_request() == NULL); | |
| 12635 | |
| 12636 HttpRequestInfo request; | |
| 12637 TestCompletionCallback callback; | |
| 12638 EXPECT_EQ(ERR_IO_PENDING, | |
| 12639 trans.Start(&request, callback.callback(), BoundNetLog())); | |
| 12640 | |
| 12641 base::WeakPtr<FakeStreamRequest> fake_request = | |
| 12642 fake_factory->last_stream_request(); | |
| 12643 ASSERT_TRUE(fake_request != NULL); | |
| 12644 EXPECT_EQ(LOW, fake_request->priority()); | |
| 12645 } | |
| 12646 | |
| 12647 // Make sure that HttpNetworkTransaction passes on its priority | |
| 12648 // updates to its stream request. | |
| 12649 TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriority) { | |
| 12650 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12651 HttpNetworkSessionPeer peer(session); | |
| 12652 FakeStreamFactory* fake_factory = new FakeStreamFactory(); | |
| 12653 peer.SetHttpStreamFactory(scoped_ptr<HttpStreamFactory>(fake_factory)); | |
| 12654 | |
| 12655 HttpNetworkTransaction trans(LOW, session.get()); | |
| 12656 | |
| 12657 HttpRequestInfo request; | |
| 12658 TestCompletionCallback callback; | |
| 12659 EXPECT_EQ(ERR_IO_PENDING, | |
| 12660 trans.Start(&request, callback.callback(), BoundNetLog())); | |
| 12661 | |
| 12662 base::WeakPtr<FakeStreamRequest> fake_request = | |
| 12663 fake_factory->last_stream_request(); | |
| 12664 ASSERT_TRUE(fake_request != NULL); | |
| 12665 EXPECT_EQ(LOW, fake_request->priority()); | |
| 12666 | |
| 12667 trans.SetPriority(LOWEST); | |
| 12668 ASSERT_TRUE(fake_request != NULL); | |
| 12669 EXPECT_EQ(LOWEST, fake_request->priority()); | |
| 12670 } | |
| 12671 | |
| 12672 // Make sure that HttpNetworkTransaction passes on its priority | |
| 12673 // updates to its stream. | |
| 12674 TEST_P(HttpNetworkTransactionTest, SetStreamPriority) { | |
| 12675 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12676 HttpNetworkSessionPeer peer(session); | |
| 12677 FakeStreamFactory* fake_factory = new FakeStreamFactory(); | |
| 12678 peer.SetHttpStreamFactory(scoped_ptr<HttpStreamFactory>(fake_factory)); | |
| 12679 | |
| 12680 HttpNetworkTransaction trans(LOW, session.get()); | |
| 12681 | |
| 12682 HttpRequestInfo request; | |
| 12683 TestCompletionCallback callback; | |
| 12684 EXPECT_EQ(ERR_IO_PENDING, | |
| 12685 trans.Start(&request, callback.callback(), BoundNetLog())); | |
| 12686 | |
| 12687 base::WeakPtr<FakeStreamRequest> fake_request = | |
| 12688 fake_factory->last_stream_request(); | |
| 12689 ASSERT_TRUE(fake_request != NULL); | |
| 12690 base::WeakPtr<FakeStream> fake_stream = fake_request->FinishStreamRequest(); | |
| 12691 ASSERT_TRUE(fake_stream != NULL); | |
| 12692 EXPECT_EQ(LOW, fake_stream->priority()); | |
| 12693 | |
| 12694 trans.SetPriority(LOWEST); | |
| 12695 EXPECT_EQ(LOWEST, fake_stream->priority()); | |
| 12696 } | |
| 12697 | |
| 12698 TEST_P(HttpNetworkTransactionTest, CreateWebSocketHandshakeStream) { | |
| 12699 // The same logic needs to be tested for both ws: and wss: schemes, but this | |
| 12700 // test is already parameterised on NextProto, so it uses a loop to verify | |
| 12701 // that the different schemes work. | |
| 12702 std::string test_cases[] = {"ws://www.google.com/", "wss://www.google.com/"}; | |
| 12703 for (size_t i = 0; i < arraysize(test_cases); ++i) { | |
| 12704 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12705 HttpNetworkSessionPeer peer(session); | |
| 12706 FakeStreamFactory* fake_factory = new FakeStreamFactory(); | |
| 12707 FakeWebSocketStreamCreateHelper websocket_stream_create_helper; | |
| 12708 peer.SetHttpStreamFactoryForWebSocket( | |
| 12709 scoped_ptr<HttpStreamFactory>(fake_factory)); | |
| 12710 | |
| 12711 HttpNetworkTransaction trans(LOW, session.get()); | |
| 12712 trans.SetWebSocketHandshakeStreamCreateHelper( | |
| 12713 &websocket_stream_create_helper); | |
| 12714 | |
| 12715 HttpRequestInfo request; | |
| 12716 TestCompletionCallback callback; | |
| 12717 request.method = "GET"; | |
| 12718 request.url = GURL(test_cases[i]); | |
| 12719 | |
| 12720 EXPECT_EQ(ERR_IO_PENDING, | |
| 12721 trans.Start(&request, callback.callback(), BoundNetLog())); | |
| 12722 | |
| 12723 base::WeakPtr<FakeStreamRequest> fake_request = | |
| 12724 fake_factory->last_stream_request(); | |
| 12725 ASSERT_TRUE(fake_request != NULL); | |
| 12726 EXPECT_EQ(&websocket_stream_create_helper, | |
| 12727 fake_request->websocket_stream_create_helper()); | |
| 12728 } | |
| 12729 } | |
| 12730 | |
| 12731 // Tests that when a used socket is returned to the SSL socket pool, it's closed | |
| 12732 // if the transport socket pool is stalled on the global socket limit. | |
| 12733 TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest) { | |
| 12734 ClientSocketPoolManager::set_max_sockets_per_group( | |
| 12735 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
| 12736 ClientSocketPoolManager::set_max_sockets_per_pool( | |
| 12737 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
| 12738 | |
| 12739 // Set up SSL request. | |
| 12740 | |
| 12741 HttpRequestInfo ssl_request; | |
| 12742 ssl_request.method = "GET"; | |
| 12743 ssl_request.url = GURL("https://www.google.com/"); | |
| 12744 | |
| 12745 MockWrite ssl_writes[] = { | |
| 12746 MockWrite("GET / HTTP/1.1\r\n" | |
| 12747 "Host: www.google.com\r\n" | |
| 12748 "Connection: keep-alive\r\n\r\n"), | |
| 12749 }; | |
| 12750 MockRead ssl_reads[] = { | |
| 12751 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 12752 MockRead("Content-Length: 11\r\n\r\n"), | |
| 12753 MockRead("hello world"), | |
| 12754 MockRead(SYNCHRONOUS, OK), | |
| 12755 }; | |
| 12756 StaticSocketDataProvider ssl_data(ssl_reads, arraysize(ssl_reads), | |
| 12757 ssl_writes, arraysize(ssl_writes)); | |
| 12758 session_deps_.socket_factory->AddSocketDataProvider(&ssl_data); | |
| 12759 | |
| 12760 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 12761 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 12762 | |
| 12763 // Set up HTTP request. | |
| 12764 | |
| 12765 HttpRequestInfo http_request; | |
| 12766 http_request.method = "GET"; | |
| 12767 http_request.url = GURL("http://www.google.com/"); | |
| 12768 | |
| 12769 MockWrite http_writes[] = { | |
| 12770 MockWrite("GET / HTTP/1.1\r\n" | |
| 12771 "Host: www.google.com\r\n" | |
| 12772 "Connection: keep-alive\r\n\r\n"), | |
| 12773 }; | |
| 12774 MockRead http_reads[] = { | |
| 12775 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 12776 MockRead("Content-Length: 7\r\n\r\n"), | |
| 12777 MockRead("falafel"), | |
| 12778 MockRead(SYNCHRONOUS, OK), | |
| 12779 }; | |
| 12780 StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), | |
| 12781 http_writes, arraysize(http_writes)); | |
| 12782 session_deps_.socket_factory->AddSocketDataProvider(&http_data); | |
| 12783 | |
| 12784 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12785 | |
| 12786 // Start the SSL request. | |
| 12787 TestCompletionCallback ssl_callback; | |
| 12788 scoped_ptr<HttpTransaction> ssl_trans( | |
| 12789 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12790 ASSERT_EQ(ERR_IO_PENDING, | |
| 12791 ssl_trans->Start(&ssl_request, ssl_callback.callback(), | |
| 12792 BoundNetLog())); | |
| 12793 | |
| 12794 // Start the HTTP request. Pool should stall. | |
| 12795 TestCompletionCallback http_callback; | |
| 12796 scoped_ptr<HttpTransaction> http_trans( | |
| 12797 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12798 ASSERT_EQ(ERR_IO_PENDING, | |
| 12799 http_trans->Start(&http_request, http_callback.callback(), | |
| 12800 BoundNetLog())); | |
| 12801 EXPECT_TRUE(IsTransportSocketPoolStalled(session.get())); | |
| 12802 | |
| 12803 // Wait for response from SSL request. | |
| 12804 ASSERT_EQ(OK, ssl_callback.WaitForResult()); | |
| 12805 std::string response_data; | |
| 12806 ASSERT_EQ(OK, ReadTransaction(ssl_trans.get(), &response_data)); | |
| 12807 EXPECT_EQ("hello world", response_data); | |
| 12808 | |
| 12809 // The SSL socket should automatically be closed, so the HTTP request can | |
| 12810 // start. | |
| 12811 EXPECT_EQ(0, GetIdleSocketCountInSSLSocketPool(session.get())); | |
| 12812 ASSERT_FALSE(IsTransportSocketPoolStalled(session.get())); | |
| 12813 | |
| 12814 // The HTTP request can now complete. | |
| 12815 ASSERT_EQ(OK, http_callback.WaitForResult()); | |
| 12816 ASSERT_EQ(OK, ReadTransaction(http_trans.get(), &response_data)); | |
| 12817 EXPECT_EQ("falafel", response_data); | |
| 12818 | |
| 12819 EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 12820 } | |
| 12821 | |
| 12822 // Tests that when a SSL connection is established but there's no corresponding | |
| 12823 // request that needs it, the new socket is closed if the transport socket pool | |
| 12824 // is stalled on the global socket limit. | |
| 12825 TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest2) { | |
| 12826 ClientSocketPoolManager::set_max_sockets_per_group( | |
| 12827 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
| 12828 ClientSocketPoolManager::set_max_sockets_per_pool( | |
| 12829 HttpNetworkSession::NORMAL_SOCKET_POOL, 1); | |
| 12830 | |
| 12831 // Set up an ssl request. | |
| 12832 | |
| 12833 HttpRequestInfo ssl_request; | |
| 12834 ssl_request.method = "GET"; | |
| 12835 ssl_request.url = GURL("https://www.foopy.com/"); | |
| 12836 | |
| 12837 // No data will be sent on the SSL socket. | |
| 12838 StaticSocketDataProvider ssl_data; | |
| 12839 session_deps_.socket_factory->AddSocketDataProvider(&ssl_data); | |
| 12840 | |
| 12841 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 12842 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 12843 | |
| 12844 // Set up HTTP request. | |
| 12845 | |
| 12846 HttpRequestInfo http_request; | |
| 12847 http_request.method = "GET"; | |
| 12848 http_request.url = GURL("http://www.google.com/"); | |
| 12849 | |
| 12850 MockWrite http_writes[] = { | |
| 12851 MockWrite("GET / HTTP/1.1\r\n" | |
| 12852 "Host: www.google.com\r\n" | |
| 12853 "Connection: keep-alive\r\n\r\n"), | |
| 12854 }; | |
| 12855 MockRead http_reads[] = { | |
| 12856 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 12857 MockRead("Content-Length: 7\r\n\r\n"), | |
| 12858 MockRead("falafel"), | |
| 12859 MockRead(SYNCHRONOUS, OK), | |
| 12860 }; | |
| 12861 StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), | |
| 12862 http_writes, arraysize(http_writes)); | |
| 12863 session_deps_.socket_factory->AddSocketDataProvider(&http_data); | |
| 12864 | |
| 12865 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12866 | |
| 12867 // Preconnect an SSL socket. A preconnect is needed because connect jobs are | |
| 12868 // cancelled when a normal transaction is cancelled. | |
| 12869 net::HttpStreamFactory* http_stream_factory = session->http_stream_factory(); | |
| 12870 net::SSLConfig ssl_config; | |
| 12871 session->ssl_config_service()->GetSSLConfig(&ssl_config); | |
| 12872 http_stream_factory->PreconnectStreams(1, ssl_request, DEFAULT_PRIORITY, | |
| 12873 ssl_config, ssl_config); | |
| 12874 EXPECT_EQ(0, GetIdleSocketCountInSSLSocketPool(session.get())); | |
| 12875 | |
| 12876 // Start the HTTP request. Pool should stall. | |
| 12877 TestCompletionCallback http_callback; | |
| 12878 scoped_ptr<HttpTransaction> http_trans( | |
| 12879 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12880 ASSERT_EQ(ERR_IO_PENDING, | |
| 12881 http_trans->Start(&http_request, http_callback.callback(), | |
| 12882 BoundNetLog())); | |
| 12883 EXPECT_TRUE(IsTransportSocketPoolStalled(session.get())); | |
| 12884 | |
| 12885 // The SSL connection will automatically be closed once the connection is | |
| 12886 // established, to let the HTTP request start. | |
| 12887 ASSERT_EQ(OK, http_callback.WaitForResult()); | |
| 12888 std::string response_data; | |
| 12889 ASSERT_EQ(OK, ReadTransaction(http_trans.get(), &response_data)); | |
| 12890 EXPECT_EQ("falafel", response_data); | |
| 12891 | |
| 12892 EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get())); | |
| 12893 } | |
| 12894 | |
| 12895 TEST_P(HttpNetworkTransactionTest, PostReadsErrorResponseAfterReset) { | |
| 12896 ScopedVector<UploadElementReader> element_readers; | |
| 12897 element_readers.push_back(new UploadBytesElementReader("foo", 3)); | |
| 12898 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 12899 | |
| 12900 HttpRequestInfo request; | |
| 12901 request.method = "POST"; | |
| 12902 request.url = GURL("http://www.foo.com/"); | |
| 12903 request.upload_data_stream = &upload_data_stream; | |
| 12904 request.load_flags = 0; | |
| 12905 | |
| 12906 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12907 scoped_ptr<HttpTransaction> trans( | |
| 12908 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12909 // Send headers successfully, but get an error while sending the body. | |
| 12910 MockWrite data_writes[] = { | |
| 12911 MockWrite("POST / HTTP/1.1\r\n" | |
| 12912 "Host: www.foo.com\r\n" | |
| 12913 "Connection: keep-alive\r\n" | |
| 12914 "Content-Length: 3\r\n\r\n"), | |
| 12915 MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), | |
| 12916 }; | |
| 12917 | |
| 12918 MockRead data_reads[] = { | |
| 12919 MockRead("HTTP/1.0 400 Not OK\r\n\r\n"), | |
| 12920 MockRead("hello world"), | |
| 12921 MockRead(SYNCHRONOUS, OK), | |
| 12922 }; | |
| 12923 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 12924 arraysize(data_writes)); | |
| 12925 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 12926 | |
| 12927 TestCompletionCallback callback; | |
| 12928 | |
| 12929 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 12930 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 12931 | |
| 12932 rv = callback.WaitForResult(); | |
| 12933 EXPECT_EQ(OK, rv); | |
| 12934 | |
| 12935 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 12936 ASSERT_TRUE(response != NULL); | |
| 12937 | |
| 12938 EXPECT_TRUE(response->headers.get() != NULL); | |
| 12939 EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine()); | |
| 12940 | |
| 12941 std::string response_data; | |
| 12942 rv = ReadTransaction(trans.get(), &response_data); | |
| 12943 EXPECT_EQ(OK, rv); | |
| 12944 EXPECT_EQ("hello world", response_data); | |
| 12945 } | |
| 12946 | |
| 12947 // This test makes sure the retry logic doesn't trigger when reading an error | |
| 12948 // response from a server that rejected a POST with a CONNECTION_RESET. | |
| 12949 TEST_P(HttpNetworkTransactionTest, | |
| 12950 PostReadsErrorResponseAfterResetOnReusedSocket) { | |
| 12951 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 12952 MockWrite data_writes[] = { | |
| 12953 MockWrite("GET / HTTP/1.1\r\n" | |
| 12954 "Host: www.foo.com\r\n" | |
| 12955 "Connection: keep-alive\r\n\r\n"), | |
| 12956 MockWrite("POST / HTTP/1.1\r\n" | |
| 12957 "Host: www.foo.com\r\n" | |
| 12958 "Connection: keep-alive\r\n" | |
| 12959 "Content-Length: 3\r\n\r\n"), | |
| 12960 MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), | |
| 12961 }; | |
| 12962 | |
| 12963 MockRead data_reads[] = { | |
| 12964 MockRead("HTTP/1.1 200 Peachy\r\n" | |
| 12965 "Content-Length: 14\r\n\r\n"), | |
| 12966 MockRead("first response"), | |
| 12967 MockRead("HTTP/1.1 400 Not OK\r\n" | |
| 12968 "Content-Length: 15\r\n\r\n"), | |
| 12969 MockRead("second response"), | |
| 12970 MockRead(SYNCHRONOUS, OK), | |
| 12971 }; | |
| 12972 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 12973 arraysize(data_writes)); | |
| 12974 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 12975 | |
| 12976 TestCompletionCallback callback; | |
| 12977 HttpRequestInfo request1; | |
| 12978 request1.method = "GET"; | |
| 12979 request1.url = GURL("http://www.foo.com/"); | |
| 12980 request1.load_flags = 0; | |
| 12981 | |
| 12982 scoped_ptr<HttpTransaction> trans1( | |
| 12983 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 12984 int rv = trans1->Start(&request1, callback.callback(), BoundNetLog()); | |
| 12985 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 12986 | |
| 12987 rv = callback.WaitForResult(); | |
| 12988 EXPECT_EQ(OK, rv); | |
| 12989 | |
| 12990 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
| 12991 ASSERT_TRUE(response1 != NULL); | |
| 12992 | |
| 12993 EXPECT_TRUE(response1->headers.get() != NULL); | |
| 12994 EXPECT_EQ("HTTP/1.1 200 Peachy", response1->headers->GetStatusLine()); | |
| 12995 | |
| 12996 std::string response_data1; | |
| 12997 rv = ReadTransaction(trans1.get(), &response_data1); | |
| 12998 EXPECT_EQ(OK, rv); | |
| 12999 EXPECT_EQ("first response", response_data1); | |
| 13000 // Delete the transaction to release the socket back into the socket pool. | |
| 13001 trans1.reset(); | |
| 13002 | |
| 13003 ScopedVector<UploadElementReader> element_readers; | |
| 13004 element_readers.push_back(new UploadBytesElementReader("foo", 3)); | |
| 13005 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 13006 | |
| 13007 HttpRequestInfo request2; | |
| 13008 request2.method = "POST"; | |
| 13009 request2.url = GURL("http://www.foo.com/"); | |
| 13010 request2.upload_data_stream = &upload_data_stream; | |
| 13011 request2.load_flags = 0; | |
| 13012 | |
| 13013 scoped_ptr<HttpTransaction> trans2( | |
| 13014 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 13015 rv = trans2->Start(&request2, callback.callback(), BoundNetLog()); | |
| 13016 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 13017 | |
| 13018 rv = callback.WaitForResult(); | |
| 13019 EXPECT_EQ(OK, rv); | |
| 13020 | |
| 13021 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
| 13022 ASSERT_TRUE(response2 != NULL); | |
| 13023 | |
| 13024 EXPECT_TRUE(response2->headers.get() != NULL); | |
| 13025 EXPECT_EQ("HTTP/1.1 400 Not OK", response2->headers->GetStatusLine()); | |
| 13026 | |
| 13027 std::string response_data2; | |
| 13028 rv = ReadTransaction(trans2.get(), &response_data2); | |
| 13029 EXPECT_EQ(OK, rv); | |
| 13030 EXPECT_EQ("second response", response_data2); | |
| 13031 } | |
| 13032 | |
| 13033 TEST_P(HttpNetworkTransactionTest, | |
| 13034 PostReadsErrorResponseAfterResetPartialBodySent) { | |
| 13035 ScopedVector<UploadElementReader> element_readers; | |
| 13036 element_readers.push_back(new UploadBytesElementReader("foo", 3)); | |
| 13037 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 13038 | |
| 13039 HttpRequestInfo request; | |
| 13040 request.method = "POST"; | |
| 13041 request.url = GURL("http://www.foo.com/"); | |
| 13042 request.upload_data_stream = &upload_data_stream; | |
| 13043 request.load_flags = 0; | |
| 13044 | |
| 13045 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 13046 scoped_ptr<HttpTransaction> trans( | |
| 13047 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 13048 // Send headers successfully, but get an error while sending the body. | |
| 13049 MockWrite data_writes[] = { | |
| 13050 MockWrite("POST / HTTP/1.1\r\n" | |
| 13051 "Host: www.foo.com\r\n" | |
| 13052 "Connection: keep-alive\r\n" | |
| 13053 "Content-Length: 3\r\n\r\n" | |
| 13054 "fo"), | |
| 13055 MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), | |
| 13056 }; | |
| 13057 | |
| 13058 MockRead data_reads[] = { | |
| 13059 MockRead("HTTP/1.0 400 Not OK\r\n\r\n"), | |
| 13060 MockRead("hello world"), | |
| 13061 MockRead(SYNCHRONOUS, OK), | |
| 13062 }; | |
| 13063 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 13064 arraysize(data_writes)); | |
| 13065 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 13066 | |
| 13067 TestCompletionCallback callback; | |
| 13068 | |
| 13069 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 13070 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 13071 | |
| 13072 rv = callback.WaitForResult(); | |
| 13073 EXPECT_EQ(OK, rv); | |
| 13074 | |
| 13075 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 13076 ASSERT_TRUE(response != NULL); | |
| 13077 | |
| 13078 EXPECT_TRUE(response->headers.get() != NULL); | |
| 13079 EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine()); | |
| 13080 | |
| 13081 std::string response_data; | |
| 13082 rv = ReadTransaction(trans.get(), &response_data); | |
| 13083 EXPECT_EQ(OK, rv); | |
| 13084 EXPECT_EQ("hello world", response_data); | |
| 13085 } | |
| 13086 | |
| 13087 // This tests the more common case than the previous test, where headers and | |
| 13088 // body are not merged into a single request. | |
| 13089 TEST_P(HttpNetworkTransactionTest, ChunkedPostReadsErrorResponseAfterReset) { | |
| 13090 ScopedVector<UploadElementReader> element_readers; | |
| 13091 element_readers.push_back(new UploadBytesElementReader("foo", 3)); | |
| 13092 ChunkedUploadDataStream upload_data_stream(0); | |
| 13093 | |
| 13094 HttpRequestInfo request; | |
| 13095 request.method = "POST"; | |
| 13096 request.url = GURL("http://www.foo.com/"); | |
| 13097 request.upload_data_stream = &upload_data_stream; | |
| 13098 request.load_flags = 0; | |
| 13099 | |
| 13100 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 13101 scoped_ptr<HttpTransaction> trans( | |
| 13102 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 13103 // Send headers successfully, but get an error while sending the body. | |
| 13104 MockWrite data_writes[] = { | |
| 13105 MockWrite("POST / HTTP/1.1\r\n" | |
| 13106 "Host: www.foo.com\r\n" | |
| 13107 "Connection: keep-alive\r\n" | |
| 13108 "Transfer-Encoding: chunked\r\n\r\n"), | |
| 13109 MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), | |
| 13110 }; | |
| 13111 | |
| 13112 MockRead data_reads[] = { | |
| 13113 MockRead("HTTP/1.0 400 Not OK\r\n\r\n"), | |
| 13114 MockRead("hello world"), | |
| 13115 MockRead(SYNCHRONOUS, OK), | |
| 13116 }; | |
| 13117 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 13118 arraysize(data_writes)); | |
| 13119 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 13120 | |
| 13121 TestCompletionCallback callback; | |
| 13122 | |
| 13123 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 13124 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 13125 // Make sure the headers are sent before adding a chunk. This ensures that | |
| 13126 // they can't be merged with the body in a single send. Not currently | |
| 13127 // necessary since a chunked body is never merged with headers, but this makes | |
| 13128 // the test more future proof. | |
| 13129 base::RunLoop().RunUntilIdle(); | |
| 13130 | |
| 13131 upload_data_stream.AppendData("last chunk", 10, true); | |
| 13132 | |
| 13133 rv = callback.WaitForResult(); | |
| 13134 EXPECT_EQ(OK, rv); | |
| 13135 | |
| 13136 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 13137 ASSERT_TRUE(response != NULL); | |
| 13138 | |
| 13139 EXPECT_TRUE(response->headers.get() != NULL); | |
| 13140 EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine()); | |
| 13141 | |
| 13142 std::string response_data; | |
| 13143 rv = ReadTransaction(trans.get(), &response_data); | |
| 13144 EXPECT_EQ(OK, rv); | |
| 13145 EXPECT_EQ("hello world", response_data); | |
| 13146 } | |
| 13147 | |
| 13148 TEST_P(HttpNetworkTransactionTest, PostReadsErrorResponseAfterResetAnd100) { | |
| 13149 ScopedVector<UploadElementReader> element_readers; | |
| 13150 element_readers.push_back(new UploadBytesElementReader("foo", 3)); | |
| 13151 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 13152 | |
| 13153 HttpRequestInfo request; | |
| 13154 request.method = "POST"; | |
| 13155 request.url = GURL("http://www.foo.com/"); | |
| 13156 request.upload_data_stream = &upload_data_stream; | |
| 13157 request.load_flags = 0; | |
| 13158 | |
| 13159 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 13160 scoped_ptr<HttpTransaction> trans( | |
| 13161 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 13162 | |
| 13163 MockWrite data_writes[] = { | |
| 13164 MockWrite("POST / HTTP/1.1\r\n" | |
| 13165 "Host: www.foo.com\r\n" | |
| 13166 "Connection: keep-alive\r\n" | |
| 13167 "Content-Length: 3\r\n\r\n"), | |
| 13168 MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), | |
| 13169 }; | |
| 13170 | |
| 13171 MockRead data_reads[] = { | |
| 13172 MockRead("HTTP/1.0 100 Continue\r\n\r\n"), | |
| 13173 MockRead("HTTP/1.0 400 Not OK\r\n\r\n"), | |
| 13174 MockRead("hello world"), | |
| 13175 MockRead(SYNCHRONOUS, OK), | |
| 13176 }; | |
| 13177 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 13178 arraysize(data_writes)); | |
| 13179 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 13180 | |
| 13181 TestCompletionCallback callback; | |
| 13182 | |
| 13183 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 13184 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 13185 | |
| 13186 rv = callback.WaitForResult(); | |
| 13187 EXPECT_EQ(OK, rv); | |
| 13188 | |
| 13189 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 13190 ASSERT_TRUE(response != NULL); | |
| 13191 | |
| 13192 EXPECT_TRUE(response->headers.get() != NULL); | |
| 13193 EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine()); | |
| 13194 | |
| 13195 std::string response_data; | |
| 13196 rv = ReadTransaction(trans.get(), &response_data); | |
| 13197 EXPECT_EQ(OK, rv); | |
| 13198 EXPECT_EQ("hello world", response_data); | |
| 13199 } | |
| 13200 | |
| 13201 TEST_P(HttpNetworkTransactionTest, PostIgnoresNonErrorResponseAfterReset) { | |
| 13202 ScopedVector<UploadElementReader> element_readers; | |
| 13203 element_readers.push_back(new UploadBytesElementReader("foo", 3)); | |
| 13204 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 13205 | |
| 13206 HttpRequestInfo request; | |
| 13207 request.method = "POST"; | |
| 13208 request.url = GURL("http://www.foo.com/"); | |
| 13209 request.upload_data_stream = &upload_data_stream; | |
| 13210 request.load_flags = 0; | |
| 13211 | |
| 13212 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 13213 scoped_ptr<HttpTransaction> trans( | |
| 13214 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 13215 // Send headers successfully, but get an error while sending the body. | |
| 13216 MockWrite data_writes[] = { | |
| 13217 MockWrite("POST / HTTP/1.1\r\n" | |
| 13218 "Host: www.foo.com\r\n" | |
| 13219 "Connection: keep-alive\r\n" | |
| 13220 "Content-Length: 3\r\n\r\n"), | |
| 13221 MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), | |
| 13222 }; | |
| 13223 | |
| 13224 MockRead data_reads[] = { | |
| 13225 MockRead("HTTP/1.0 200 Just Dandy\r\n\r\n"), | |
| 13226 MockRead("hello world"), | |
| 13227 MockRead(SYNCHRONOUS, OK), | |
| 13228 }; | |
| 13229 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 13230 arraysize(data_writes)); | |
| 13231 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 13232 | |
| 13233 TestCompletionCallback callback; | |
| 13234 | |
| 13235 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 13236 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 13237 | |
| 13238 rv = callback.WaitForResult(); | |
| 13239 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 13240 | |
| 13241 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 13242 EXPECT_TRUE(response == NULL); | |
| 13243 } | |
| 13244 | |
| 13245 TEST_P(HttpNetworkTransactionTest, | |
| 13246 PostIgnoresNonErrorResponseAfterResetAnd100) { | |
| 13247 ScopedVector<UploadElementReader> element_readers; | |
| 13248 element_readers.push_back(new UploadBytesElementReader("foo", 3)); | |
| 13249 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 13250 | |
| 13251 HttpRequestInfo request; | |
| 13252 request.method = "POST"; | |
| 13253 request.url = GURL("http://www.foo.com/"); | |
| 13254 request.upload_data_stream = &upload_data_stream; | |
| 13255 request.load_flags = 0; | |
| 13256 | |
| 13257 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 13258 scoped_ptr<HttpTransaction> trans( | |
| 13259 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 13260 // Send headers successfully, but get an error while sending the body. | |
| 13261 MockWrite data_writes[] = { | |
| 13262 MockWrite("POST / HTTP/1.1\r\n" | |
| 13263 "Host: www.foo.com\r\n" | |
| 13264 "Connection: keep-alive\r\n" | |
| 13265 "Content-Length: 3\r\n\r\n"), | |
| 13266 MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), | |
| 13267 }; | |
| 13268 | |
| 13269 MockRead data_reads[] = { | |
| 13270 MockRead("HTTP/1.0 100 Continue\r\n\r\n"), | |
| 13271 MockRead("HTTP/1.0 302 Redirect\r\n"), | |
| 13272 MockRead("Location: http://somewhere-else.com/\r\n"), | |
| 13273 MockRead("Content-Length: 0\r\n\r\n"), | |
| 13274 MockRead(SYNCHRONOUS, OK), | |
| 13275 }; | |
| 13276 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 13277 arraysize(data_writes)); | |
| 13278 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 13279 | |
| 13280 TestCompletionCallback callback; | |
| 13281 | |
| 13282 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 13283 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 13284 | |
| 13285 rv = callback.WaitForResult(); | |
| 13286 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 13287 | |
| 13288 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 13289 EXPECT_TRUE(response == NULL); | |
| 13290 } | |
| 13291 | |
| 13292 TEST_P(HttpNetworkTransactionTest, PostIgnoresHttp09ResponseAfterReset) { | |
| 13293 ScopedVector<UploadElementReader> element_readers; | |
| 13294 element_readers.push_back(new UploadBytesElementReader("foo", 3)); | |
| 13295 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 13296 | |
| 13297 HttpRequestInfo request; | |
| 13298 request.method = "POST"; | |
| 13299 request.url = GURL("http://www.foo.com/"); | |
| 13300 request.upload_data_stream = &upload_data_stream; | |
| 13301 request.load_flags = 0; | |
| 13302 | |
| 13303 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 13304 scoped_ptr<HttpTransaction> trans( | |
| 13305 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 13306 // Send headers successfully, but get an error while sending the body. | |
| 13307 MockWrite data_writes[] = { | |
| 13308 MockWrite("POST / HTTP/1.1\r\n" | |
| 13309 "Host: www.foo.com\r\n" | |
| 13310 "Connection: keep-alive\r\n" | |
| 13311 "Content-Length: 3\r\n\r\n"), | |
| 13312 MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), | |
| 13313 }; | |
| 13314 | |
| 13315 MockRead data_reads[] = { | |
| 13316 MockRead("HTTP 0.9 rocks!"), | |
| 13317 MockRead(SYNCHRONOUS, OK), | |
| 13318 }; | |
| 13319 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 13320 arraysize(data_writes)); | |
| 13321 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 13322 | |
| 13323 TestCompletionCallback callback; | |
| 13324 | |
| 13325 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 13326 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 13327 | |
| 13328 rv = callback.WaitForResult(); | |
| 13329 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 13330 | |
| 13331 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 13332 EXPECT_TRUE(response == NULL); | |
| 13333 } | |
| 13334 | |
| 13335 TEST_P(HttpNetworkTransactionTest, PostIgnoresPartial400HeadersAfterReset) { | |
| 13336 ScopedVector<UploadElementReader> element_readers; | |
| 13337 element_readers.push_back(new UploadBytesElementReader("foo", 3)); | |
| 13338 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
| 13339 | |
| 13340 HttpRequestInfo request; | |
| 13341 request.method = "POST"; | |
| 13342 request.url = GURL("http://www.foo.com/"); | |
| 13343 request.upload_data_stream = &upload_data_stream; | |
| 13344 request.load_flags = 0; | |
| 13345 | |
| 13346 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 13347 scoped_ptr<HttpTransaction> trans( | |
| 13348 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 13349 // Send headers successfully, but get an error while sending the body. | |
| 13350 MockWrite data_writes[] = { | |
| 13351 MockWrite("POST / HTTP/1.1\r\n" | |
| 13352 "Host: www.foo.com\r\n" | |
| 13353 "Connection: keep-alive\r\n" | |
| 13354 "Content-Length: 3\r\n\r\n"), | |
| 13355 MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET), | |
| 13356 }; | |
| 13357 | |
| 13358 MockRead data_reads[] = { | |
| 13359 MockRead("HTTP/1.0 400 Not a Full Response\r\n"), | |
| 13360 MockRead(SYNCHRONOUS, OK), | |
| 13361 }; | |
| 13362 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 13363 arraysize(data_writes)); | |
| 13364 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 13365 | |
| 13366 TestCompletionCallback callback; | |
| 13367 | |
| 13368 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 13369 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 13370 | |
| 13371 rv = callback.WaitForResult(); | |
| 13372 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 13373 | |
| 13374 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 13375 EXPECT_TRUE(response == NULL); | |
| 13376 } | |
| 13377 | |
| 13378 // Verify that proxy headers are not sent to the destination server when | |
| 13379 // establishing a tunnel for a secure WebSocket connection. | |
| 13380 TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWssTunnel) { | |
| 13381 HttpRequestInfo request; | |
| 13382 request.method = "GET"; | |
| 13383 request.url = GURL("wss://www.google.com/"); | |
| 13384 AddWebSocketHeaders(&request.extra_headers); | |
| 13385 | |
| 13386 // Configure against proxy server "myproxy:70". | |
| 13387 session_deps_.proxy_service.reset( | |
| 13388 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); | |
| 13389 | |
| 13390 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 13391 | |
| 13392 // Since a proxy is configured, try to establish a tunnel. | |
| 13393 MockWrite data_writes[] = { | |
| 13394 MockWrite( | |
| 13395 "CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 13396 "Host: www.google.com\r\n" | |
| 13397 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 13398 | |
| 13399 // After calling trans->RestartWithAuth(), this is the request we should | |
| 13400 // be issuing -- the final header line contains the credentials. | |
| 13401 MockWrite( | |
| 13402 "CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 13403 "Host: www.google.com\r\n" | |
| 13404 "Proxy-Connection: keep-alive\r\n" | |
| 13405 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 13406 | |
| 13407 MockWrite( | |
| 13408 "GET / HTTP/1.1\r\n" | |
| 13409 "Host: www.google.com\r\n" | |
| 13410 "Connection: Upgrade\r\n" | |
| 13411 "Upgrade: websocket\r\n" | |
| 13412 "Origin: http://www.google.com\r\n" | |
| 13413 "Sec-WebSocket-Version: 13\r\n" | |
| 13414 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n"), | |
| 13415 }; | |
| 13416 | |
| 13417 // The proxy responds to the connect with a 407, using a persistent | |
| 13418 // connection. | |
| 13419 MockRead data_reads[] = { | |
| 13420 // No credentials. | |
| 13421 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 13422 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 13423 MockRead("Proxy-Connection: close\r\n\r\n"), | |
| 13424 | |
| 13425 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 13426 | |
| 13427 MockRead("HTTP/1.1 101 Switching Protocols\r\n"), | |
| 13428 MockRead("Upgrade: websocket\r\n"), | |
| 13429 MockRead("Connection: Upgrade\r\n"), | |
| 13430 MockRead("Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"), | |
| 13431 }; | |
| 13432 | |
| 13433 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 13434 arraysize(data_writes)); | |
| 13435 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 13436 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 13437 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); | |
| 13438 | |
| 13439 scoped_ptr<HttpTransaction> trans( | |
| 13440 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 13441 FakeWebSocketStreamCreateHelper websocket_stream_create_helper; | |
| 13442 trans->SetWebSocketHandshakeStreamCreateHelper( | |
| 13443 &websocket_stream_create_helper); | |
| 13444 | |
| 13445 { | |
| 13446 TestCompletionCallback callback; | |
| 13447 | |
| 13448 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 13449 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 13450 | |
| 13451 rv = callback.WaitForResult(); | |
| 13452 EXPECT_EQ(OK, rv); | |
| 13453 } | |
| 13454 | |
| 13455 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 13456 ASSERT_TRUE(response); | |
| 13457 ASSERT_TRUE(response->headers.get()); | |
| 13458 EXPECT_EQ(407, response->headers->response_code()); | |
| 13459 | |
| 13460 { | |
| 13461 TestCompletionCallback callback; | |
| 13462 | |
| 13463 int rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), | |
| 13464 callback.callback()); | |
| 13465 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 13466 | |
| 13467 rv = callback.WaitForResult(); | |
| 13468 EXPECT_EQ(OK, rv); | |
| 13469 } | |
| 13470 | |
| 13471 response = trans->GetResponseInfo(); | |
| 13472 ASSERT_TRUE(response); | |
| 13473 ASSERT_TRUE(response->headers.get()); | |
| 13474 | |
| 13475 EXPECT_EQ(101, response->headers->response_code()); | |
| 13476 | |
| 13477 trans.reset(); | |
| 13478 session->CloseAllConnections(); | |
| 13479 } | |
| 13480 | |
| 13481 // Verify that proxy headers are not sent to the destination server when | |
| 13482 // establishing a tunnel for an insecure WebSocket connection. | |
| 13483 // This requires the authentication info to be injected into the auth cache | |
| 13484 // due to crbug.com/395064 | |
| 13485 // TODO(ricea): Change to use a 407 response once issue 395064 is fixed. | |
| 13486 TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWsTunnel) { | |
| 13487 HttpRequestInfo request; | |
| 13488 request.method = "GET"; | |
| 13489 request.url = GURL("ws://www.google.com/"); | |
| 13490 AddWebSocketHeaders(&request.extra_headers); | |
| 13491 | |
| 13492 // Configure against proxy server "myproxy:70". | |
| 13493 session_deps_.proxy_service.reset( | |
| 13494 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); | |
| 13495 | |
| 13496 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_)); | |
| 13497 | |
| 13498 MockWrite data_writes[] = { | |
| 13499 // Try to establish a tunnel for the WebSocket connection, with | |
| 13500 // credentials. Because WebSockets have a separate set of socket pools, | |
| 13501 // they cannot and will not use the same TCP/IP connection as the | |
| 13502 // preflight HTTP request. | |
| 13503 MockWrite( | |
| 13504 "CONNECT www.google.com:80 HTTP/1.1\r\n" | |
| 13505 "Host: www.google.com\r\n" | |
| 13506 "Proxy-Connection: keep-alive\r\n" | |
| 13507 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 13508 | |
| 13509 MockWrite( | |
| 13510 "GET / HTTP/1.1\r\n" | |
| 13511 "Host: www.google.com\r\n" | |
| 13512 "Connection: Upgrade\r\n" | |
| 13513 "Upgrade: websocket\r\n" | |
| 13514 "Origin: http://www.google.com\r\n" | |
| 13515 "Sec-WebSocket-Version: 13\r\n" | |
| 13516 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n"), | |
| 13517 }; | |
| 13518 | |
| 13519 MockRead data_reads[] = { | |
| 13520 // HTTP CONNECT with credentials. | |
| 13521 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 13522 | |
| 13523 // WebSocket connection established inside tunnel. | |
| 13524 MockRead("HTTP/1.1 101 Switching Protocols\r\n"), | |
| 13525 MockRead("Upgrade: websocket\r\n"), | |
| 13526 MockRead("Connection: Upgrade\r\n"), | |
| 13527 MockRead("Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"), | |
| 13528 }; | |
| 13529 | |
| 13530 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 13531 arraysize(data_writes)); | |
| 13532 session_deps_.socket_factory->AddSocketDataProvider(&data); | |
| 13533 | |
| 13534 session->http_auth_cache()->Add( | |
| 13535 GURL("http://myproxy:70/"), "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, | |
| 13536 "Basic realm=MyRealm1", AuthCredentials(kFoo, kBar), "/"); | |
| 13537 | |
| 13538 scoped_ptr<HttpTransaction> trans( | |
| 13539 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
| 13540 FakeWebSocketStreamCreateHelper websocket_stream_create_helper; | |
| 13541 trans->SetWebSocketHandshakeStreamCreateHelper( | |
| 13542 &websocket_stream_create_helper); | |
| 13543 | |
| 13544 TestCompletionCallback callback; | |
| 13545 | |
| 13546 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 13547 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 13548 | |
| 13549 rv = callback.WaitForResult(); | |
| 13550 EXPECT_EQ(OK, rv); | |
| 13551 | |
| 13552 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 13553 ASSERT_TRUE(response); | |
| 13554 ASSERT_TRUE(response->headers.get()); | |
| 13555 | |
| 13556 EXPECT_EQ(101, response->headers->response_code()); | |
| 13557 | |
| 13558 trans.reset(); | |
| 13559 session->CloseAllConnections(); | |
| 13560 } | |
| 13561 | |
| 13562 } // namespace net | |
| OLD | NEW |