Home | History | Annotate | Download | only in http
      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