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