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 25 namespace net { 26 27 class ClientSocketHandle; 28 class HttpAuthController; 29 class HttpNetworkSession; 30 class HttpStream; 31 class SpdySessionPool; 32 class QuicHttpStream; 33 34 // An HttpStreamRequestImpl exists for each stream which is in progress of being 35 // created for the StreamFactory. 36 class 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 AlternateProtocolInfo 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 priority()78 RequestPriority priority() const { return priority_; } 79 bool was_npn_negotiated() const; 80 NextProto protocol_negotiated() const; 81 bool using_spdy() const; net_log()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 // Creates a SpdyHttpStream from the given values and sets to |stream_|. Does 181 // nothing if |stream_factory_| is for WebSockets. 182 int SetSpdyHttpStream(base::WeakPtr<SpdySession> session, bool direct); 183 184 // Returns to STATE_INIT_CONNECTION and resets some state. 185 void ReturnToStateInitConnection(bool close_connection); 186 187 // Set the motivation for this request onto the underlying socket. 188 void SetSocketMotivation(); 189 190 bool IsHttpsProxyAndHttpUrl() const; 191 192 // Sets several fields of ssl_config for the given origin_server based on the 193 // proxy info and other factors. 194 void InitSSLConfig(const HostPortPair& origin_server, 195 SSLConfig* ssl_config, 196 bool is_proxy) const; 197 198 // Retrieve SSLInfo from our SSL Socket. 199 // This must only be called when we are using an SSLSocket. 200 // After calling, the caller can use ssl_info_. 201 void GetSSLInfo(); 202 203 SpdySessionKey GetSpdySessionKey() const; 204 205 // Returns true if the current request can use an existing spdy session. 206 bool CanUseExistingSpdySession() const; 207 208 // Called when we encounter a network error that could be resolved by trying 209 // a new proxy configuration. If there is another proxy configuration to try 210 // then this method sets next_state_ appropriately and returns either OK or 211 // ERR_IO_PENDING depending on whether or not the new proxy configuration is 212 // available synchronously or asynchronously. Otherwise, the given error 213 // code is simply returned. 214 int ReconsiderProxyAfterError(int error); 215 216 // Called to handle a certificate error. Stores the certificate in the 217 // allowed_bad_certs list, and checks if the error can be ignored. Returns 218 // OK if it can be ignored, or the error code otherwise. 219 int HandleCertificateError(int error); 220 221 // Called to handle a client certificate request. 222 int HandleCertificateRequest(int error); 223 224 // Moves this stream request into SPDY mode. 225 void SwitchToSpdyMode(); 226 227 // Should we force SPDY to run over SSL for this stream request. 228 bool ShouldForceSpdySSL() const; 229 230 // Should we force SPDY to run without SSL for this stream request. 231 bool ShouldForceSpdyWithoutSSL() const; 232 233 // Should we force QUIC for this stream request. 234 bool ShouldForceQuic() const; 235 236 void MaybeMarkAlternateProtocolBroken(); 237 238 // Record histograms of latency until Connect() completes. 239 static void LogHttpConnectedMetrics(const ClientSocketHandle& handle); 240 241 // Invoked by the transport socket pool after host resolution is complete 242 // to allow the connection to be aborted, if a matching SPDY session can 243 // be found. Will return ERR_SPDY_SESSION_ALREADY_EXISTS if such a 244 // session is found, and OK otherwise. 245 static int OnHostResolution(SpdySessionPool* spdy_session_pool, 246 const SpdySessionKey& spdy_session_key, 247 const AddressList& addresses, 248 const BoundNetLog& net_log); 249 250 Request* request_; 251 252 const HttpRequestInfo request_info_; 253 RequestPriority priority_; 254 ProxyInfo proxy_info_; 255 SSLConfig server_ssl_config_; 256 SSLConfig proxy_ssl_config_; 257 const BoundNetLog net_log_; 258 259 CompletionCallback io_callback_; 260 scoped_ptr<ClientSocketHandle> connection_; 261 HttpNetworkSession* const session_; 262 HttpStreamFactoryImpl* const stream_factory_; 263 State next_state_; 264 ProxyService::PacRequest* pac_request_; 265 SSLInfo ssl_info_; 266 267 // The origin server we're trying to reach. 268 HostPortPair origin_; 269 270 // The origin url we're trying to reach. This url may be different from the 271 // original request when host mapping rules are set-up. 272 GURL origin_url_; 273 274 // If this is a Job for an "Alternate-Protocol", then this will be non-NULL 275 // and will specify the original URL. 276 scoped_ptr<GURL> original_url_; 277 278 // This is the Job we're dependent on. It will notify us if/when it's OK to 279 // proceed. 280 Job* blocking_job_; 281 282 // |waiting_job_| is a Job waiting to see if |this| can reuse a connection. 283 // If |this| is unable to do so, we'll notify |waiting_job_| that it's ok to 284 // proceed and then race the two Jobs. 285 Job* waiting_job_; 286 287 // True if handling a HTTPS request, or using SPDY with SSL 288 bool using_ssl_; 289 290 // True if this network transaction is using SPDY instead of HTTP. 291 bool using_spdy_; 292 293 // True if this network transaction is using QUIC instead of HTTP. 294 bool using_quic_; 295 QuicStreamRequest quic_request_; 296 297 // True if this job used an existing QUIC session. 298 bool using_existing_quic_session_; 299 300 // Force quic for a specific port. 301 int force_quic_port_; 302 303 // The certificate error while using SPDY over SSL for insecure URLs. 304 int spdy_certificate_error_; 305 306 scoped_refptr<HttpAuthController> 307 auth_controllers_[HttpAuth::AUTH_NUM_TARGETS]; 308 309 // True when the tunnel is in the process of being established - we can't 310 // read from the socket until the tunnel is done. 311 bool establishing_tunnel_; 312 313 scoped_ptr<HttpStream> stream_; 314 scoped_ptr<WebSocketHandshakeStreamBase> websocket_stream_; 315 316 // True if we negotiated NPN. 317 bool was_npn_negotiated_; 318 319 // Protocol negotiated with the server. 320 NextProto protocol_negotiated_; 321 322 // 0 if we're not preconnecting. Otherwise, the number of streams to 323 // preconnect. 324 int num_streams_; 325 326 // Initialized when we create a new SpdySession. 327 base::WeakPtr<SpdySession> new_spdy_session_; 328 329 // Initialized when we have an existing SpdySession. 330 base::WeakPtr<SpdySession> existing_spdy_session_; 331 332 // Only used if |new_spdy_session_| is non-NULL. 333 bool spdy_session_direct_; 334 335 JobStatus job_status_; 336 JobStatus other_job_status_; 337 338 base::WeakPtrFactory<Job> ptr_factory_; 339 340 DISALLOW_COPY_AND_ASSIGN(Job); 341 }; 342 343 } // namespace net 344 345 #endif // NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_ 346