OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
15 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
16 #include "base/values.h" | 16 #include "base/values.h" |
17 #include "build/build_config.h" | 17 #include "build/build_config.h" |
18 #include "net/base/connection_type_histograms.h" | 18 #include "net/base/connection_type_histograms.h" |
19 #include "net/base/net_log.h" | 19 #include "net/base/net_log.h" |
20 #include "net/base/net_util.h" | 20 #include "net/base/net_util.h" |
21 #include "net/http/http_basic_stream.h" | 21 #include "net/http/http_basic_stream.h" |
22 #include "net/http/http_network_session.h" | 22 #include "net/http/http_network_session.h" |
23 #include "net/http/http_pipelined_connection.h" | |
24 #include "net/http/http_pipelined_host.h" | |
25 #include "net/http/http_pipelined_host_pool.h" | |
26 #include "net/http/http_pipelined_stream.h" | |
27 #include "net/http/http_proxy_client_socket.h" | 23 #include "net/http/http_proxy_client_socket.h" |
28 #include "net/http/http_proxy_client_socket_pool.h" | 24 #include "net/http/http_proxy_client_socket_pool.h" |
29 #include "net/http/http_request_info.h" | 25 #include "net/http/http_request_info.h" |
30 #include "net/http/http_server_properties.h" | 26 #include "net/http/http_server_properties.h" |
31 #include "net/http/http_stream_factory.h" | 27 #include "net/http/http_stream_factory.h" |
32 #include "net/http/http_stream_factory_impl_request.h" | 28 #include "net/http/http_stream_factory_impl_request.h" |
33 #include "net/quic/quic_http_stream.h" | 29 #include "net/quic/quic_http_stream.h" |
34 #include "net/socket/client_socket_handle.h" | 30 #include "net/socket/client_socket_handle.h" |
35 #include "net/socket/client_socket_pool.h" | 31 #include "net/socket/client_socket_pool.h" |
36 #include "net/socket/client_socket_pool_manager.h" | 32 #include "net/socket/client_socket_pool_manager.h" |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 quic_request_(session_->quic_stream_factory()), | 96 quic_request_(session_->quic_stream_factory()), |
101 using_existing_quic_session_(false), | 97 using_existing_quic_session_(false), |
102 force_spdy_always_(HttpStreamFactory::force_spdy_always()), | 98 force_spdy_always_(HttpStreamFactory::force_spdy_always()), |
103 force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()), | 99 force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()), |
104 spdy_certificate_error_(OK), | 100 spdy_certificate_error_(OK), |
105 establishing_tunnel_(false), | 101 establishing_tunnel_(false), |
106 was_npn_negotiated_(false), | 102 was_npn_negotiated_(false), |
107 protocol_negotiated_(kProtoUnknown), | 103 protocol_negotiated_(kProtoUnknown), |
108 num_streams_(0), | 104 num_streams_(0), |
109 spdy_session_direct_(false), | 105 spdy_session_direct_(false), |
110 existing_available_pipeline_(false), | |
111 ptr_factory_(this) { | 106 ptr_factory_(this) { |
112 DCHECK(stream_factory); | 107 DCHECK(stream_factory); |
113 DCHECK(session); | 108 DCHECK(session); |
114 } | 109 } |
115 | 110 |
116 HttpStreamFactoryImpl::Job::~Job() { | 111 HttpStreamFactoryImpl::Job::~Job() { |
117 net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_JOB); | 112 net_log_.EndEvent(NetLog::TYPE_HTTP_STREAM_JOB); |
118 | 113 |
119 // When we're in a partially constructed state, waiting for the user to | 114 // When we're in a partially constructed state, waiting for the user to |
120 // provide certificate handling information or authentication, we can't reuse | 115 // provide certificate handling information or authentication, we can't reuse |
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
609 int rv = RunLoop(OK); | 604 int rv = RunLoop(OK); |
610 DCHECK_EQ(ERR_IO_PENDING, rv); | 605 DCHECK_EQ(ERR_IO_PENDING, rv); |
611 return rv; | 606 return rv; |
612 } | 607 } |
613 | 608 |
614 int HttpStreamFactoryImpl::Job::DoStart() { | 609 int HttpStreamFactoryImpl::Job::DoStart() { |
615 int port = request_info_.url.EffectiveIntPort(); | 610 int port = request_info_.url.EffectiveIntPort(); |
616 origin_ = HostPortPair(request_info_.url.HostNoBrackets(), port); | 611 origin_ = HostPortPair(request_info_.url.HostNoBrackets(), port); |
617 origin_url_ = stream_factory_->ApplyHostMappingRules( | 612 origin_url_ = stream_factory_->ApplyHostMappingRules( |
618 request_info_.url, &origin_); | 613 request_info_.url, &origin_); |
619 http_pipelining_key_.reset(new HttpPipelinedHost::Key(origin_)); | |
620 | 614 |
621 net_log_.BeginEvent(NetLog::TYPE_HTTP_STREAM_JOB, | 615 net_log_.BeginEvent(NetLog::TYPE_HTTP_STREAM_JOB, |
622 base::Bind(&NetLogHttpStreamJobCallback, | 616 base::Bind(&NetLogHttpStreamJobCallback, |
623 &request_info_.url, &origin_url_, | 617 &request_info_.url, &origin_url_, |
624 priority_)); | 618 priority_)); |
625 | 619 |
626 // Don't connect to restricted ports. | 620 // Don't connect to restricted ports. |
627 bool is_port_allowed = IsPortAllowedByDefault(port); | 621 bool is_port_allowed = IsPortAllowedByDefault(port); |
628 if (request_info_.url.SchemeIs("ftp")) { | 622 if (request_info_.url.SchemeIs("ftp")) { |
629 // Never share connection with other jobs for FTP requests. | 623 // Never share connection with other jobs for FTP requests. |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
777 // actually need to preconnect any sockets, so we're done. | 771 // actually need to preconnect any sockets, so we're done. |
778 if (IsPreconnecting()) | 772 if (IsPreconnecting()) |
779 return OK; | 773 return OK; |
780 using_spdy_ = true; | 774 using_spdy_ = true; |
781 next_state_ = STATE_CREATE_STREAM; | 775 next_state_ = STATE_CREATE_STREAM; |
782 existing_spdy_session_ = spdy_session; | 776 existing_spdy_session_ = spdy_session; |
783 return OK; | 777 return OK; |
784 } else if (request_ && (using_ssl_ || ShouldForceSpdyWithoutSSL())) { | 778 } else if (request_ && (using_ssl_ || ShouldForceSpdyWithoutSSL())) { |
785 // Update the spdy session key for the request that launched this job. | 779 // Update the spdy session key for the request that launched this job. |
786 request_->SetSpdySessionKey(spdy_session_key); | 780 request_->SetSpdySessionKey(spdy_session_key); |
787 } else if (IsRequestEligibleForPipelining()) { | |
788 // TODO(simonjam): With pipelining, we might be better off using fewer | |
789 // connections and thus should make fewer preconnections. Explore | |
790 // preconnecting fewer than the requested num_connections. | |
791 // | |
792 // Separate note: A forced pipeline is always available if one exists for | |
793 // this key. This is different than normal pipelines, which may be | |
794 // unavailable or unusable. So, there is no need to worry about a race | |
795 // between when a pipeline becomes available and when this job blocks. | |
796 existing_available_pipeline_ = stream_factory_->http_pipelined_host_pool_. | |
797 IsExistingPipelineAvailableForKey(*http_pipelining_key_.get()); | |
798 if (existing_available_pipeline_) { | |
799 return OK; | |
800 } else { | |
801 bool was_new_key = request_->SetHttpPipeliningKey( | |
802 *http_pipelining_key_.get()); | |
803 if (!was_new_key && session_->force_http_pipelining()) { | |
804 return ERR_IO_PENDING; | |
805 } | |
806 } | |
807 } | 781 } |
808 | 782 |
809 // OK, there's no available SPDY session. Let |waiting_job_| resume if it's | 783 // OK, there's no available SPDY session. Let |waiting_job_| resume if it's |
810 // paused. | 784 // paused. |
811 | 785 |
812 if (waiting_job_) { | 786 if (waiting_job_) { |
813 waiting_job_->Resume(this); | 787 waiting_job_->Resume(this); |
814 waiting_job_ = NULL; | 788 waiting_job_ = NULL; |
815 } | 789 } |
816 | 790 |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
901 return OK; | 875 return OK; |
902 } | 876 } |
903 | 877 |
904 // TODO(willchan): Make this a bit more exact. Maybe there are recoverable | 878 // TODO(willchan): Make this a bit more exact. Maybe there are recoverable |
905 // errors, such as ignoring certificate errors for Alternate-Protocol. | 879 // errors, such as ignoring certificate errors for Alternate-Protocol. |
906 if (result < 0 && waiting_job_) { | 880 if (result < 0 && waiting_job_) { |
907 waiting_job_->Resume(this); | 881 waiting_job_->Resume(this); |
908 waiting_job_ = NULL; | 882 waiting_job_ = NULL; |
909 } | 883 } |
910 | 884 |
911 if (result < 0 && session_->force_http_pipelining()) { | |
912 stream_factory_->AbortPipelinedRequestsWithKey( | |
913 this, *http_pipelining_key_.get(), result, server_ssl_config_); | |
914 } | |
915 | |
916 // |result| may be the result of any of the stacked pools. The following | 885 // |result| may be the result of any of the stacked pools. The following |
917 // logic is used when determining how to interpret an error. | 886 // logic is used when determining how to interpret an error. |
918 // If |result| < 0: | 887 // If |result| < 0: |
919 // and connection_->socket() != NULL, then the SSL handshake ran and it | 888 // and connection_->socket() != NULL, then the SSL handshake ran and it |
920 // is a potentially recoverable error. | 889 // is a potentially recoverable error. |
921 // and connection_->socket == NULL and connection_->is_ssl_error() is true, | 890 // and connection_->socket == NULL and connection_->is_ssl_error() is true, |
922 // then the SSL handshake ran with an unrecoverable error. | 891 // then the SSL handshake ran with an unrecoverable error. |
923 // otherwise, the error came from one of the other pools. | 892 // otherwise, the error came from one of the other pools. |
924 bool ssl_started = using_ssl_ && (result == OK || connection_->socket() || | 893 bool ssl_started = using_ssl_ && (result == OK || connection_->socket() || |
925 connection_->is_ssl_error()); | 894 connection_->is_ssl_error()); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1039 int HttpStreamFactoryImpl::Job::DoWaitingUserAction(int result) { | 1008 int HttpStreamFactoryImpl::Job::DoWaitingUserAction(int result) { |
1040 // This state indicates that the stream request is in a partially | 1009 // This state indicates that the stream request is in a partially |
1041 // completed state, and we've called back to the delegate for more | 1010 // completed state, and we've called back to the delegate for more |
1042 // information. | 1011 // information. |
1043 | 1012 |
1044 // We're always waiting here for the delegate to call us back. | 1013 // We're always waiting here for the delegate to call us back. |
1045 return ERR_IO_PENDING; | 1014 return ERR_IO_PENDING; |
1046 } | 1015 } |
1047 | 1016 |
1048 int HttpStreamFactoryImpl::Job::DoCreateStream() { | 1017 int HttpStreamFactoryImpl::Job::DoCreateStream() { |
1049 DCHECK(connection_->socket() || existing_spdy_session_.get() || | 1018 DCHECK(connection_->socket() || existing_spdy_session_.get() || using_quic_); |
1050 existing_available_pipeline_ || using_quic_); | |
1051 | 1019 |
1052 next_state_ = STATE_CREATE_STREAM_COMPLETE; | 1020 next_state_ = STATE_CREATE_STREAM_COMPLETE; |
1053 | 1021 |
1054 // We only set the socket motivation if we're the first to use | 1022 // We only set the socket motivation if we're the first to use |
1055 // this socket. Is there a race for two SPDY requests? We really | 1023 // this socket. Is there a race for two SPDY requests? We really |
1056 // need to plumb this through to the connect level. | 1024 // need to plumb this through to the connect level. |
1057 if (connection_->socket() && !connection_->is_reused()) | 1025 if (connection_->socket() && !connection_->is_reused()) |
1058 SetSocketMotivation(); | 1026 SetSocketMotivation(); |
1059 | 1027 |
1060 if (!using_spdy_) { | 1028 if (!using_spdy_) { |
1061 // We may get ftp scheme when fetching ftp resources through proxy. | 1029 // We may get ftp scheme when fetching ftp resources through proxy. |
1062 bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) && | 1030 bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) && |
1063 (request_info_.url.SchemeIs("http") || | 1031 (request_info_.url.SchemeIs("http") || |
1064 request_info_.url.SchemeIs("ftp")); | 1032 request_info_.url.SchemeIs("ftp")); |
1065 if (stream_factory_->http_pipelined_host_pool_. | 1033 if (stream_factory_->for_websockets_) { |
1066 IsExistingPipelineAvailableForKey(*http_pipelining_key_.get())) { | |
1067 DCHECK(!stream_factory_->for_websockets_); | |
1068 stream_.reset(stream_factory_->http_pipelined_host_pool_. | |
1069 CreateStreamOnExistingPipeline( | |
1070 *http_pipelining_key_.get())); | |
1071 CHECK(stream_.get()); | |
1072 } else if (stream_factory_->for_websockets_) { | |
1073 DCHECK(request_); | 1034 DCHECK(request_); |
1074 DCHECK(request_->websocket_handshake_stream_create_helper()); | 1035 DCHECK(request_->websocket_handshake_stream_create_helper()); |
1075 websocket_stream_.reset( | 1036 websocket_stream_.reset( |
1076 request_->websocket_handshake_stream_create_helper() | 1037 request_->websocket_handshake_stream_create_helper() |
1077 ->CreateBasicStream(connection_.Pass(), using_proxy)); | 1038 ->CreateBasicStream(connection_.Pass(), using_proxy)); |
1078 } else if (!using_proxy && IsRequestEligibleForPipelining()) { | |
1079 // TODO(simonjam): Support proxies. | |
1080 stream_.reset( | |
1081 stream_factory_->http_pipelined_host_pool_.CreateStreamOnNewPipeline( | |
1082 *http_pipelining_key_.get(), | |
1083 connection_.release(), | |
1084 server_ssl_config_, | |
1085 proxy_info_, | |
1086 net_log_, | |
1087 was_npn_negotiated_, | |
1088 protocol_negotiated_)); | |
1089 CHECK(stream_.get()); | |
1090 } else { | 1039 } else { |
1091 stream_.reset(new HttpBasicStream(connection_.release(), using_proxy)); | 1040 stream_.reset(new HttpBasicStream(connection_.release(), using_proxy)); |
1092 } | 1041 } |
1093 return OK; | 1042 return OK; |
1094 } | 1043 } |
1095 | 1044 |
1096 CHECK(!stream_.get()); | 1045 CHECK(!stream_.get()); |
1097 | 1046 |
1098 bool direct = true; | 1047 bool direct = true; |
1099 const ProxyServer& proxy_server = proxy_info_.proxy_server(); | 1048 const ProxyServer& proxy_server = proxy_info_.proxy_server(); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1196 | 1145 |
1197 return ReconsiderProxyAfterError(result); | 1146 return ReconsiderProxyAfterError(result); |
1198 } | 1147 } |
1199 | 1148 |
1200 void HttpStreamFactoryImpl::Job::ReturnToStateInitConnection( | 1149 void HttpStreamFactoryImpl::Job::ReturnToStateInitConnection( |
1201 bool close_connection) { | 1150 bool close_connection) { |
1202 if (close_connection && connection_->socket()) | 1151 if (close_connection && connection_->socket()) |
1203 connection_->socket()->Disconnect(); | 1152 connection_->socket()->Disconnect(); |
1204 connection_->Reset(); | 1153 connection_->Reset(); |
1205 | 1154 |
1206 if (request_) { | 1155 if (request_) |
1207 request_->RemoveRequestFromSpdySessionRequestMap(); | 1156 request_->RemoveRequestFromSpdySessionRequestMap(); |
1208 request_->RemoveRequestFromHttpPipeliningRequestMap(); | |
1209 } | |
1210 | 1157 |
1211 next_state_ = STATE_INIT_CONNECTION; | 1158 next_state_ = STATE_INIT_CONNECTION; |
1212 } | 1159 } |
1213 | 1160 |
1214 void HttpStreamFactoryImpl::Job::SetSocketMotivation() { | 1161 void HttpStreamFactoryImpl::Job::SetSocketMotivation() { |
1215 if (request_info_.motivation == HttpRequestInfo::PRECONNECT_MOTIVATED) | 1162 if (request_info_.motivation == HttpRequestInfo::PRECONNECT_MOTIVATED) |
1216 connection_->socket()->SetSubresourceSpeculation(); | 1163 connection_->socket()->SetSubresourceSpeculation(); |
1217 else if (request_info_.motivation == HttpRequestInfo::OMNIBOX_MOTIVATED) | 1164 else if (request_info_.motivation == HttpRequestInfo::OMNIBOX_MOTIVATED) |
1218 connection_->socket()->SetOmniboxSpeculation(); | 1165 connection_->socket()->SetOmniboxSpeculation(); |
1219 // TODO(mbelshe): Add other motivations (like EARLY_LOAD_MOTIVATED). | 1166 // TODO(mbelshe): Add other motivations (like EARLY_LOAD_MOTIVATED). |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1351 } | 1298 } |
1352 | 1299 |
1353 int rv = session_->proxy_service()->ReconsiderProxyAfterError( | 1300 int rv = session_->proxy_service()->ReconsiderProxyAfterError( |
1354 request_info_.url, &proxy_info_, io_callback_, &pac_request_, net_log_); | 1301 request_info_.url, &proxy_info_, io_callback_, &pac_request_, net_log_); |
1355 if (rv == OK || rv == ERR_IO_PENDING) { | 1302 if (rv == OK || rv == ERR_IO_PENDING) { |
1356 // If the error was during connection setup, there is no socket to | 1303 // If the error was during connection setup, there is no socket to |
1357 // disconnect. | 1304 // disconnect. |
1358 if (connection_->socket()) | 1305 if (connection_->socket()) |
1359 connection_->socket()->Disconnect(); | 1306 connection_->socket()->Disconnect(); |
1360 connection_->Reset(); | 1307 connection_->Reset(); |
1361 if (request_) { | 1308 if (request_) |
1362 request_->RemoveRequestFromSpdySessionRequestMap(); | 1309 request_->RemoveRequestFromSpdySessionRequestMap(); |
1363 request_->RemoveRequestFromHttpPipeliningRequestMap(); | |
1364 } | |
1365 next_state_ = STATE_RESOLVE_PROXY_COMPLETE; | 1310 next_state_ = STATE_RESOLVE_PROXY_COMPLETE; |
1366 } else { | 1311 } else { |
1367 // If ReconsiderProxyAfterError() failed synchronously, it means | 1312 // If ReconsiderProxyAfterError() failed synchronously, it means |
1368 // there was nothing left to fall-back to, so fail the transaction | 1313 // there was nothing left to fall-back to, so fail the transaction |
1369 // with the last connection error we got. | 1314 // with the last connection error we got. |
1370 // TODO(eroman): This is a confusing contract, make it more obvious. | 1315 // TODO(eroman): This is a confusing contract, make it more obvious. |
1371 rv = error; | 1316 rv = error; |
1372 } | 1317 } |
1373 | 1318 |
1374 return rv; | 1319 return rv; |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1463 } else if (original_url_) { | 1408 } else if (original_url_) { |
1464 // This job was the alternate protocol job, and hence won the race. | 1409 // This job was the alternate protocol job, and hence won the race. |
1465 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_WON_RACE); | 1410 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_WON_RACE); |
1466 } else { | 1411 } else { |
1467 // This job was the normal job, and hence the alternate protocol job lost | 1412 // This job was the normal job, and hence the alternate protocol job lost |
1468 // the race. | 1413 // the race. |
1469 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_LOST_RACE); | 1414 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_LOST_RACE); |
1470 } | 1415 } |
1471 } | 1416 } |
1472 | 1417 |
1473 bool HttpStreamFactoryImpl::Job::IsRequestEligibleForPipelining() { | |
1474 if (IsPreconnecting() || !request_) { | |
1475 return false; | |
1476 } | |
1477 if (stream_factory_->for_websockets_) { | |
1478 return false; | |
1479 } | |
1480 if (session_->force_http_pipelining()) { | |
1481 return true; | |
1482 } | |
1483 if (!session_->params().http_pipelining_enabled) { | |
1484 return false; | |
1485 } | |
1486 if (using_ssl_) { | |
1487 return false; | |
1488 } | |
1489 if (request_info_.method != "GET" && request_info_.method != "HEAD") { | |
1490 return false; | |
1491 } | |
1492 if (request_info_.load_flags & | |
1493 (net::LOAD_MAIN_FRAME | net::LOAD_SUB_FRAME | net::LOAD_PREFETCH | | |
1494 net::LOAD_IS_DOWNLOAD)) { | |
1495 // Avoid pipelining resources that may be streamed for a long time. | |
1496 return false; | |
1497 } | |
1498 return stream_factory_->http_pipelined_host_pool_.IsKeyEligibleForPipelining( | |
1499 *http_pipelining_key_.get()); | |
1500 } | |
1501 | |
1502 } // namespace net | 1418 } // namespace net |
OLD | NEW |