Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(105)

Side by Side Diff: net/http/http_stream_factory_impl_job.cc

Issue 7289006: Basic HTTP pipelining support (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/http/http_stream_factory_impl_job.h ('k') | net/http/http_stream_factory_impl_request.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/http/http_stream_factory_impl_job.h ('k') | net/http/http_stream_factory_impl_request.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698