1 // Copyright (c) 2011 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/task.h" 11 #include "net/base/completion_callback.h" 12 #include "net/base/net_log.h" 13 #include "net/base/ssl_config_service.h" 14 #include "net/http/http_alternate_protocols.h" 15 #include "net/http/http_auth.h" 16 #include "net/http/http_auth_controller.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/socket/client_socket_handle.h" 21 22 namespace net { 23 24 class ClientSocketHandle; 25 class HttpAuthController; 26 class HttpNetworkSession; 27 class HttpProxySocketParams; 28 class HttpStream; 29 class SOCKSSocketParams; 30 class SSLSocketParams; 31 class TransportSocketParams; 32 33 // An HttpStreamRequestImpl exists for each stream which is in progress of being 34 // created for the StreamFactory. 35 class HttpStreamFactoryImpl::Job { 36 public: 37 Job(HttpStreamFactoryImpl* stream_factory, 38 HttpNetworkSession* session, 39 const HttpRequestInfo& request_info, 40 const SSLConfig& ssl_config, 41 const BoundNetLog& net_log); 42 ~Job(); 43 44 // Start initiates the process of creating a new HttpStream. |request| will be 45 // notified upon completion if the Job has not been Orphan()'d. 46 void Start(Request* request); 47 48 // Preconnect will attempt to request |num_streams| sockets from the 49 // appropriate ClientSocketPool. 50 int Preconnect(int num_streams); 51 52 int RestartTunnelWithProxyAuth(const string16& username, 53 const string16& password); 54 LoadState GetLoadState() const; 55 56 // Marks this Job as the "alternate" job, from Alternate-Protocol. Tracks the 57 // original url so we can mark the Alternate-Protocol as broken if 58 // we fail to connect. 59 void MarkAsAlternate(const GURL& original_url); 60 61 // Tells |this| to wait for |job| to resume it. 62 void WaitFor(Job* job); 63 64 // Tells |this| that |job| has determined it still needs to continue 65 // connecting, so allow |this| to continue. If this is not called, then 66 // |request_| is expected to cancel |this| by deleting it. 67 void Resume(Job* job); 68 69 // Used to detach the Job from |request|. 70 void Orphan(const Request* request); 71 72 bool was_npn_negotiated() const; 73 bool using_spdy() const; 74 const BoundNetLog& net_log() const { return net_log_; } 75 76 const SSLConfig& ssl_config() const; 77 const ProxyInfo& proxy_info() const; 78 79 // Indicates whether or not this job is performing a preconnect. 80 bool IsPreconnecting() const; 81 82 // Indicates whether or not this Job has been orphaned by a Request. 83 bool IsOrphaned() const; 84 85 private: 86 enum State { 87 STATE_RESOLVE_PROXY, 88 STATE_RESOLVE_PROXY_COMPLETE, 89 90 // Note that when Alternate-Protocol says we can connect to an alternate 91 // port using a different protocol, we have the choice of communicating over 92 // the original protocol, or speaking the alternate protocol (currently, 93 // only npn-spdy) over an alternate port. For a cold page load, the http 94 // connection that delivers the http response that has the 95 // Alternate-Protocol header will already be warm. So, blocking the next 96 // http request on establishing a new npn-spdy connection would incur extra 97 // latency. Even if the http connection was not reused, establishing a new 98 // http connection is typically faster than npn-spdy, since npn-spdy 99 // requires a SSL handshake. Therefore, we start both the http and the 100 // npn-spdy jobs in parallel. In order not to unnecessarily waste sockets, 101 // we have the http job block on the npn-spdy job after proxy resolution. 102 // The npn-spdy job will Resume() the http job if, in 103 // STATE_INIT_CONNECTION_COMPLETE, it detects an error or does not find an 104 // existing SpdySession. In that case, the http and npn-spdy jobs will race. 105 STATE_WAIT_FOR_JOB, 106 STATE_WAIT_FOR_JOB_COMPLETE, 107 108 STATE_INIT_CONNECTION, 109 STATE_INIT_CONNECTION_COMPLETE, 110 STATE_WAITING_USER_ACTION, 111 STATE_RESTART_TUNNEL_AUTH, 112 STATE_RESTART_TUNNEL_AUTH_COMPLETE, 113 STATE_CREATE_STREAM, 114 STATE_CREATE_STREAM_COMPLETE, 115 STATE_DRAIN_BODY_FOR_AUTH_RESTART, 116 STATE_DRAIN_BODY_FOR_AUTH_RESTART_COMPLETE, 117 STATE_DONE, 118 STATE_NONE 119 }; 120 121 void OnStreamReadyCallback(); 122 void OnSpdySessionReadyCallback(); 123 void OnStreamFailedCallback(int result); 124 void OnCertificateErrorCallback(int result, const SSLInfo& ssl_info); 125 void OnNeedsProxyAuthCallback(const HttpResponseInfo& response_info, 126 HttpAuthController* auth_controller); 127 void OnNeedsClientAuthCallback(SSLCertRequestInfo* cert_info); 128 void OnHttpsProxyTunnelResponseCallback(const HttpResponseInfo& response_info, 129 HttpStream* stream); 130 void OnPreconnectsComplete(); 131 132 void OnIOComplete(int result); 133 int RunLoop(int result); 134 int DoLoop(int result); 135 int StartInternal(); 136 137 // Each of these methods corresponds to a State value. Those with an input 138 // argument receive the result from the previous state. If a method returns 139 // ERR_IO_PENDING, then the result from OnIOComplete will be passed to the 140 // next state method as the result arg. 141 int DoResolveProxy(); 142 int DoResolveProxyComplete(int result); 143 int DoWaitForJob(); 144 int DoWaitForJobComplete(int result); 145 int DoInitConnection(); 146 int DoInitConnectionComplete(int result); 147 int DoWaitingUserAction(int result); 148 int DoCreateStream(); 149 int DoCreateStreamComplete(int result); 150 int DoRestartTunnelAuth(); 151 int DoRestartTunnelAuthComplete(int result); 152 153 // Returns to STATE_INIT_CONNECTION and resets some state. 154 void ReturnToStateInitConnection(bool close_connection); 155 156 // Set the motivation for this request onto the underlying socket. 157 void SetSocketMotivation(); 158 159 bool IsHttpsProxyAndHttpUrl(); 160 161 // Sets several fields of ssl_config for the given origin_server based on the 162 // proxy info and other factors. 163 void InitSSLConfig(const HostPortPair& origin_server, 164 SSLConfig* ssl_config) const; 165 166 // AlternateProtocol API 167 void MarkBrokenAlternateProtocolAndFallback(); 168 169 // Retrieve SSLInfo from our SSL Socket. 170 // This must only be called when we are using an SSLSocket. 171 // After calling, the caller can use ssl_info_. 172 void GetSSLInfo(); 173 174 // Called when we encounter a network error that could be resolved by trying 175 // a new proxy configuration. If there is another proxy configuration to try 176 // then this method sets next_state_ appropriately and returns either OK or 177 // ERR_IO_PENDING depending on whether or not the new proxy configuration is 178 // available synchronously or asynchronously. Otherwise, the given error 179 // code is simply returned. 180 int ReconsiderProxyAfterError(int error); 181 182 // Called to handle a certificate error. Stores the certificate in the 183 // allowed_bad_certs list, and checks if the error can be ignored. Returns 184 // OK if it can be ignored, or the error code otherwise. 185 int HandleCertificateError(int error); 186 187 // Called to handle a client certificate request. 188 int HandleCertificateRequest(int error); 189 190 // Moves this stream request into SPDY mode. 191 void SwitchToSpdyMode(); 192 193 // Should we force SPDY to run over SSL for this stream request. 194 bool ShouldForceSpdySSL() const; 195 196 // Should we force SPDY to run without SSL for this stream request. 197 bool ShouldForceSpdyWithoutSSL() const; 198 199 // Record histograms of latency until Connect() completes. 200 static void LogHttpConnectedMetrics(const ClientSocketHandle& handle); 201 202 Request* request_; 203 204 const HttpRequestInfo request_info_; 205 ProxyInfo proxy_info_; 206 SSLConfig ssl_config_; 207 const BoundNetLog net_log_; 208 209 CompletionCallbackImpl<Job> io_callback_; 210 scoped_ptr<ClientSocketHandle> connection_; 211 HttpNetworkSession* const session_; 212 HttpStreamFactoryImpl* const stream_factory_; 213 State next_state_; 214 ProxyService::PacRequest* pac_request_; 215 SSLInfo ssl_info_; 216 217 // The origin server we're trying to reach. 218 HostPortPair origin_; 219 220 // If this is a Job for an "Alternate-Protocol", then this will be non-NULL 221 // and will specify the original URL. 222 scoped_ptr<GURL> original_url_; 223 224 // This is the Job we're dependent on. It will notify us if/when it's OK to 225 // proceed. 226 Job* blocking_job_; 227 228 // |dependent_job_| is dependent on |this|. Notify it when it's ok to proceed. 229 Job* dependent_job_; 230 231 // True if handling a HTTPS request, or using SPDY with SSL 232 bool using_ssl_; 233 234 // True if this network transaction is using SPDY instead of HTTP. 235 bool using_spdy_; 236 237 // Force spdy for all connections. 238 bool force_spdy_always_; 239 240 // Force spdy only for SSL connections. 241 bool force_spdy_over_ssl_; 242 243 // The certificate error while using SPDY over SSL for insecure URLs. 244 int spdy_certificate_error_; 245 246 scoped_refptr<HttpAuthController> 247 auth_controllers_[HttpAuth::AUTH_NUM_TARGETS]; 248 249 // True when the tunnel is in the process of being established - we can't 250 // read from the socket until the tunnel is done. 251 bool establishing_tunnel_; 252 253 scoped_ptr<HttpStream> stream_; 254 255 // True if we negotiated NPN. 256 bool was_npn_negotiated_; 257 258 // 0 if we're not preconnecting. Otherwise, the number of streams to 259 // preconnect. 260 int num_streams_; 261 262 // Initialized when we create a new SpdySession. 263 scoped_refptr<SpdySession> new_spdy_session_; 264 265 // Only used if |new_spdy_session_| is non-NULL. 266 bool spdy_session_direct_; 267 268 ScopedRunnableMethodFactory<Job> method_factory_; 269 270 DISALLOW_COPY_AND_ASSIGN(Job); 271 }; 272 273 } // namespace net 274 275 #endif // NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_ 276