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 |