text: // Copyright 2018 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef NET_SOCKET_CONNECT_JOB_H_
  #define NET_SOCKET_CONNECT_JOB_H_
  
  #include <memory>
  #include <string>
  #include <vector>
  
  #include "base/callback_forward.h"
  #include "base/memory/raw_ptr.h"
  #include "base/memory/ref_counted.h"
  #include "base/time/time.h"
  #include "base/timer/timer.h"
  #include "net/base/address_list.h"
  #include "net/base/load_states.h"
  #include "net/base/load_timing_info.h"
  #include "net/base/net_export.h"
  #include "net/base/request_priority.h"
  #include "net/dns/public/resolve_error_info.h"
  #include "net/log/net_log_with_source.h"
  #include "net/socket/connection_attempts.h"
  #include "net/socket/socket_tag.h"
  #include "net/socket/ssl_client_socket.h"
  #include "net/third_party/quiche/src/quic/core/quic_versions.h"
  #include "third_party/abseil-cpp/absl/types/optional.h"
  
  namespace net {
  
  class ClientSocketFactory;
  class HostPortPair;
  class HostResolver;
  class HttpAuthCache;
  class HttpAuthController;
  class HttpAuthHandlerFactory;
  class HttpResponseInfo;
  class HttpUserAgentSettings;
  class NetLog;
  class NetLogWithSource;
  class NetworkQualityEstimator;
  class ProxyDelegate;
  class SocketPerformanceWatcherFactory;
  class StreamSocket;
  class WebSocketEndpointLockManager;
  class QuicStreamFactory;
  class SocketTag;
  class SpdySessionPool;
  class SSLCertRequestInfo;
  
  // Immutable socket parameters intended for shared use by all ConnectJob types.
  // Excludes priority because it can be modified over the lifetime of a
  // ConnectJob. Excludes connection timeout and NetLogWithSource because
  // ConnectJobs that wrap other ConnectJobs typically have different values for
  // those.
  struct NET_EXPORT_PRIVATE CommonConnectJobParams {
    CommonConnectJobParams(
        ClientSocketFactory* client_socket_factory,
        HostResolver* host_resolver,
        HttpAuthCache* http_auth_cache,
        HttpAuthHandlerFactory* http_auth_handler_factory,
        SpdySessionPool* spdy_session_pool,
        const quic::ParsedQuicVersionVector* quic_supported_versions,
        QuicStreamFactory* quic_stream_factory,
        ProxyDelegate* proxy_delegate,
        const HttpUserAgentSettings* http_user_agent_settings,
        SSLClientContext* ssl_client_context,
        SocketPerformanceWatcherFactory* socket_performance_watcher_factory,
        NetworkQualityEstimator* network_quality_estimator,
        NetLog* net_log,
        WebSocketEndpointLockManager* websocket_endpoint_lock_manager);
    CommonConnectJobParams(const CommonConnectJobParams& other);
    ~CommonConnectJobParams();
  
    CommonConnectJobParams& operator=(const CommonConnectJobParams& other);
  
    raw_ptr<ClientSocketFactory> client_socket_factory;
    raw_ptr<HostResolver> host_resolver;
    raw_ptr<HttpAuthCache> http_auth_cache;
    raw_ptr<HttpAuthHandlerFactory> http_auth_handler_factory;
    raw_ptr<SpdySessionPool> spdy_session_pool;
    raw_ptr<const quic::ParsedQuicVersionVector> quic_supported_versions;
    raw_ptr<QuicStreamFactory> quic_stream_factory;
    raw_ptr<ProxyDelegate> proxy_delegate;
    raw_ptr<const HttpUserAgentSettings> http_user_agent_settings;
    raw_ptr<SSLClientContext> ssl_client_context;
    raw_ptr<SocketPerformanceWatcherFactory> socket_performance_watcher_factory;
    raw_ptr<NetworkQualityEstimator> network_quality_estimator;
    raw_ptr<NetLog> net_log;
  
    // This must only be non-null for WebSockets.
    raw_ptr<WebSocketEndpointLockManager> websocket_endpoint_lock_manager;
  };
  
  // When a host resolution completes, OnHostResolutionCallback() is invoked. If
  // it returns |kContinue|, the ConnectJob can continue immediately. If it
  // returns |kMayBeDeletedAsync|, the ConnectJob may be slated for asychronous
  // destruction, so should post a task before continuing, in case it will be
  // deleted. The purpose of kMayBeDeletedAsync is to avoid needlessly creating
  // and connecting a socket when it might not be needed.
  enum class OnHostResolutionCallbackResult {
    kContinue,
    kMayBeDeletedAsync,
  };
  
  // If non-null, invoked when host resolution completes. May not destroy the
  // ConnectJob synchronously, but may signal the ConnectJob may be destroyed
  // asynchronously. See OnHostResolutionCallbackResult above.
  //
  // |address_list| is the list of addresses the host being connected to was
  // resolved to, with the port fields populated to the port being connected to.
  using OnHostResolutionCallback =
      base::RepeatingCallback<OnHostResolutionCallbackResult(
          const HostPortPair& host_port_pair,
          const AddressList& address_list)>;
  
  // ConnectJob provides an abstract interface for "connecting" a socket.
  // The connection may involve host resolution, tcp connection, ssl connection,
  // etc.
  class NET_EXPORT_PRIVATE ConnectJob {
   public:
    // Alerts the delegate that the connection completed. |job| must be destroyed
    // by the delegate. A std::unique_ptr<> isn't used because the caller of this
    // function doesn't own |job|.
    class NET_EXPORT_PRIVATE Delegate {
     public:
      Delegate() {}
  
      Delegate(const Delegate&) = delete;
      Delegate& operator=(const Delegate&) = delete;
  
      virtual ~Delegate() {}
  
      // Alerts the delegate that the connection completed. |job| must be
      // destroyed by the delegate. A std::unique_ptr<> isn't used because the
      // caller of this function doesn't own |job|.
      virtual void OnConnectJobComplete(int result, ConnectJob* job) = 0;
  
      // Invoked when an HTTP proxy returns an HTTP auth challenge during tunnel
      // establishment. Always invoked asynchronously. The caller should use
      // |auth_controller| to set challenge response information and then invoke
      // |restart_with_auth_callback| to continue establishing a connection, or
      // delete the ConnectJob if it doesn't want to respond to the challenge.
      //
      // Will only be called once at a time. Neither OnConnectJobComplete() nor
      // OnNeedsProxyAuth() will be called synchronously when
      // |restart_with_auth_callback| is invoked. Will not be called after
      // OnConnectJobComplete() has been invoked.
      virtual void OnNeedsProxyAuth(const HttpResponseInfo& response,
                                    HttpAuthController* auth_controller,
                                    base::OnceClosure restart_with_auth_callback,
                                    ConnectJob* job) = 0;
    };
  
    // A |timeout_duration| of 0 corresponds to no timeout.
    //
    // If |net_log| is non-NULL, the ConnectJob will use it for logging.
    // Otherwise, a new one will be created of type |net_log_source_type|.
    //
    // |net_log_connect_event_type| is the NetLog event type logged on Connect()
    // and connect completion.
    ConnectJob(RequestPriority priority,
               const SocketTag& socket_tag,
               base::TimeDelta timeout_duration,
               const CommonConnectJobParams* common_connect_job_params,
               Delegate* delegate,
               const NetLogWithSource* net_log,
               NetLogSourceType net_log_source_type,
               NetLogEventType net_log_connect_event_type);
  
    ConnectJob(const ConnectJob&) = delete;
    ConnectJob& operator=(const ConnectJob&) = delete;
  
    virtual ~ConnectJob();
  
    // Accessors
    const NetLogWithSource& net_log() { return net_log_; }
    RequestPriority priority() const { return priority_; }
  
    // Releases ownership of the underlying socket to the caller. Returns the
    // released socket, or nullptr if there was a connection error.
    std::unique_ptr<StreamSocket> PassSocket();
  
    // Returns the connected socket, or nullptr if PassSocket() has already been
    // called. Used to query the socket state. May only be called after the
    // ConnectJob completes.
    StreamSocket* socket() { return socket_.get(); }
  
    void ChangePriority(RequestPriority priority);
  
    // Begins connecting the socket.  Returns OK on success, ERR_IO_PENDING if it
    // cannot complete synchronously without blocking, or another net error code
    // on error.  In asynchronous completion, the ConnectJob will notify
    // |delegate_| via OnConnectJobComplete.  In both asynchronous and synchronous
    // completion, ReleaseSocket() can be called to acquire the connected socket
    // if it succeeded.
    //
    // On completion, the ConnectJob must be destroyed synchronously, since it
    // doesn't bother to stop its timer when complete.
    // TODO(mmenke): Can that be fixed?
    int Connect();
  
    // Returns the current LoadState of the ConnectJob. Each ConnectJob class must
    // start (optionally) with a LOAD_STATE_RESOLVING_HOST followed by
    // LOAD_STATE_CONNECTING, and never return to LOAD_STATE_CONNECTING. This
    // behavior is needed for backup ConnectJobs to function correctly.
    //
    // TODO(mmenke): Can something better be done here?
    virtual LoadState GetLoadState() const = 0;
  
    // Returns true if the ConnectJob has ever successfully established a TCP
    // connection. Used solely for deciding if a backup job is needed. Once it
    // starts returning true, must always return true when called in the future.
    // Not safe to call after NotifyComplete() is invoked.
    virtual bool HasEstablishedConnection() const = 0;
  
    // If the ConnectJobFailed, this method returns a list of failed attempts to
    // connect to the destination server. Returns an empty list if connecting to a
    // proxy.
    virtual ConnectionAttempts GetConnectionAttempts() const;
  
    // Returns error information about any host resolution attempt.
    virtual ResolveErrorInfo GetResolveErrorInfo() const = 0;
  
    // If the ConnectJob failed, returns true if the failure occurred after SSL
    // negotiation started. If the ConnectJob succeeded, the returned value is
    // undefined.
    virtual bool IsSSLError() const;
  
    // If the ConnectJob failed with ERR_SSL_CLIENT_AUTH_CERT_NEEDED, returns the
    // SSLCertRequestInfo received. Otherwise, returns nullptr.
    virtual scoped_refptr<SSLCertRequestInfo> GetCertRequestInfo();
  
    const LoadTimingInfo::ConnectTiming& connect_timing() const {
      return connect_timing_;
    }
  
    const NetLogWithSource& net_log() const { return net_log_; }
  
   protected:
    const SocketTag& socket_tag() const { return socket_tag_; }
    ClientSocketFactory* client_socket_factory() {
      return common_connect_job_params_->client_socket_factory;
    }
    HostResolver* host_resolver() {
      return common_connect_job_params_->host_resolver;
    }
    const HttpUserAgentSettings* http_user_agent_settings() const {
      return common_connect_job_params_->http_user_agent_settings;
    }
    SSLClientContext* ssl_client_context() {
      return common_connect_job_params_->ssl_client_context;
    }
    SocketPerformanceWatcherFactory* socket_performance_watcher_factory() {
      return common_connect_job_params_->socket_performance_watcher_factory;
    }
    NetworkQualityEstimator* network_quality_estimator() {
      return common_connect_job_params_->network_quality_estimator;
    }
    WebSocketEndpointLockManager* websocket_endpoint_lock_manager() {
      return common_connect_job_params_->websocket_endpoint_lock_manager;
    }
    const CommonConnectJobParams* common_connect_job_params() {
      return common_connect_job_params_;
    }
  
    void SetSocket(std::unique_ptr<StreamSocket> socket,
                   absl::optional<std::vector<std::string>> dns_aliases);
    void NotifyDelegateOfCompletion(int rv);
    void NotifyDelegateOfProxyAuth(const HttpResponseInfo& response,
                                   HttpAuthController* auth_controller,
                                   base::OnceClosure restart_with_auth_callback);
  
    // If |remaining_time| is base::TimeDelta(), stops the timeout timer, if it's
    // running. Otherwise, Starts / restarts the timeout timer to trigger in the
    // specified amount of time.
    void ResetTimer(base::TimeDelta remaining_time);
  
    // Returns whether or not the timeout timer is running. Only intended for use
    // by DCHECKs.
    bool TimerIsRunning() const;
  
    // Connection establishment timing information.
    // TODO(mmenke): This should be private.
    LoadTimingInfo::ConnectTiming connect_timing_;
  
   private:
    virtual int ConnectInternal() = 0;
  
    virtual void ChangePriorityInternal(RequestPriority priority) = 0;
  
    void LogConnectStart();
    void LogConnectCompletion(int net_error);
  
    // Alerts the delegate that the ConnectJob has timed out.
    void OnTimeout();
  
    // Invoked to notify subclasses that the has request timed out.
    virtual void OnTimedOutInternal();
  
    const base::TimeDelta timeout_duration_;
    RequestPriority priority_;
    const SocketTag socket_tag_;
    raw_ptr<const CommonConnectJobParams> common_connect_job_params_;
    // Timer to abort jobs that take too long.
    base::OneShotTimer timer_;
    raw_ptr<Delegate> delegate_;
    std::unique_ptr<StreamSocket> socket_;
    // Indicates if this is the topmost ConnectJob. The topmost ConnectJob logs an
    // extra begin and end event, to allow callers to log extra data before the
    // ConnectJob has started / after it has completed.
    const bool top_level_job_;
    NetLogWithSource net_log_;
    const NetLogEventType net_log_connect_event_type_;
  };
  
  }  // namespace net
  
  #endif  // NET_SOCKET_CONNECT_JOB_H_
  