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