| OLD | NEW |
| (Empty) |
| 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 | |
| 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 // 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 // AlternateProtocol for this job if this is an alternate job. | |
| 279 AlternateProtocolInfo alternate_protocol_; | |
| 280 | |
| 281 // AlternateProtocol for the other job if this is not an alternate job. | |
| 282 AlternateProtocolInfo other_job_alternate_protocol_; | |
| 283 | |
| 284 // This is the Job we're dependent on. It will notify us if/when it's OK to | |
| 285 // proceed. | |
| 286 Job* blocking_job_; | |
| 287 | |
| 288 // |waiting_job_| is a Job waiting to see if |this| can reuse a connection. | |
| 289 // If |this| is unable to do so, we'll notify |waiting_job_| that it's ok to | |
| 290 // proceed and then race the two Jobs. | |
| 291 Job* waiting_job_; | |
| 292 | |
| 293 // True if handling a HTTPS request, or using SPDY with SSL | |
| 294 bool using_ssl_; | |
| 295 | |
| 296 // True if this network transaction is using SPDY instead of HTTP. | |
| 297 bool using_spdy_; | |
| 298 | |
| 299 // True if this network transaction is using QUIC instead of HTTP. | |
| 300 bool using_quic_; | |
| 301 QuicStreamRequest quic_request_; | |
| 302 | |
| 303 // True if this job used an existing QUIC session. | |
| 304 bool using_existing_quic_session_; | |
| 305 | |
| 306 // Force quic for a specific port. | |
| 307 int force_quic_port_; | |
| 308 | |
| 309 // The certificate error while using SPDY over SSL for insecure URLs. | |
| 310 int spdy_certificate_error_; | |
| 311 | |
| 312 scoped_refptr<HttpAuthController> | |
| 313 auth_controllers_[HttpAuth::AUTH_NUM_TARGETS]; | |
| 314 | |
| 315 // True when the tunnel is in the process of being established - we can't | |
| 316 // read from the socket until the tunnel is done. | |
| 317 bool establishing_tunnel_; | |
| 318 | |
| 319 scoped_ptr<HttpStream> stream_; | |
| 320 scoped_ptr<WebSocketHandshakeStreamBase> websocket_stream_; | |
| 321 | |
| 322 // True if we negotiated NPN. | |
| 323 bool was_npn_negotiated_; | |
| 324 | |
| 325 // Protocol negotiated with the server. | |
| 326 NextProto protocol_negotiated_; | |
| 327 | |
| 328 // 0 if we're not preconnecting. Otherwise, the number of streams to | |
| 329 // preconnect. | |
| 330 int num_streams_; | |
| 331 | |
| 332 // Initialized when we create a new SpdySession. | |
| 333 base::WeakPtr<SpdySession> new_spdy_session_; | |
| 334 | |
| 335 // Initialized when we have an existing SpdySession. | |
| 336 base::WeakPtr<SpdySession> existing_spdy_session_; | |
| 337 | |
| 338 // Only used if |new_spdy_session_| is non-NULL. | |
| 339 bool spdy_session_direct_; | |
| 340 | |
| 341 JobStatus job_status_; | |
| 342 JobStatus other_job_status_; | |
| 343 | |
| 344 base::WeakPtrFactory<Job> ptr_factory_; | |
| 345 | |
| 346 DISALLOW_COPY_AND_ASSIGN(Job); | |
| 347 }; | |
| 348 | |
| 349 } // namespace net | |
| 350 | |
| 351 #endif // NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_ | |
| OLD | NEW |