• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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_JOB_H_
6 #define NET_HTTP_HTTP_STREAM_FACTORY_JOB_H_
7 
8 #include <memory>
9 #include <utility>
10 
11 #include "base/memory/raw_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/time/time.h"
14 #include "net/base/completion_repeating_callback.h"
15 #include "net/base/net_export.h"
16 #include "net/base/request_priority.h"
17 #include "net/dns/public/resolve_error_info.h"
18 #include "net/dns/public/secure_dns_policy.h"
19 #include "net/http/bidirectional_stream_impl.h"
20 #include "net/http/http_auth.h"
21 #include "net/http/http_auth_controller.h"
22 #include "net/http/http_request_info.h"
23 #include "net/http/http_stream_factory.h"
24 #include "net/http/http_stream_request.h"
25 #include "net/quic/quic_stream_factory.h"
26 #include "net/socket/client_socket_handle.h"
27 #include "net/socket/client_socket_pool.h"
28 #include "net/socket/client_socket_pool_manager.h"
29 #include "net/socket/next_proto.h"
30 #include "net/socket/ssl_client_socket.h"
31 #include "net/spdy/spdy_session_key.h"
32 #include "net/spdy/spdy_session_pool.h"
33 #include "url/scheme_host_port.h"
34 
35 namespace net {
36 
37 namespace test {
38 
39 class HttpStreamFactoryJobPeer;
40 
41 }  // namespace test
42 
43 class ClientSocketHandle;
44 class HttpAuthController;
45 class HttpNetworkSession;
46 class HttpStream;
47 class SpdySessionPool;
48 class NetLog;
49 class ProxyChain;
50 struct SSLConfig;
51 
52 // An HttpStreamRequest exists for each stream which is in progress of being
53 // created for the HttpStreamFactory.
54 class HttpStreamFactory::Job
55     : public SpdySessionPool::SpdySessionRequest::Delegate {
56  public:
57   // For jobs issued simultaneously to an HTTP/2 supported server, a delay is
58   // applied to avoid unnecessary socket connection establishments.
59   // https://crbug.com/718576
60   static const int kHTTP2ThrottleMs = 300;
61 
62   // Returns true when QUIC is forcibly used for `destination`.
63   static bool OriginToForceQuicOn(const QuicParams& quic_params,
64                                   const url::SchemeHostPort& destination);
65 
66   // Delegate to report Job's status to HttpStreamRequest and HttpStreamFactory.
67   class NET_EXPORT_PRIVATE Delegate {
68    public:
69     virtual ~Delegate() = default;
70 
71     // Invoked when |job| has an HttpStream ready.
72     virtual void OnStreamReady(Job* job, const SSLConfig& used_ssl_config) = 0;
73 
74     // Invoked when |job| has a BidirectionalStream ready.
75     virtual void OnBidirectionalStreamImplReady(
76         Job* job,
77         const SSLConfig& used_ssl_config,
78         const ProxyInfo& used_proxy_info) = 0;
79 
80     // Invoked when |job| has a WebSocketHandshakeStream ready.
81     virtual void OnWebSocketHandshakeStreamReady(
82         Job* job,
83         const SSLConfig& used_ssl_config,
84         const ProxyInfo& used_proxy_info,
85         std::unique_ptr<WebSocketHandshakeStreamBase> stream) = 0;
86 
87     // Invoked when |job| fails to create a stream.
88     virtual void OnStreamFailed(Job* job,
89                                 int status,
90                                 const SSLConfig& used_ssl_config) = 0;
91 
92     // Invoked when |job| fails on the default network.
93     virtual void OnFailedOnDefaultNetwork(Job* job) = 0;
94 
95     // Invoked when |job| has a certificate error for the HttpStreamRequest.
96     virtual void OnCertificateError(Job* job,
97                                     int status,
98                                     const SSLConfig& used_ssl_config,
99                                     const SSLInfo& ssl_info) = 0;
100 
101     // Invoked when |job| raises failure for SSL Client Auth.
102     virtual void OnNeedsClientAuth(Job* job,
103                                    const SSLConfig& used_ssl_config,
104                                    SSLCertRequestInfo* cert_info) = 0;
105 
106     // Invoked when |job| needs proxy authentication.
107     virtual void OnNeedsProxyAuth(Job* job,
108                                   const HttpResponseInfo& proxy_response,
109                                   const SSLConfig& used_ssl_config,
110                                   const ProxyInfo& used_proxy_info,
111                                   HttpAuthController* auth_controller) = 0;
112 
113     // Invoked when the |job| finishes pre-connecting sockets.
114     virtual void OnPreconnectsComplete(Job* job, int result) = 0;
115 
116     // Invoked to record connection attempts made by the socket layer to
117     // HttpStreamRequest if |job| is associated with HttpStreamRequest.
118     virtual void AddConnectionAttemptsToRequest(
119         Job* job,
120         const ConnectionAttempts& attempts) = 0;
121 
122     // Invoked when |job| finishes initiating a connection.
123     virtual void OnConnectionInitialized(Job* job, int rv) = 0;
124 
125     // Return false if |job| can advance to the next state. Otherwise, |job|
126     // will wait for Job::Resume() to be called before advancing.
127     virtual bool ShouldWait(Job* job) = 0;
128 
129     virtual const NetLogWithSource* GetNetLog() const = 0;
130 
131     virtual WebSocketHandshakeStreamBase::CreateHelper*
132     websocket_handshake_stream_create_helper() = 0;
133 
134     virtual void MaybeSetWaitTimeForMainJob(const base::TimeDelta& delay) = 0;
135   };
136 
137   // Job is owned by |delegate|, hence |delegate| is valid for the lifetime of
138   // the Job.
139   //
140   // |alternative_protocol| is the protocol required by Alternative Service, if
141   // any:
142   // * |alternative_protocol == kProtoUnknown| means that the Job can pool to an
143   //   existing SpdySession, or bind to a idle TCP socket that might use either
144   //   HTTP/1.1 or HTTP/2.
145   // * |alternative_protocol == kProtoHTTP2| means that the Job can pool to an
146   //   existing SpdySession, or bind to a idle TCP socket.  In the latter case,
147   //   if the socket does not use HTTP/2, then the Job fails.
148   // * |alternative_protocol == kProtoQUIC| means that the Job can pool to an
149   //   existing QUIC connection or open a new one.
150   // Note that this can be overwritten by specifying a QUIC proxy in
151   // |proxy_info|, or by setting
152   // HttpNetworkSession::Params::origins_to_force_quic_on.
153   Job(Delegate* delegate,
154       JobType job_type,
155       HttpNetworkSession* session,
156       const HttpRequestInfo& request_info,
157       RequestPriority priority,
158       const ProxyInfo& proxy_info,
159       const SSLConfig& server_ssl_config,
160       url::SchemeHostPort destination,
161       GURL origin_url,
162       NextProto alternative_protocol,
163       quic::ParsedQuicVersion quic_version,
164       bool is_websocket,
165       bool enable_ip_based_pooling,
166       NetLog* net_log);
167 
168   Job(const Job&) = delete;
169   Job& operator=(const Job&) = delete;
170 
171   ~Job() override;
172 
173   // Start initiates the process of creating a new HttpStream.
174   // |delegate_| will be notified upon completion.
175   void Start(HttpStreamRequest::StreamType stream_type);
176 
177   // Preconnect will attempt to request |num_streams| sockets from the
178   // appropriate ClientSocketPool.
179   int Preconnect(int num_streams);
180 
181   int RestartTunnelWithProxyAuth();
182   LoadState GetLoadState() const;
183 
184   // Tells |this| that |delegate_| has determined it still needs to continue
185   // connecting.
186   virtual void Resume();
187 
188   // Called when |this| is orphaned by Delegate. This is valid for
189   // ALTERNATIVE job and DNS_ALPN_H3 job.
190   void Orphan();
191 
192   void SetPriority(RequestPriority priority);
193 
194   // Returns true if the current request can be immediately sent on a existing
195   // spdy session.
196   bool HasAvailableSpdySession() const;
197 
198   // Returns true if the current request can be immediately sent on a existing
199   // QUIC session.
200   bool HasAvailableQuicSession() const;
201 
202   // Returns true if a connected (idle or handed out) or connecting socket
203   // exists for the job. This method is not supported for WebSocket and QUIC.
204   bool TargettedSocketGroupHasActiveSocket() const;
205 
origin_url()206   const GURL& origin_url() const { return origin_url_; }
priority()207   RequestPriority priority() const { return priority_; }
208   NextProto negotiated_protocol() const;
net_log()209   const NetLogWithSource& net_log() const { return net_log_; }
stream_type()210   HttpStreamRequest::StreamType stream_type() const { return stream_type_; }
211 
ReleaseStream()212   std::unique_ptr<HttpStream> ReleaseStream() { return std::move(stream_); }
213 
ReleaseBidirectionalStream()214   std::unique_ptr<BidirectionalStreamImpl> ReleaseBidirectionalStream() {
215     return std::move(bidirectional_stream_impl_);
216   }
217 
is_waiting()218   bool is_waiting() const { return next_state_ == STATE_WAIT_COMPLETE; }
219   const ProxyInfo& proxy_info() const;
220   ResolveErrorInfo resolve_error_info() const;
221 
job_type()222   JobType job_type() const { return job_type_; }
223 
using_existing_quic_session()224   bool using_existing_quic_session() const {
225     return using_existing_quic_session_;
226   }
227 
expect_on_quic_session_created()228   bool expect_on_quic_session_created() const {
229     return expect_on_quic_session_created_;
230   }
231 
expect_on_quic_host_resolution_for_tests()232   bool expect_on_quic_host_resolution_for_tests() const {
233     return expect_on_quic_host_resolution_;
234   }
235 
using_quic()236   bool using_quic() const { return using_quic_; }
237 
should_reconsider_proxy()238   bool should_reconsider_proxy() const { return should_reconsider_proxy_; }
239 
net_error_details()240   NetErrorDetails* net_error_details() { return &net_error_details_; }
241 
242  private:
243   friend class test::HttpStreamFactoryJobPeer;
244 
245   enum State {
246     STATE_START,
247     // The main and alternative jobs are started in parallel.  The main job
248     // can wait if it's paused. The alternative job never waits.
249     //
250     // An HTTP/2 alternative job notifies the JobController in DoInitConnection
251     // unless it can pool to an existing SpdySession.  JobController, in turn,
252     // resumes the main job.
253     //
254     // A QUIC alternative job notifies the JobController in DoInitConnection
255     // regardless of whether it pools to an existing QUIC session, but the main
256     // job is only resumed after some delay.
257     //
258     // If the main job is resumed, then it races the alternative job.
259     STATE_WAIT,
260     STATE_WAIT_COMPLETE,
261 
262     STATE_INIT_CONNECTION,
263     STATE_INIT_CONNECTION_COMPLETE,
264     STATE_WAITING_USER_ACTION,
265     STATE_CREATE_STREAM,
266     STATE_CREATE_STREAM_COMPLETE,
267     STATE_DONE,
268     STATE_NONE,
269   };
270 
271   void OnStreamReadyCallback();
272   void OnBidirectionalStreamImplReadyCallback();
273   void OnWebSocketHandshakeStreamReadyCallback();
274   // This callback function is called when a new SPDY session is created.
275   void OnNewSpdySessionReadyCallback();
276   void OnStreamFailedCallback(int result);
277   void OnCertificateErrorCallback(int result, const SSLInfo& ssl_info);
278   void OnNeedsProxyAuthCallback(const HttpResponseInfo& response_info,
279                                 HttpAuthController* auth_controller,
280                                 base::OnceClosure restart_with_auth_callback);
281   void OnNeedsClientAuthCallback(SSLCertRequestInfo* cert_info);
282   void OnPreconnectsComplete(int result);
283 
284   void OnIOComplete(int result);
285   // RunLoop() finishes asynchronously and invokes one of the On* methods (see
286   // above) when done.
287   void RunLoop(int result);
288   int DoLoop(int result);
289   int StartInternal();
290   int DoInitConnectionImpl();
291   int DoInitConnectionImplQuic();
292 
293   // If this is a QUIC alt job, then this function is called when host
294   // resolution completes. It's called with the next result after host
295   // resolution, not the result of host resolution itself.
296   void OnQuicHostResolution(int result);
297 
298   // If this is a QUIC alt job, this function is called when the QUIC session is
299   // created. It's called with the result of either failed session creation or
300   // an attempted crypto connection.
301   void OnQuicSessionCreated(int result);
302 
303   // Invoked when the underlying connection fails on the default network.
304   void OnFailedOnDefaultNetwork(int result);
305 
306   // Each of these methods corresponds to a State value.  Those with an input
307   // argument receive the result from the previous state.  If a method returns
308   // ERR_IO_PENDING, then the result from OnIOComplete will be passed to the
309   // next state method as the result arg.
310   int DoStart();
311   int DoWait();
312   int DoWaitComplete(int result);
313   int DoInitConnection();
314   int DoInitConnectionComplete(int result);
315   int DoWaitingUserAction(int result);
316   int DoCreateStream();
317   int DoCreateStreamComplete(int result);
318 
319   void ResumeInitConnection();
320 
321   // Creates a SpdyHttpStream or a BidirectionalStreamImpl from the given values
322   // and sets to |stream_| or |bidirectional_stream_impl_| respectively. Does
323   // nothing if |stream_factory_| is for WebSocket.
324   int SetSpdyHttpStreamOrBidirectionalStreamImpl(
325       base::WeakPtr<SpdySession> session);
326 
327   // SpdySessionPool::SpdySessionRequest::Delegate implementation:
328   void OnSpdySessionAvailable(base::WeakPtr<SpdySession> spdy_session) override;
329 
330   // Retrieve SSLInfo from our SSL Socket.
331   // This must only be called when we are using an SSLSocket.
332   void GetSSLInfo(SSLInfo* ssl_info);
333 
334   // Called in Job constructor: should Job be forced to use QUIC.
335   static bool ShouldForceQuic(HttpNetworkSession* session,
336                               const url::SchemeHostPort& destination,
337                               const ProxyInfo& proxy_info,
338                               bool using_ssl,
339                               bool is_websocket);
340 
341   // Called in Job constructor. Use |spdy_session_key_| after construction.
342   static SpdySessionKey GetSpdySessionKey(
343       const ProxyChain& proxy_chain,
344       const GURL& origin_url,
345       PrivacyMode privacy_mode,
346       const SocketTag& socket_tag,
347       const NetworkAnonymizationKey& network_anonymization_key,
348       SecureDnsPolicy secure_dns_policy);
349 
350   // Returns true if the current request can use an existing spdy session.
351   bool CanUseExistingSpdySession() const;
352 
353   // Called when we encounter a network error that could be resolved by trying
354   // a new proxy configuration.  If there is another proxy configuration to try
355   // then this method sets next_state_ appropriately and returns either OK or
356   // ERR_IO_PENDING depending on whether or not the new proxy configuration is
357   // available synchronously or asynchronously.  Otherwise, the given error
358   // code is simply returned.
359   int ReconsiderProxyAfterError(int error);
360 
361   void MaybeCopyConnectionAttemptsFromHandle();
362 
363   // Returns true if the request should be throttled to allow for only one
364   // connection attempt to be made to an H2 server at a time.
365   bool ShouldThrottleConnectForSpdy() const;
366 
367   // True if Job actually uses HTTP/2. Note this describes both using HTTP/2
368   // with an HTTPS origin, and proxying a cleartext HTTP request over an HTTP/2
369   // proxy. This differs from `using_ssl_`, which only describes the origin.
370   bool using_spdy() const;
371 
372   const HttpRequestInfo request_info_;
373   RequestPriority priority_;
374   const ProxyInfo proxy_info_;
375   SSLConfig server_ssl_config_;
376   const NetLogWithSource net_log_;
377 
378   const CompletionRepeatingCallback io_callback_;
379   std::unique_ptr<ClientSocketHandle> connection_;
380   const raw_ptr<HttpNetworkSession> session_;
381 
382   State next_state_ = STATE_NONE;
383 
384   // The server we are trying to reach, could be that of the origin or of the
385   // alternative service (after applying host mapping rules).
386   const url::SchemeHostPort destination_;
387 
388   // The origin url we're trying to reach. This url may be different from the
389   // original request when host mapping rules are set-up.
390   const GURL origin_url_;
391 
392   // True if request is for Websocket.
393   const bool is_websocket_;
394 
395   // True if WebSocket request is allowed to use a WebSocket-capable existing
396   // HTTP/2 connection.  In this case FindAvailableSession() must be called with
397   // |enable_websocket = true|.
398   const bool try_websocket_over_http2_;
399 
400   // Enable pooling to a SpdySession with matching IP and certificate
401   // even if the SpdySessionKey is different.
402   const bool enable_ip_based_pooling_;
403 
404   // Unowned. |this| job is owned by |delegate_|.
405   const raw_ptr<Delegate> delegate_;
406 
407   const JobType job_type_;
408 
409   // True if handling a HTTPS request. Note this only describes the origin URL.
410   // If false (an HTTP request), the request may still be sent over an HTTPS
411   // proxy. This differs from `using_quic_` and `using_spdy()`, which also
412   // describe some proxy cases.
413   const bool using_ssl_;
414 
415   // True if Job actually uses QUIC. Note this describes both using QUIC
416   // with an HTTPS origin, and proxying a cleartext HTTP request over an QUIC
417   // proxy. This differs from `using_ssl_`, which only describes the origin.
418   const bool using_quic_;
419 
420   // quic::ParsedQuicVersion that should be used to connect to the QUIC
421   // server if Job uses QUIC.
422   quic::ParsedQuicVersion quic_version_;
423 
424   // True if Alternative Service protocol field requires that HTTP/2 is used.
425   // In this case, Job fails if it cannot pool to an existing SpdySession and
426   // the server does not negotiate HTTP/2 on a new socket.
427   const bool expect_spdy_;
428 
429   // True if this job might succeed with a different proxy config.
430   bool should_reconsider_proxy_ = false;
431 
432   QuicStreamRequest quic_request_;
433 
434   // Only valid for a QUIC job. Set when a QUIC connection is started. If true,
435   // then OnQuicHostResolution() is expected to be called in the future.
436   bool expect_on_quic_host_resolution_ = false;
437 
438   // Only valid for a QUIC job. Set when a QUIC connection is started. If true,
439   // OnQuicSessionCreated() is expected to be called in the future.
440   bool expect_on_quic_session_created_ = false;
441 
442   // True if this job used an existing QUIC session.
443   bool using_existing_quic_session_ = false;
444 
445   // True when the tunnel is in the process of being established - we can't
446   // read from the socket until the tunnel is done.
447   bool establishing_tunnel_ = false;
448 
449   std::unique_ptr<HttpStream> stream_;
450   std::unique_ptr<WebSocketHandshakeStreamBase> websocket_stream_;
451   std::unique_ptr<BidirectionalStreamImpl> bidirectional_stream_impl_;
452 
453   // Protocol negotiated with the server.
454   NextProto negotiated_protocol_ = kProtoUnknown;
455 
456   // 0 if we're not preconnecting. Otherwise, the number of streams to
457   // preconnect.
458   int num_streams_ = 0;
459 
460   // Initialized when we have an existing SpdySession.
461   base::WeakPtr<SpdySession> existing_spdy_session_;
462 
463   // Which SpdySessions in the pool to use. Note that, if requesting an HTTP URL
464   // through an HTTPS proxy, this key corresponds to the last proxy in the proxy
465   // chain and not the origin server.
466   const SpdySessionKey spdy_session_key_;
467 
468   // Type of stream that is requested.
469   HttpStreamRequest::StreamType stream_type_ =
470       HttpStreamRequest::BIDIRECTIONAL_STREAM;
471 
472   // Whether Job has continued to DoInitConnection().
473   bool init_connection_already_resumed_ = false;
474 
475   base::OnceClosure restart_with_auth_callback_;
476 
477   NetErrorDetails net_error_details_;
478 
479   ResolveErrorInfo resolve_error_info_;
480 
481   std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request_;
482 
483   base::WeakPtrFactory<Job> ptr_factory_{this};
484 };
485 
486 // Factory for creating Jobs.
487 class HttpStreamFactory::JobFactory {
488  public:
489   JobFactory();
490 
491   virtual ~JobFactory();
492 
493   virtual std::unique_ptr<HttpStreamFactory::Job> CreateJob(
494       HttpStreamFactory::Job::Delegate* delegate,
495       HttpStreamFactory::JobType job_type,
496       HttpNetworkSession* session,
497       const HttpRequestInfo& request_info,
498       RequestPriority priority,
499       const ProxyInfo& proxy_info,
500       const SSLConfig& server_ssl_config,
501       url::SchemeHostPort destination,
502       GURL origin_url,
503       bool is_websocket,
504       bool enable_ip_based_pooling,
505       NetLog* net_log,
506       NextProto alternative_protocol = kProtoUnknown,
507       quic::ParsedQuicVersion quic_version =
508           quic::ParsedQuicVersion::Unsupported());
509 };
510 
511 }  // namespace net
512 
513 #endif  // NET_HTTP_HTTP_STREAM_FACTORY_JOB_H_
514