| 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" |
| 22 #include "net/http/http_server_properties.h" | 26 #include "net/http/http_server_properties.h" |
| 27 #include "net/http/http_stream_factory.h" |
| 23 #include "net/http/http_stream_factory_impl_request.h" | 28 #include "net/http/http_stream_factory_impl_request.h" |
| 24 #include "net/socket/client_socket_handle.h" | 29 #include "net/socket/client_socket_handle.h" |
| 25 #include "net/socket/client_socket_pool.h" | 30 #include "net/socket/client_socket_pool.h" |
| 26 #include "net/socket/socks_client_socket_pool.h" | 31 #include "net/socket/socks_client_socket_pool.h" |
| 27 #include "net/socket/ssl_client_socket.h" | 32 #include "net/socket/ssl_client_socket.h" |
| 28 #include "net/socket/ssl_client_socket_pool.h" | 33 #include "net/socket/ssl_client_socket_pool.h" |
| 29 #include "net/spdy/spdy_http_stream.h" | 34 #include "net/spdy/spdy_http_stream.h" |
| 30 #include "net/spdy/spdy_session.h" | 35 #include "net/spdy/spdy_session.h" |
| 31 #include "net/spdy/spdy_session_pool.h" | 36 #include "net/spdy/spdy_session_pool.h" |
| 32 | 37 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 dependent_job_(NULL), | 86 dependent_job_(NULL), |
| 82 using_ssl_(false), | 87 using_ssl_(false), |
| 83 using_spdy_(false), | 88 using_spdy_(false), |
| 84 force_spdy_always_(HttpStreamFactory::force_spdy_always()), | 89 force_spdy_always_(HttpStreamFactory::force_spdy_always()), |
| 85 force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()), | 90 force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()), |
| 86 spdy_certificate_error_(OK), | 91 spdy_certificate_error_(OK), |
| 87 establishing_tunnel_(false), | 92 establishing_tunnel_(false), |
| 88 was_npn_negotiated_(false), | 93 was_npn_negotiated_(false), |
| 89 num_streams_(0), | 94 num_streams_(0), |
| 90 spdy_session_direct_(false), | 95 spdy_session_direct_(false), |
| 96 existing_available_pipeline_(false), |
| 91 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { | 97 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
| 92 DCHECK(stream_factory); | 98 DCHECK(stream_factory); |
| 93 DCHECK(session); | 99 DCHECK(session); |
| 94 } | 100 } |
| 95 | 101 |
| 96 HttpStreamFactoryImpl::Job::~Job() { | 102 HttpStreamFactoryImpl::Job::~Job() { |
| 97 net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_JOB, NULL); | 103 net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_JOB, NULL); |
| 98 | 104 |
| 99 // When we're in a partially constructed state, waiting for the user to | 105 // When we're in a partially constructed state, waiting for the user to |
| 100 // provide certificate handling information or authentication, we can't reuse | 106 // provide certificate handling information or authentication, we can't reuse |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 // actually need to preconnect any sockets, so we're done. | 597 // actually need to preconnect any sockets, so we're done. |
| 592 if (IsPreconnecting()) | 598 if (IsPreconnecting()) |
| 593 return OK; | 599 return OK; |
| 594 using_spdy_ = true; | 600 using_spdy_ = true; |
| 595 next_state_ = STATE_CREATE_STREAM; | 601 next_state_ = STATE_CREATE_STREAM; |
| 596 existing_spdy_session_ = spdy_session; | 602 existing_spdy_session_ = spdy_session; |
| 597 return OK; | 603 return OK; |
| 598 } else if (request_ && (using_ssl_ || ShouldForceSpdyWithoutSSL())) { | 604 } else if (request_ && (using_ssl_ || ShouldForceSpdyWithoutSSL())) { |
| 599 // Update the spdy session key for the request that launched this job. | 605 // Update the spdy session key for the request that launched this job. |
| 600 request_->SetSpdySessionKey(spdy_session_key); | 606 request_->SetSpdySessionKey(spdy_session_key); |
| 607 } else if (IsRequestEligibleForPipelining()) { |
| 608 // TODO(simonjam): With pipelining, we might be better off using fewer |
| 609 // connections and thus should make fewer preconnections. Explore |
| 610 // preconnecting fewer than the requested num_connections. |
| 611 existing_available_pipeline_ = stream_factory_->http_pipelined_host_pool_. |
| 612 IsExistingPipelineAvailableForOrigin(origin_); |
| 613 if (existing_available_pipeline_) { |
| 614 return OK; |
| 615 } else { |
| 616 request_->SetHttpPipeliningKey(origin_); |
| 617 } |
| 601 } | 618 } |
| 602 | 619 |
| 603 // OK, there's no available SPDY session. Let |dependent_job_| resume if it's | 620 // OK, there's no available SPDY session. Let |dependent_job_| resume if it's |
| 604 // paused. | 621 // paused. |
| 605 | 622 |
| 606 if (dependent_job_) { | 623 if (dependent_job_) { |
| 607 dependent_job_->Resume(this); | 624 dependent_job_->Resume(this); |
| 608 dependent_job_ = NULL; | 625 dependent_job_ = NULL; |
| 609 } | 626 } |
| 610 | 627 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) { | 766 if (result == OK && !connection_->socket()->IsConnectedAndIdle()) { |
| 750 ReturnToStateInitConnection(true /* close connection */); | 767 ReturnToStateInitConnection(true /* close connection */); |
| 751 return result; | 768 return result; |
| 752 } | 769 } |
| 753 } | 770 } |
| 754 } | 771 } |
| 755 if (result < 0) | 772 if (result < 0) |
| 756 return result; | 773 return result; |
| 757 } | 774 } |
| 758 | 775 |
| 759 if (!connection_->socket()) { | |
| 760 HACKCrashHereToDebug80095(); | |
| 761 } | |
| 762 | |
| 763 next_state_ = STATE_CREATE_STREAM; | 776 next_state_ = STATE_CREATE_STREAM; |
| 764 return OK; | 777 return OK; |
| 765 } | 778 } |
| 766 | 779 |
| 767 int HttpStreamFactoryImpl::Job::DoWaitingUserAction(int result) { | 780 int HttpStreamFactoryImpl::Job::DoWaitingUserAction(int result) { |
| 768 // This state indicates that the stream request is in a partially | 781 // This state indicates that the stream request is in a partially |
| 769 // completed state, and we've called back to the delegate for more | 782 // completed state, and we've called back to the delegate for more |
| 770 // information. | 783 // information. |
| 771 | 784 |
| 772 // We're always waiting here for the delegate to call us back. | 785 // We're always waiting here for the delegate to call us back. |
| 773 return ERR_IO_PENDING; | 786 return ERR_IO_PENDING; |
| 774 } | 787 } |
| 775 | 788 |
| 776 int HttpStreamFactoryImpl::Job::DoCreateStream() { | 789 int HttpStreamFactoryImpl::Job::DoCreateStream() { |
| 777 if (!connection_->socket() && !existing_spdy_session_) | 790 DCHECK(connection_->socket() || existing_spdy_session_ || |
| 778 HACKCrashHereToDebug80095(); | 791 existing_available_pipeline_); |
| 779 | 792 |
| 780 next_state_ = STATE_CREATE_STREAM_COMPLETE; | 793 next_state_ = STATE_CREATE_STREAM_COMPLETE; |
| 781 | 794 |
| 782 // We only set the socket motivation if we're the first to use | 795 // We only set the socket motivation if we're the first to use |
| 783 // this socket. Is there a race for two SPDY requests? We really | 796 // this socket. Is there a race for two SPDY requests? We really |
| 784 // need to plumb this through to the connect level. | 797 // need to plumb this through to the connect level. |
| 785 if (connection_->socket() && !connection_->is_reused()) | 798 if (connection_->socket() && !connection_->is_reused()) |
| 786 SetSocketMotivation(); | 799 SetSocketMotivation(); |
| 787 | 800 |
| 788 const ProxyServer& proxy_server = proxy_info_.proxy_server(); | 801 const ProxyServer& proxy_server = proxy_info_.proxy_server(); |
| 789 | 802 |
| 790 if (!using_spdy_) { | 803 if (!using_spdy_) { |
| 791 bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) && | 804 bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) && |
| 792 request_info_.url.SchemeIs("http"); | 805 request_info_.url.SchemeIs("http"); |
| 793 stream_.reset(new HttpBasicStream(connection_.release(), NULL, | 806 // TODO(simonjam): Support proxies. |
| 794 using_proxy)); | 807 if (existing_available_pipeline_) { |
| 808 stream_.reset(stream_factory_->http_pipelined_host_pool_. |
| 809 CreateStreamOnExistingPipeline(origin_)); |
| 810 CHECK(stream_.get()); |
| 811 } else if (!using_proxy && IsRequestEligibleForPipelining()) { |
| 812 stream_.reset( |
| 813 stream_factory_->http_pipelined_host_pool_.CreateStreamOnNewPipeline( |
| 814 origin_, |
| 815 connection_.release(), |
| 816 server_ssl_config_, |
| 817 proxy_info_, |
| 818 net_log_, |
| 819 was_npn_negotiated_)); |
| 820 CHECK(stream_.get()); |
| 821 } else { |
| 822 stream_.reset(new HttpBasicStream(connection_.release(), NULL, |
| 823 using_proxy)); |
| 824 } |
| 795 return OK; | 825 return OK; |
| 796 } | 826 } |
| 797 | 827 |
| 798 CHECK(!stream_.get()); | 828 CHECK(!stream_.get()); |
| 799 | 829 |
| 800 if (!connection_->socket() && !existing_spdy_session_) | |
| 801 HACKCrashHereToDebug80095(); | |
| 802 | |
| 803 bool direct = true; | 830 bool direct = true; |
| 804 HostPortProxyPair pair(origin_, proxy_server); | 831 HostPortProxyPair pair(origin_, proxy_server); |
| 805 if (IsHttpsProxyAndHttpUrl()) { | 832 if (IsHttpsProxyAndHttpUrl()) { |
| 806 // If we don't have a direct SPDY session, and we're using an HTTPS | 833 // If we don't have a direct SPDY session, and we're using an HTTPS |
| 807 // proxy, then we might have a SPDY session to the proxy. | 834 // proxy, then we might have a SPDY session to the proxy. |
| 808 pair = HostPortProxyPair(proxy_server.host_port_pair(), | 835 pair = HostPortProxyPair(proxy_server.host_port_pair(), |
| 809 ProxyServer::Direct()); | 836 ProxyServer::Direct()); |
| 810 direct = false; | 837 direct = false; |
| 811 } | 838 } |
| 812 | 839 |
| 813 scoped_refptr<SpdySession> spdy_session; | 840 scoped_refptr<SpdySession> spdy_session; |
| 814 if (existing_spdy_session_) { | 841 if (existing_spdy_session_) { |
| 815 // We picked up an existing session, so we don't need our socket. | 842 // We picked up an existing session, so we don't need our socket. |
| 816 if (connection_->socket()) | 843 if (connection_->socket()) |
| 817 connection_->socket()->Disconnect(); | 844 connection_->socket()->Disconnect(); |
| 818 connection_->Reset(); | 845 connection_->Reset(); |
| 819 spdy_session.swap(existing_spdy_session_); | 846 spdy_session.swap(existing_spdy_session_); |
| 820 } else { | 847 } else { |
| 821 SpdySessionPool* spdy_pool = session_->spdy_session_pool(); | 848 SpdySessionPool* spdy_pool = session_->spdy_session_pool(); |
| 822 spdy_session = spdy_pool->GetIfExists(pair, net_log_); | 849 spdy_session = spdy_pool->GetIfExists(pair, net_log_); |
| 823 if (!spdy_session) { | 850 if (!spdy_session) { |
| 824 // SPDY can be negotiated using the TLS next protocol negotiation (NPN) | |
| 825 // extension, or just directly using SSL. Either way, |connection_| must | |
| 826 // contain an SSLClientSocket. | |
| 827 if (!connection_->socket()) | |
| 828 HACKCrashHereToDebug80095(); | |
| 829 | |
| 830 int error = spdy_pool->GetSpdySessionFromSocket( | 851 int error = spdy_pool->GetSpdySessionFromSocket( |
| 831 pair, connection_.release(), net_log_, spdy_certificate_error_, | 852 pair, connection_.release(), net_log_, spdy_certificate_error_, |
| 832 &new_spdy_session_, using_ssl_); | 853 &new_spdy_session_, using_ssl_); |
| 833 if (error != OK) | 854 if (error != OK) |
| 834 return error; | 855 return error; |
| 835 const HostPortPair& host_port_pair = pair.first; | 856 const HostPortPair& host_port_pair = pair.first; |
| 836 HttpServerProperties* http_server_properties = | 857 HttpServerProperties* http_server_properties = |
| 837 session_->http_server_properties(); | 858 session_->http_server_properties(); |
| 838 if (http_server_properties) | 859 if (http_server_properties) |
| 839 http_server_properties->SetSupportsSpdy(host_port_pair, true); | 860 http_server_properties->SetSupportsSpdy(host_port_pair, true); |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1095 | 1116 |
| 1096 bool HttpStreamFactoryImpl::Job::IsPreconnecting() const { | 1117 bool HttpStreamFactoryImpl::Job::IsPreconnecting() const { |
| 1097 DCHECK_GE(num_streams_, 0); | 1118 DCHECK_GE(num_streams_, 0); |
| 1098 return num_streams_ > 0; | 1119 return num_streams_ > 0; |
| 1099 } | 1120 } |
| 1100 | 1121 |
| 1101 bool HttpStreamFactoryImpl::Job::IsOrphaned() const { | 1122 bool HttpStreamFactoryImpl::Job::IsOrphaned() const { |
| 1102 return !IsPreconnecting() && !request_; | 1123 return !IsPreconnecting() && !request_; |
| 1103 } | 1124 } |
| 1104 | 1125 |
| 1105 #if defined(OS_WIN) | 1126 bool HttpStreamFactoryImpl::Job::IsRequestEligibleForPipelining() const { |
| 1106 #pragma warning (disable: 4748) | 1127 if (!HttpStreamFactory::http_pipelining_enabled()) { |
| 1107 #pragma optimize( "", off ) | 1128 return false; |
| 1108 #endif | |
| 1109 | |
| 1110 void HttpStreamFactoryImpl::Job::HACKCrashHereToDebug80095() { | |
| 1111 // If we enter this code path, then we'll cause a crash later in | |
| 1112 // DoCreateStream(). Crash now and figure out what happened: | |
| 1113 // http://crbug.com/80095. | |
| 1114 GURL url = original_url_.get() ? *original_url_ : request_info_.url; | |
| 1115 bool using_ssl = using_ssl_; | |
| 1116 bool using_spdy = using_spdy_; | |
| 1117 char url_buf[512]; | |
| 1118 base::strlcpy(url_buf, url.spec().data(), arraysize(url_buf)); | |
| 1119 | |
| 1120 // Note that these local variables have their addresses referenced to | |
| 1121 // prevent the compiler from optimizing them away. | |
| 1122 if (using_spdy) { | |
| 1123 LOG(FATAL) << "Crashing here because willchan doesn't know why we're " | |
| 1124 << "crashing later. Sorry! I'll give you a cookie later. " | |
| 1125 << "Cheers mate!\n" | |
| 1126 << "url[" << &url << "]: " << url << "\n" | |
| 1127 << "using_ssl[" << &using_ssl << "]: " | |
| 1128 << (using_ssl ? "true\n" : "false\n") | |
| 1129 << "using_spdy[" << &using_spdy << "]: " | |
| 1130 << (using_spdy ? "true\n" : "false\n"); | |
| 1131 } else { | |
| 1132 LOG(FATAL) << "Crashing here because willchan doesn't know why we're " | |
| 1133 << "crashing later. Sorry! I'll give you a cookie later. " | |
| 1134 << "Cheers mate!\n" | |
| 1135 << "url[" << &url << "]: " << url << "\n" | |
| 1136 << "using_ssl[" << &using_ssl << "]: " | |
| 1137 << (using_ssl ? "true\n" : "false\n") | |
| 1138 << "using_spdy[" << &using_spdy << "]: " | |
| 1139 << (using_spdy ? "true\n" : "false\n"); | |
| 1140 } | 1129 } |
| 1130 if (IsPreconnecting() || !request_) { |
| 1131 return false; |
| 1132 } |
| 1133 if (using_ssl_) { |
| 1134 return false; |
| 1135 } |
| 1136 return request_info_.method == "GET" || request_info_.method == "HEAD"; |
| 1141 } | 1137 } |
| 1142 | 1138 |
| 1143 #if defined(OS_WIN) | |
| 1144 #pragma optimize( "", on ) | |
| 1145 #pragma warning (default: 4748) | |
| 1146 #endif | |
| 1147 | |
| 1148 } // namespace net | 1139 } // namespace net |
| OLD | NEW |