| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/http/http_stream_factory_impl_job.h" | 5 #include "net/http/http_stream_factory_impl_job.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
| 11 #include "base/values.h" | 11 #include "base/values.h" |
| 12 #include "build/build_config.h" | 12 #include "build/build_config.h" |
| 13 #include "net/base/connection_type_histograms.h" | 13 #include "net/base/connection_type_histograms.h" |
| 14 #include "net/base/net_log.h" | 14 #include "net/base/net_log.h" |
| 15 #include "net/base/net_util.h" | 15 #include "net/base/net_util.h" |
| 16 #include "net/base/ssl_cert_request_info.h" | 16 #include "net/base/ssl_cert_request_info.h" |
| 17 #include "net/http/http_basic_stream.h" | 17 #include "net/http/http_basic_stream.h" |
| 18 #include "net/http/http_network_session.h" | 18 #include "net/http/http_network_session.h" |
| 19 #include "net/http/http_pipelined_connection.h" |
| 20 #include "net/http/http_pipelined_host.h" |
| 21 #include "net/http/http_pipelined_host_pool.h" |
| 22 #include "net/http/http_pipelined_stream.h" |
| 19 #include "net/http/http_proxy_client_socket.h" | 23 #include "net/http/http_proxy_client_socket.h" |
| 20 #include "net/http/http_proxy_client_socket_pool.h" | 24 #include "net/http/http_proxy_client_socket_pool.h" |
| 21 #include "net/http/http_request_info.h" | 25 #include "net/http/http_request_info.h" |
| 26 #include "net/http/http_stream_factory.h" |
| 22 #include "net/http/http_stream_factory_impl_request.h" | 27 #include "net/http/http_stream_factory_impl_request.h" |
| 23 #include "net/socket/client_socket_handle.h" | 28 #include "net/socket/client_socket_handle.h" |
| 24 #include "net/socket/client_socket_pool.h" | 29 #include "net/socket/client_socket_pool.h" |
| 25 #include "net/socket/socks_client_socket_pool.h" | 30 #include "net/socket/socks_client_socket_pool.h" |
| 26 #include "net/socket/ssl_client_socket.h" | 31 #include "net/socket/ssl_client_socket.h" |
| 27 #include "net/socket/ssl_client_socket_pool.h" | 32 #include "net/socket/ssl_client_socket_pool.h" |
| 28 #include "net/spdy/spdy_http_stream.h" | 33 #include "net/spdy/spdy_http_stream.h" |
| 29 #include "net/spdy/spdy_session.h" | 34 #include "net/spdy/spdy_session.h" |
| 30 #include "net/spdy/spdy_session_pool.h" | 35 #include "net/spdy/spdy_session_pool.h" |
| 31 | 36 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 dependent_job_(NULL), | 85 dependent_job_(NULL), |
| 81 using_ssl_(false), | 86 using_ssl_(false), |
| 82 using_spdy_(false), | 87 using_spdy_(false), |
| 83 force_spdy_always_(HttpStreamFactory::force_spdy_always()), | 88 force_spdy_always_(HttpStreamFactory::force_spdy_always()), |
| 84 force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()), | 89 force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()), |
| 85 spdy_certificate_error_(OK), | 90 spdy_certificate_error_(OK), |
| 86 establishing_tunnel_(false), | 91 establishing_tunnel_(false), |
| 87 was_npn_negotiated_(false), | 92 was_npn_negotiated_(false), |
| 88 num_streams_(0), | 93 num_streams_(0), |
| 89 spdy_session_direct_(false), | 94 spdy_session_direct_(false), |
| 95 existing_available_pipeline_(false), |
| 90 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { | 96 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
| 91 DCHECK(stream_factory); | 97 DCHECK(stream_factory); |
| 92 DCHECK(session); | 98 DCHECK(session); |
| 93 } | 99 } |
| 94 | 100 |
| 95 HttpStreamFactoryImpl::Job::~Job() { | 101 HttpStreamFactoryImpl::Job::~Job() { |
| 96 net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_JOB, NULL); | 102 net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_JOB, NULL); |
| 97 | 103 |
| 98 // When we're in a partially constructed state, waiting for the user to | 104 // When we're in a partially constructed state, waiting for the user to |
| 99 // provide certificate handling information or authentication, we can't reuse | 105 // provide certificate handling information or authentication, we can't reuse |
| (...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 // actually need to preconnect any sockets, so we're done. | 586 // actually need to preconnect any sockets, so we're done. |
| 581 if (IsPreconnecting()) | 587 if (IsPreconnecting()) |
| 582 return OK; | 588 return OK; |
| 583 using_spdy_ = true; | 589 using_spdy_ = true; |
| 584 next_state_ = STATE_CREATE_STREAM; | 590 next_state_ = STATE_CREATE_STREAM; |
| 585 existing_spdy_session_ = spdy_session; | 591 existing_spdy_session_ = spdy_session; |
| 586 return OK; | 592 return OK; |
| 587 } else if (request_ && (using_ssl_ || ShouldForceSpdyWithoutSSL())) { | 593 } else if (request_ && (using_ssl_ || ShouldForceSpdyWithoutSSL())) { |
| 588 // Update the spdy session key for the request that launched this job. | 594 // Update the spdy session key for the request that launched this job. |
| 589 request_->SetSpdySessionKey(spdy_session_key); | 595 request_->SetSpdySessionKey(spdy_session_key); |
| 596 } else if (IsRequestEligibleForPipelining()) { |
| 597 // TODO(simonjam): With pipelining, we might be better off using fewer |
| 598 // connections and thus should make fewer preconnections. Explore |
| 599 // preconnecting fewer than the requested num_connections. |
| 600 existing_available_pipeline_ = session_->http_pipelined_host_pool()-> |
| 601 IsExistingPipelineAvailableForOrigin(origin_); |
| 602 request_->SetHttpPipeliningKey(origin_); |
| 590 } | 603 } |
| 591 | 604 |
| 592 // OK, there's no available SPDY session. Let |dependent_job_| resume if it's | 605 // OK, there's no available SPDY session. Let |dependent_job_| resume if it's |
| 593 // paused. | 606 // paused. |
| 594 | 607 |
| 595 if (dependent_job_) { | 608 if (dependent_job_) { |
| 596 dependent_job_->Resume(this); | 609 dependent_job_->Resume(this); |
| 597 dependent_job_ = NULL; | 610 dependent_job_ = NULL; |
| 598 } | 611 } |
| 599 | 612 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 738 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) { | 751 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) { |
| 739 ReturnToStateInitConnection(true /* close connection */); | 752 ReturnToStateInitConnection(true /* close connection */); |
| 740 return result; | 753 return result; |
| 741 } | 754 } |
| 742 } | 755 } |
| 743 } | 756 } |
| 744 if (result < 0) | 757 if (result < 0) |
| 745 return result; | 758 return result; |
| 746 } | 759 } |
| 747 | 760 |
| 748 if (!connection_->socket()) { | |
| 749 HACKCrashHereToDebug80095(); | |
| 750 } | |
| 751 | |
| 752 next_state_ = STATE_CREATE_STREAM; | 761 next_state_ = STATE_CREATE_STREAM; |
| 753 return OK; | 762 return OK; |
| 754 } | 763 } |
| 755 | 764 |
| 756 int HttpStreamFactoryImpl::Job::DoWaitingUserAction(int result) { | 765 int HttpStreamFactoryImpl::Job::DoWaitingUserAction(int result) { |
| 757 // This state indicates that the stream request is in a partially | 766 // This state indicates that the stream request is in a partially |
| 758 // completed state, and we've called back to the delegate for more | 767 // completed state, and we've called back to the delegate for more |
| 759 // information. | 768 // information. |
| 760 | 769 |
| 761 // We're always waiting here for the delegate to call us back. | 770 // We're always waiting here for the delegate to call us back. |
| 762 return ERR_IO_PENDING; | 771 return ERR_IO_PENDING; |
| 763 } | 772 } |
| 764 | 773 |
| 765 int HttpStreamFactoryImpl::Job::DoCreateStream() { | 774 int HttpStreamFactoryImpl::Job::DoCreateStream() { |
| 766 if (!connection_->socket() && !existing_spdy_session_) | 775 DCHECK(connection_->socket() || existing_spdy_session_ || |
| 767 HACKCrashHereToDebug80095(); | 776 existing_available_pipeline_); |
| 768 | 777 |
| 769 next_state_ = STATE_CREATE_STREAM_COMPLETE; | 778 next_state_ = STATE_CREATE_STREAM_COMPLETE; |
| 770 | 779 |
| 771 // We only set the socket motivation if we're the first to use | 780 // We only set the socket motivation if we're the first to use |
| 772 // this socket. Is there a race for two SPDY requests? We really | 781 // this socket. Is there a race for two SPDY requests? We really |
| 773 // need to plumb this through to the connect level. | 782 // need to plumb this through to the connect level. |
| 774 if (connection_->socket() && !connection_->is_reused()) | 783 if (connection_->socket() && !connection_->is_reused()) |
| 775 SetSocketMotivation(); | 784 SetSocketMotivation(); |
| 776 | 785 |
| 777 const ProxyServer& proxy_server = proxy_info_.proxy_server(); | 786 const ProxyServer& proxy_server = proxy_info_.proxy_server(); |
| 778 | 787 |
| 779 if (!using_spdy_) { | 788 if (!using_spdy_) { |
| 780 bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) && | 789 bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) && |
| 781 request_info_.url.SchemeIs("http"); | 790 request_info_.url.SchemeIs("http"); |
| 782 stream_.reset(new HttpBasicStream(connection_.release(), NULL, | 791 // TODO(simonjam): Support proxies. |
| 783 using_proxy)); | 792 if (existing_available_pipeline_) { |
| 793 stream_.reset( |
| 794 session_->http_pipelined_host_pool()->CreateStreamOnExistingPipeline( |
| 795 origin_)); |
| 796 } else if (!using_proxy && IsRequestEligibleForPipelining()) { |
| 797 stream_.reset( |
| 798 session_->http_pipelined_host_pool()->CreateStreamOnNewPipeline( |
| 799 origin_, |
| 800 connection_.release(), |
| 801 server_ssl_config_, |
| 802 proxy_info_, |
| 803 net_log_, |
| 804 was_npn_negotiated_)); |
| 805 } else { |
| 806 stream_.reset(new HttpBasicStream(connection_.release(), NULL, |
| 807 using_proxy)); |
| 808 } |
| 784 return OK; | 809 return OK; |
| 785 } | 810 } |
| 786 | 811 |
| 787 CHECK(!stream_.get()); | 812 CHECK(!stream_.get()); |
| 788 | 813 |
| 789 if (!connection_->socket() && !existing_spdy_session_) | |
| 790 HACKCrashHereToDebug80095(); | |
| 791 | |
| 792 bool direct = true; | 814 bool direct = true; |
| 793 HostPortProxyPair pair(origin_, proxy_server); | 815 HostPortProxyPair pair(origin_, proxy_server); |
| 794 if (IsHttpsProxyAndHttpUrl()) { | 816 if (IsHttpsProxyAndHttpUrl()) { |
| 795 // If we don't have a direct SPDY session, and we're using an HTTPS | 817 // If we don't have a direct SPDY session, and we're using an HTTPS |
| 796 // proxy, then we might have a SPDY session to the proxy. | 818 // proxy, then we might have a SPDY session to the proxy. |
| 797 pair = HostPortProxyPair(proxy_server.host_port_pair(), | 819 pair = HostPortProxyPair(proxy_server.host_port_pair(), |
| 798 ProxyServer::Direct()); | 820 ProxyServer::Direct()); |
| 799 direct = false; | 821 direct = false; |
| 800 } | 822 } |
| 801 | 823 |
| 802 scoped_refptr<SpdySession> spdy_session; | 824 scoped_refptr<SpdySession> spdy_session; |
| 803 if (existing_spdy_session_) { | 825 if (existing_spdy_session_) { |
| 804 // We picked up an existing session, so we don't need our socket. | 826 // We picked up an existing session, so we don't need our socket. |
| 805 if (connection_->socket()) | 827 if (connection_->socket()) |
| 806 connection_->socket()->Disconnect(); | 828 connection_->socket()->Disconnect(); |
| 807 connection_->Reset(); | 829 connection_->Reset(); |
| 808 spdy_session.swap(existing_spdy_session_); | 830 spdy_session.swap(existing_spdy_session_); |
| 809 } else { | 831 } else { |
| 810 SpdySessionPool* spdy_pool = session_->spdy_session_pool(); | 832 SpdySessionPool* spdy_pool = session_->spdy_session_pool(); |
| 811 spdy_session = spdy_pool->GetIfExists(pair, net_log_); | 833 spdy_session = spdy_pool->GetIfExists(pair, net_log_); |
| 812 if (!spdy_session) { | 834 if (!spdy_session) { |
| 813 // SPDY can be negotiated using the TLS next protocol negotiation (NPN) | |
| 814 // extension, or just directly using SSL. Either way, |connection_| must | |
| 815 // contain an SSLClientSocket. | |
| 816 if (!connection_->socket()) | |
| 817 HACKCrashHereToDebug80095(); | |
| 818 | |
| 819 int error = spdy_pool->GetSpdySessionFromSocket( | 835 int error = spdy_pool->GetSpdySessionFromSocket( |
| 820 pair, connection_.release(), net_log_, spdy_certificate_error_, | 836 pair, connection_.release(), net_log_, spdy_certificate_error_, |
| 821 &new_spdy_session_, using_ssl_); | 837 &new_spdy_session_, using_ssl_); |
| 822 if (error != OK) | 838 if (error != OK) |
| 823 return error; | 839 return error; |
| 824 spdy_session_direct_ = direct; | 840 spdy_session_direct_ = direct; |
| 825 return OK; | 841 return OK; |
| 826 } | 842 } |
| 827 } | 843 } |
| 828 | 844 |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1079 | 1095 |
| 1080 bool HttpStreamFactoryImpl::Job::IsPreconnecting() const { | 1096 bool HttpStreamFactoryImpl::Job::IsPreconnecting() const { |
| 1081 DCHECK_GE(num_streams_, 0); | 1097 DCHECK_GE(num_streams_, 0); |
| 1082 return num_streams_ > 0; | 1098 return num_streams_ > 0; |
| 1083 } | 1099 } |
| 1084 | 1100 |
| 1085 bool HttpStreamFactoryImpl::Job::IsOrphaned() const { | 1101 bool HttpStreamFactoryImpl::Job::IsOrphaned() const { |
| 1086 return !IsPreconnecting() && !request_; | 1102 return !IsPreconnecting() && !request_; |
| 1087 } | 1103 } |
| 1088 | 1104 |
| 1089 #if defined(OS_WIN) | 1105 bool HttpStreamFactoryImpl::Job::IsRequestEligibleForPipelining() const { |
| 1090 #pragma warning (disable: 4748) | 1106 if (!HttpStreamFactory::http_pipelining_enabled()) { |
| 1091 #pragma optimize( "", off ) | 1107 return false; |
| 1092 #endif | |
| 1093 | |
| 1094 void HttpStreamFactoryImpl::Job::HACKCrashHereToDebug80095() { | |
| 1095 // If we enter this code path, then we'll cause a crash later in | |
| 1096 // DoCreateStream(). Crash now and figure out what happened: | |
| 1097 // http://crbug.com/80095. | |
| 1098 GURL url = original_url_.get() ? *original_url_ : request_info_.url; | |
| 1099 bool using_ssl = using_ssl_; | |
| 1100 bool using_spdy = using_spdy_; | |
| 1101 char url_buf[512]; | |
| 1102 base::strlcpy(url_buf, url.spec().data(), arraysize(url_buf)); | |
| 1103 | |
| 1104 // Note that these local variables have their addresses referenced to | |
| 1105 // prevent the compiler from optimizing them away. | |
| 1106 if (using_spdy) { | |
| 1107 LOG(FATAL) << "Crashing here because willchan doesn't know why we're " | |
| 1108 << "crashing later. Sorry! I'll give you a cookie later. " | |
| 1109 << "Cheers mate!\n" | |
| 1110 << "url[" << &url << "]: " << url << "\n" | |
| 1111 << "using_ssl[" << &using_ssl << "]: " | |
| 1112 << (using_ssl ? "true\n" : "false\n") | |
| 1113 << "using_spdy[" << &using_spdy << "]: " | |
| 1114 << (using_spdy ? "true\n" : "false\n"); | |
| 1115 } else { | |
| 1116 LOG(FATAL) << "Crashing here because willchan doesn't know why we're " | |
| 1117 << "crashing later. Sorry! I'll give you a cookie later. " | |
| 1118 << "Cheers mate!\n" | |
| 1119 << "url[" << &url << "]: " << url << "\n" | |
| 1120 << "using_ssl[" << &using_ssl << "]: " | |
| 1121 << (using_ssl ? "true\n" : "false\n") | |
| 1122 << "using_spdy[" << &using_spdy << "]: " | |
| 1123 << (using_spdy ? "true\n" : "false\n"); | |
| 1124 } | 1108 } |
| 1109 if (IsPreconnecting() || !request_) { |
| 1110 return false; |
| 1111 } |
| 1112 if (using_ssl_) { |
| 1113 return false; |
| 1114 } |
| 1115 return request_info_.method == "GET" || request_info_.method == "HEAD"; |
| 1125 } | 1116 } |
| 1126 | 1117 |
| 1127 #if defined(OS_WIN) | |
| 1128 #pragma optimize( "", on ) | |
| 1129 #pragma warning (default: 4748) | |
| 1130 #endif | |
| 1131 | |
| 1132 } // namespace net | 1118 } // namespace net |
| OLD | NEW |