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

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: Change pool API 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
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"
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698