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