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