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