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 3// found in the LICENSE file. 4 5#ifndef NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_ 6#define NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_ 7 8#include "base/memory/ref_counted.h" 9#include "base/memory/scoped_ptr.h" 10#include "base/memory/weak_ptr.h" 11#include "net/base/completion_callback.h" 12#include "net/base/net_log.h" 13#include "net/base/request_priority.h" 14#include "net/http/http_auth.h" 15#include "net/http/http_auth_controller.h" 16#include "net/http/http_request_info.h" 17#include "net/http/http_stream_factory_impl.h" 18#include "net/proxy/proxy_service.h" 19#include "net/quic/quic_stream_factory.h" 20#include "net/socket/client_socket_handle.h" 21#include "net/socket/ssl_client_socket.h" 22#include "net/spdy/spdy_session_key.h" 23#include "net/ssl/ssl_config_service.h" 24 25namespace net { 26 27class ClientSocketHandle; 28class HttpAuthController; 29class HttpNetworkSession; 30class HttpStream; 31class SpdySessionPool; 32class QuicHttpStream; 33 34// An HttpStreamRequestImpl exists for each stream which is in progress of being 35// created for the StreamFactory. 36class HttpStreamFactoryImpl::Job { 37 public: 38 Job(HttpStreamFactoryImpl* stream_factory, 39 HttpNetworkSession* session, 40 const HttpRequestInfo& request_info, 41 RequestPriority priority, 42 const SSLConfig& server_ssl_config, 43 const SSLConfig& proxy_ssl_config, 44 NetLog* net_log); 45 ~Job(); 46 47 // Start initiates the process of creating a new HttpStream. |request| will be 48 // notified upon completion if the Job has not been Orphan()'d. 49 void Start(Request* request); 50 51 // Preconnect will attempt to request |num_streams| sockets from the 52 // appropriate ClientSocketPool. 53 int Preconnect(int num_streams); 54 55 int RestartTunnelWithProxyAuth(const AuthCredentials& credentials); 56 LoadState GetLoadState() const; 57 58 // Marks this Job as the "alternate" job, from Alternate-Protocol. Tracks the 59 // original url so we can mark the Alternate-Protocol as broken if 60 // we fail to connect. |alternate| specifies the alternate protocol to use 61 // and alternate port to connect to. 62 void MarkAsAlternate(const GURL& original_url, 63 PortAlternateProtocolPair alternate); 64 65 // Tells |this| to wait for |job| to resume it. 66 void WaitFor(Job* job); 67 68 // Tells |this| that |job| has determined it still needs to continue 69 // connecting, so allow |this| to continue. If this is not called, then 70 // |request_| is expected to cancel |this| by deleting it. 71 void Resume(Job* job); 72 73 // Used to detach the Job from |request|. 74 void Orphan(const Request* request); 75 76 void SetPriority(RequestPriority priority); 77 78 RequestPriority priority() const { return priority_; } 79 bool was_npn_negotiated() const; 80 NextProto protocol_negotiated() const; 81 bool using_spdy() const; 82 const BoundNetLog& net_log() const { return net_log_; } 83 84 const SSLConfig& server_ssl_config() const; 85 const SSLConfig& proxy_ssl_config() const; 86 const ProxyInfo& proxy_info() const; 87 88 // Indicates whether or not this job is performing a preconnect. 89 bool IsPreconnecting() const; 90 91 // Indicates whether or not this Job has been orphaned by a Request. 92 bool IsOrphaned() const; 93 94 // Called to indicate that this job succeeded, and some other jobs 95 // will be orphaned. 96 void ReportJobSuccededForRequest(); 97 98 // Marks that the other |job| has completed. 99 void MarkOtherJobComplete(const Job& job); 100 101 private: 102 enum State { 103 STATE_START, 104 STATE_RESOLVE_PROXY, 105 STATE_RESOLVE_PROXY_COMPLETE, 106 107 // Note that when Alternate-Protocol says we can connect to an alternate 108 // port using a different protocol, we have the choice of communicating over 109 // the original protocol, or speaking the alternate protocol (currently, 110 // only npn-spdy) over an alternate port. For a cold page load, the http 111 // connection that delivers the http response that has the 112 // Alternate-Protocol header will already be warm. So, blocking the next 113 // http request on establishing a new npn-spdy connection would incur extra 114 // latency. Even if the http connection was not reused, establishing a new 115 // http connection is typically faster than npn-spdy, since npn-spdy 116 // requires a SSL handshake. Therefore, we start both the http and the 117 // npn-spdy jobs in parallel. In order not to unnecessarily waste sockets, 118 // we have the http job block on the npn-spdy job after proxy resolution. 119 // The npn-spdy job will Resume() the http job if, in 120 // STATE_INIT_CONNECTION_COMPLETE, it detects an error or does not find an 121 // existing SpdySession. In that case, the http and npn-spdy jobs will race. 122 STATE_WAIT_FOR_JOB, 123 STATE_WAIT_FOR_JOB_COMPLETE, 124 125 STATE_INIT_CONNECTION, 126 STATE_INIT_CONNECTION_COMPLETE, 127 STATE_WAITING_USER_ACTION, 128 STATE_RESTART_TUNNEL_AUTH, 129 STATE_RESTART_TUNNEL_AUTH_COMPLETE, 130 STATE_CREATE_STREAM, 131 STATE_CREATE_STREAM_COMPLETE, 132 STATE_DRAIN_BODY_FOR_AUTH_RESTART, 133 STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE, 134 STATE_DONE, 135 STATE_NONE 136 }; 137 138 enum JobStatus { 139 STATUS_RUNNING, 140 STATUS_FAILED, 141 STATUS_BROKEN, 142 STATUS_SUCCEEDED 143 }; 144 145 void OnStreamReadyCallback(); 146 void OnWebSocketHandshakeStreamReadyCallback(); 147 // This callback function is called when a new SPDY session is created. 148 void OnNewSpdySessionReadyCallback(); 149 void OnStreamFailedCallback(int result); 150 void OnCertificateErrorCallback(int result, const SSLInfo& ssl_info); 151 void OnNeedsProxyAuthCallback(const HttpResponseInfo& response_info, 152 HttpAuthController* auth_controller); 153 void OnNeedsClientAuthCallback(SSLCertRequestInfo* cert_info); 154 void OnHttpsProxyTunnelResponseCallback(const HttpResponseInfo& response_info, 155 HttpStream* stream); 156 void OnPreconnectsComplete(); 157 158 void OnIOComplete(int result); 159 int RunLoop(int result); 160 int DoLoop(int result); 161 int StartInternal(); 162 163 // Each of these methods corresponds to a State value. Those with an input 164 // argument receive the result from the previous state. If a method returns 165 // ERR_IO_PENDING, then the result from OnIOComplete will be passed to the 166 // next state method as the result arg. 167 int DoStart(); 168 int DoResolveProxy(); 169 int DoResolveProxyComplete(int result); 170 int DoWaitForJob(); 171 int DoWaitForJobComplete(int result); 172 int DoInitConnection(); 173 int DoInitConnectionComplete(int result); 174 int DoWaitingUserAction(int result); 175 int DoCreateStream(); 176 int DoCreateStreamComplete(int result); 177 int DoRestartTunnelAuth(); 178 int DoRestartTunnelAuthComplete(int result); 179 180 // Returns to STATE_INIT_CONNECTION and resets some state. 181 void ReturnToStateInitConnection(bool close_connection); 182 183 // Set the motivation for this request onto the underlying socket. 184 void SetSocketMotivation(); 185 186 bool IsHttpsProxyAndHttpUrl() const; 187 188 // Sets several fields of ssl_config for the given origin_server based on the 189 // proxy info and other factors. 190 void InitSSLConfig(const HostPortPair& origin_server, 191 SSLConfig* ssl_config, 192 bool is_proxy) const; 193 194 // Retrieve SSLInfo from our SSL Socket. 195 // This must only be called when we are using an SSLSocket. 196 // After calling, the caller can use ssl_info_. 197 void GetSSLInfo(); 198 199 SpdySessionKey GetSpdySessionKey() const; 200 201 // Returns true if the current request can use an existing spdy session. 202 bool CanUseExistingSpdySession() const; 203 204 // Called when we encounter a network error that could be resolved by trying 205 // a new proxy configuration. If there is another proxy configuration to try 206 // then this method sets next_state_ appropriately and returns either OK or 207 // ERR_IO_PENDING depending on whether or not the new proxy configuration is 208 // available synchronously or asynchronously. Otherwise, the given error 209 // code is simply returned. 210 int ReconsiderProxyAfterError(int error); 211 212 // Called to handle a certificate error. Stores the certificate in the 213 // allowed_bad_certs list, and checks if the error can be ignored. Returns 214 // OK if it can be ignored, or the error code otherwise. 215 int HandleCertificateError(int error); 216 217 // Called to handle a client certificate request. 218 int HandleCertificateRequest(int error); 219 220 // Moves this stream request into SPDY mode. 221 void SwitchToSpdyMode(); 222 223 // Should we force SPDY to run over SSL for this stream request. 224 bool ShouldForceSpdySSL() const; 225 226 // Should we force SPDY to run without SSL for this stream request. 227 bool ShouldForceSpdyWithoutSSL() const; 228 229 // Should we force QUIC for this stream request. 230 bool ShouldForceQuic() const; 231 232 void MaybeMarkAlternateProtocolBroken(); 233 234 // Record histograms of latency until Connect() completes. 235 static void LogHttpConnectedMetrics(const ClientSocketHandle& handle); 236 237 // Invoked by the transport socket pool after host resolution is complete 238 // to allow the connection to be aborted, if a matching SPDY session can 239 // be found. Will return ERR_SPDY_SESSION_ALREADY_EXISTS if such a 240 // session is found, and OK otherwise. 241 static int OnHostResolution(SpdySessionPool* spdy_session_pool, 242 const SpdySessionKey& spdy_session_key, 243 const AddressList& addresses, 244 const BoundNetLog& net_log); 245 246 Request* request_; 247 248 const HttpRequestInfo request_info_; 249 RequestPriority priority_; 250 ProxyInfo proxy_info_; 251 SSLConfig server_ssl_config_; 252 SSLConfig proxy_ssl_config_; 253 const BoundNetLog net_log_; 254 255 CompletionCallback io_callback_; 256 scoped_ptr<ClientSocketHandle> connection_; 257 HttpNetworkSession* const session_; 258 HttpStreamFactoryImpl* const stream_factory_; 259 State next_state_; 260 ProxyService::PacRequest* pac_request_; 261 SSLInfo ssl_info_; 262 263 // The origin server we're trying to reach. 264 HostPortPair origin_; 265 266 // The origin url we're trying to reach. This url may be different from the 267 // original request when host mapping rules are set-up. 268 GURL origin_url_; 269 270 // If this is a Job for an "Alternate-Protocol", then this will be non-NULL 271 // and will specify the original URL. 272 scoped_ptr<GURL> original_url_; 273 274 // This is the Job we're dependent on. It will notify us if/when it's OK to 275 // proceed. 276 Job* blocking_job_; 277 278 // |waiting_job_| is a Job waiting to see if |this| can reuse a connection. 279 // If |this| is unable to do so, we'll notify |waiting_job_| that it's ok to 280 // proceed and then race the two Jobs. 281 Job* waiting_job_; 282 283 // True if handling a HTTPS request, or using SPDY with SSL 284 bool using_ssl_; 285 286 // True if this network transaction is using SPDY instead of HTTP. 287 bool using_spdy_; 288 289 // True if this network transaction is using QUIC instead of HTTP. 290 bool using_quic_; 291 QuicStreamRequest quic_request_; 292 293 // True if this job used an existing QUIC session. 294 bool using_existing_quic_session_; 295 296 // Force quic for a specific port. 297 int force_quic_port_; 298 299 // The certificate error while using SPDY over SSL for insecure URLs. 300 int spdy_certificate_error_; 301 302 scoped_refptr<HttpAuthController> 303 auth_controllers_[HttpAuth::AUTH_NUM_TARGETS]; 304 305 // True when the tunnel is in the process of being established - we can't 306 // read from the socket until the tunnel is done. 307 bool establishing_tunnel_; 308 309 scoped_ptr<HttpStream> stream_; 310 scoped_ptr<WebSocketHandshakeStreamBase> websocket_stream_; 311 312 // True if we negotiated NPN. 313 bool was_npn_negotiated_; 314 315 // Protocol negotiated with the server. 316 NextProto protocol_negotiated_; 317 318 // 0 if we're not preconnecting. Otherwise, the number of streams to 319 // preconnect. 320 int num_streams_; 321 322 // Initialized when we create a new SpdySession. 323 base::WeakPtr<SpdySession> new_spdy_session_; 324 325 // Initialized when we have an existing SpdySession. 326 base::WeakPtr<SpdySession> existing_spdy_session_; 327 328 // Only used if |new_spdy_session_| is non-NULL. 329 bool spdy_session_direct_; 330 331 JobStatus job_status_; 332 JobStatus other_job_status_; 333 334 base::WeakPtrFactory<Job> ptr_factory_; 335 336 DISALLOW_COPY_AND_ASSIGN(Job); 337}; 338 339} // namespace net 340 341#endif // NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_ 342