• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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_CONTROLLER_H_
6 #define NET_HTTP_HTTP_STREAM_FACTORY_JOB_CONTROLLER_H_
7 
8 #include <memory>
9 #include <string>
10 #include <vector>
11 
12 #include "base/cancelable_callback.h"
13 #include "base/memory/raw_ptr.h"
14 #include "base/time/time.h"
15 #include "net/base/host_port_pair.h"
16 #include "net/base/net_errors.h"
17 #include "net/http/http_stream_factory_job.h"
18 #include "net/http/http_stream_request.h"
19 #include "net/spdy/spdy_session_pool.h"
20 #include "net/ssl/ssl_config.h"
21 #include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
22 
23 namespace net {
24 
25 class ProxyResolutionRequest;
26 
27 namespace test {
28 
29 class JobControllerPeer;
30 
31 }  // namespace test
32 
33 // HttpStreamFactory::JobController manages Request and Job(s).
34 class HttpStreamFactory::JobController
35     : public HttpStreamFactory::Job::Delegate,
36       public HttpStreamRequest::Helper {
37  public:
38   JobController(HttpStreamFactory* factory,
39                 HttpStreamRequest::Delegate* delegate,
40                 HttpNetworkSession* session,
41                 JobFactory* job_factory,
42                 const HttpRequestInfo& http_request_info,
43                 bool is_preconnect,
44                 bool is_websocket,
45                 bool enable_ip_based_pooling,
46                 bool enable_alternative_services,
47                 bool delay_main_job_with_available_spdy_session,
48                 const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs);
49 
50   ~JobController() override;
51 
52   // Used in tests only for verification purpose.
main_job()53   const Job* main_job() const { return main_job_.get(); }
alternative_job()54   const Job* alternative_job() const { return alternative_job_.get(); }
dns_alpn_h3_job()55   const Job* dns_alpn_h3_job() const { return dns_alpn_h3_job_.get(); }
56 
57   // Modifies `url` in-place, applying any applicable HostMappingRules of
58   // `session_` to it.
59   void RewriteUrlWithHostMappingRules(GURL& url) const;
60 
61   // Same as RewriteUrlWithHostMappingRules(), but duplicates `url` instead of
62   // modifying it.
63   GURL DuplicateUrlWithHostMappingRules(const GURL& url) const;
64 
65   // Methods below are called by HttpStreamFactory only.
66   // Creates request and hands out to HttpStreamFactory, this will also create
67   // Job(s) and start serving the created request.
68   std::unique_ptr<HttpStreamRequest> Start(
69       HttpStreamRequest::Delegate* delegate,
70       WebSocketHandshakeStreamBase::CreateHelper*
71           websocket_handshake_stream_create_helper,
72       const NetLogWithSource& source_net_log,
73       HttpStreamRequest::StreamType stream_type,
74       RequestPriority priority);
75 
76   void Preconnect(int num_streams);
77 
78   // From HttpStreamRequest::Helper.
79   // Returns the LoadState for Request.
80   LoadState GetLoadState() const override;
81 
82   // Called when Request is destructed. Job(s) associated with but not bound to
83   // |request_| will be deleted. |request_| and |bound_job_| will be nulled if
84   // ever set.
85   void OnRequestComplete() override;
86 
87   // Called to resume the HttpStream creation process when necessary
88   // Proxy authentication credentials are collected.
89   int RestartTunnelWithProxyAuth() override;
90 
91   // Called when the priority of transaction changes.
92   void SetPriority(RequestPriority priority) override;
93 
94   // From HttpStreamFactory::Job::Delegate.
95   // Invoked when |job| has an HttpStream ready.
96   void OnStreamReady(Job* job) override;
97 
98   // Invoked when |job| has a BidirectionalStream ready.
99   void OnBidirectionalStreamImplReady(
100       Job* job,
101       const ProxyInfo& used_proxy_info) override;
102 
103   // Invoked when |job| has a WebSocketHandshakeStream ready.
104   void OnWebSocketHandshakeStreamReady(
105       Job* job,
106       const ProxyInfo& used_proxy_info,
107       std::unique_ptr<WebSocketHandshakeStreamBase> stream) override;
108 
109   // Invoked when a QUIC job finished a DNS resolution.
110   void OnQuicHostResolution(const url::SchemeHostPort& destination,
111                             base::TimeTicks dns_resolution_start_time,
112                             base::TimeTicks dns_resolution_end_time) override;
113 
114   // Invoked when |job| fails to create a stream.
115   void OnStreamFailed(Job* job, int status) override;
116 
117   // Invoked when |job| fails on the default network.
118   void OnFailedOnDefaultNetwork(Job* job) override;
119 
120   // Invoked when |job| has a certificate error for the Request.
121   void OnCertificateError(Job* job,
122                           int status,
123                           const SSLInfo& ssl_info) override;
124 
125   // Invoked when |job| raises failure for SSL Client Auth.
126   void OnNeedsClientAuth(Job* job, SSLCertRequestInfo* cert_info) override;
127 
128   // Invoked when |job| needs proxy authentication.
129   void OnNeedsProxyAuth(Job* job,
130                         const HttpResponseInfo& proxy_response,
131                         const ProxyInfo& used_proxy_info,
132                         HttpAuthController* auth_controller) override;
133 
134   // Invoked when the |job| finishes pre-connecting sockets.
135   void OnPreconnectsComplete(Job* job, int result) override;
136 
137   // Invoked to record connection attempts made by the socket layer to
138   // Request if |job| is associated with Request.
139   void AddConnectionAttemptsToRequest(
140       Job* job,
141       const ConnectionAttempts& attempts) override;
142 
143   // Invoked when |job| finishes initiating a connection.
144   // Resume the other job if there's an error raised.
145   void OnConnectionInitialized(Job* job, int rv) override;
146 
147   // Return false if |job| can advance to the next state. Otherwise, |job|
148   // will wait for Job::Resume() to be called before advancing.
149   bool ShouldWait(Job* job) override;
150 
151   const NetLogWithSource* GetNetLog() const override;
152 
153   void MaybeSetWaitTimeForMainJob(const base::TimeDelta& delay) override;
154 
155   WebSocketHandshakeStreamBase::CreateHelper*
156   websocket_handshake_stream_create_helper() override;
157 
is_preconnect()158   bool is_preconnect() const { return is_preconnect_; }
159 
160   // Returns true if |this| has a pending request that is not completed.
HasPendingRequest()161   bool HasPendingRequest() const { return request_ != nullptr; }
162 
163   // Returns true if |this| has a pending main job that is not completed.
164   bool HasPendingMainJob() const;
165 
166   // Returns true if |this| has a pending alternative job that is not completed.
167   bool HasPendingAltJob() const;
168 
get_main_job_wait_time_for_tests()169   base::TimeDelta get_main_job_wait_time_for_tests() {
170     return main_job_wait_time_;
171   }
172 
173  private:
174   friend class test::JobControllerPeer;
175 
176   enum State {
177     STATE_RESOLVE_PROXY,
178     STATE_RESOLVE_PROXY_COMPLETE,
179     STATE_CREATE_JOBS,
180     STATE_NONE
181   };
182 
183   void OnIOComplete(int result);
184 
185   void RunLoop(int result);
186   int DoLoop(int result);
187   int DoResolveProxy();
188   int DoResolveProxyComplete(int result);
189   // Creates Job(s) for |request_info_|. Job(s) will be owned by |this|.
190   int DoCreateJobs();
191 
192   // Called to bind |job| to the |request_| and orphan all other jobs that are
193   // still associated with |request_|.
194   void BindJob(Job* job);
195 
196   // Called after BindJob() to notify the unbound job that its result should be
197   // ignored by JobController. The unbound job can be canceled or continue until
198   // completion.
199   void OrphanUnboundJob();
200 
201   // Invoked when the orphaned |job| finishes.
202   void OnOrphanedJobComplete(const Job* job);
203 
204   // Called when a Job succeeds.
205   void OnJobSucceeded(Job* job);
206 
207   // Clears inappropriate jobs before starting them.
208   void ClearInappropriateJobs();
209 
210   // Marks completion of the |request_|.
211   void MarkRequestComplete(Job* job);
212 
213   // Called when all Jobs complete. Reports alternative service brokenness to
214   // HttpServerProperties if apply and resets net errors afterwards:
215   // - report broken if the main job has no error and the alternative job has an
216   //   error;
217   // - report broken until default network change if the main job has no error,
218   //   the alternative job has no error, but the alternative job failed on the
219   //   default network.
220   void MaybeReportBrokenAlternativeService(
221       const AlternativeService& alt_service,
222       int alt_job_net_error,
223       bool alt_job_failed_on_default_network,
224       const std::string& histogram_name_for_failure);
225 
226   void MaybeNotifyFactoryOfCompletion();
227 
228   void NotifyRequestFailed(int rv);
229 
230   // Called to resume the main job with delay. Main job is resumed only when
231   // |alternative_job_| has failed or |main_job_wait_time_| elapsed.
232   void MaybeResumeMainJob(Job* job, const base::TimeDelta& delay);
233 
234   // Posts a task to resume the main job after |delay|.
235   void ResumeMainJobLater(const base::TimeDelta& delay);
236 
237   // Resumes the main job immediately.
238   void ResumeMainJob();
239 
240   // Reset error status to default value for Jobs:
241   // - reset |main_job_net_error_| and |alternative_job_net_error_| and
242   //   |dns_alpn_h3_job_net_error_| to OK;
243   // - reset |alternative_job_failed_on_default_network_| and
244   //   |dns_alpn_h3_job_failed_on_default_network_| to false.
245   void ResetErrorStatusForJobs();
246 
247   AlternativeServiceInfo GetAlternativeServiceInfoFor(
248       const GURL& http_request_info_url,
249       const StreamRequestInfo& request_info,
250       HttpStreamRequest::Delegate* delegate,
251       HttpStreamRequest::StreamType stream_type);
252 
253   AlternativeServiceInfo GetAlternativeServiceInfoInternal(
254       const GURL& http_request_info_url,
255       const StreamRequestInfo& request_info,
256       HttpStreamRequest::Delegate* delegate,
257       HttpStreamRequest::StreamType stream_type);
258 
259   // Just calls QuicContext::SelectQuicVersion().
260   quic::ParsedQuicVersion SelectQuicVersion(
261       const quic::ParsedQuicVersionVector& advertised_versions);
262 
263   // Records histogram metrics for the usage of alternative protocol. Must be
264   // called when |job| has succeeded and the other job will be orphaned.
265   void ReportAlternateProtocolUsage(
266       AlternateProtocolUsage alternate_protocol_usage,
267       bool is_google_host) const;
268 
269   // Returns whether |job| is an orphaned job.
270   bool IsJobOrphaned(Job* job) const;
271 
272   // Calculates why Chrome uses a specific transport protocol for HTTP semantics
273   // and returns it as an enum.
274   // This returns ALTERNATE_PROTOCOL_USAGE_UNSPECIFIED_REASON as a default value
275   // when the reason is unknown.
276   AlternateProtocolUsage CalculateAlternateProtocolUsage(Job* job) const;
277 
278   // Called when a Job encountered a network error that could be resolved by
279   // trying a new proxy configuration. If there is another proxy configuration
280   // to try then this method sets |next_state_| appropriately and returns either
281   // OK or ERR_IO_PENDING depending on whether or not the new proxy
282   // configuration is available synchronously or asynchronously.  Otherwise, the
283   // given error code is simply returned.
284   int ReconsiderProxyAfterError(Job* job, int error);
285 
286   // Returns true if QUIC is allowed for |host|.
287   bool IsQuicAllowedForHost(const std::string& host);
288 
GetJobCount()289   int GetJobCount() const {
290     return (main_job_ ? 1 : 0) + (alternative_job_ ? 1 : 0) +
291            (dns_alpn_h3_job_ ? 1 : 0);
292   }
293 
294   // Called when the request needs to use the HttpStreamPool instead of `this`.
295   // Call site of Start() should destroy the current HttpStreamRequest and
296   // switch to the HttpStreamPool. `this` will be destroyed when `request_` is
297   // destroyed.
298   void SwitchToHttpStreamPool();
299 
300   // Called when `this` asked the HttpStreamPool to handle a preconnect and
301   // the preconnect completed. Used to notify the factory of completion.
302   void OnPoolPreconnectsComplete(int rv);
303 
304   // Used to call HttpStreamRequest::OnSwitchesToHttpStreamPool() later.
305   void CallOnSwitchesToHttpStreamPool(HttpStreamPoolRequestInfo request_info);
306 
307   const raw_ptr<HttpStreamFactory> factory_;
308   const raw_ptr<HttpNetworkSession> session_;
309   const raw_ptr<JobFactory> job_factory_;
310 
311   // Request will be handed out to factory once created. This just keeps an
312   // reference and is safe as |request_| will notify |this| JobController
313   // when it's destructed by calling OnRequestComplete(), which nulls
314   // |request_|.
315   raw_ptr<HttpStreamRequest> request_ = nullptr;
316 
317   raw_ptr<HttpStreamRequest::Delegate> delegate_;
318 
319   // True if this JobController is used to preconnect streams.
320   const bool is_preconnect_;
321 
322   // True if request is for Websocket.
323   const bool is_websocket_;
324 
325   // Enable pooling to a SpdySession with matching IP and certificate even if
326   // the SpdySessionKey is different.
327   const bool enable_ip_based_pooling_;
328 
329   // Enable using alternative services for the request. If false, the
330   // JobController will only create a |main_job_|.
331   const bool enable_alternative_services_;
332 
333   // For normal (non-preconnect) job, |main_job_| is a job waiting to see if
334   // |alternative_job_| or |dns_alpn_h3_job_| can reuse a connection. If both
335   // |alternative_job_| and |dns_alpn_h3_job_| are unable to do so, |this| will
336   // notify |main_job_| to proceed and then race the two jobs.
337   // For preconnect job, |main_job_| is started first, and if it fails with
338   // ERR_DNS_NO_MATCHING_SUPPORTED_ALPN, |preconnect_backup_job_| will be
339   // started.
340   std::unique_ptr<Job> main_job_;
341   std::unique_ptr<Job> alternative_job_;
342   std::unique_ptr<Job> dns_alpn_h3_job_;
343 
344   std::unique_ptr<Job> preconnect_backup_job_;
345 
346   // The alternative service used by |alternative_job_|
347   // (or by |main_job_| if |is_preconnect_|.)
348   AlternativeServiceInfo alternative_service_info_;
349 
350   // Error status used for alternative service brokenness reporting.
351   // Net error code of the main job. Set to OK by default.
352   int main_job_net_error_ = OK;
353   // Net error code of the alternative job. Set to OK by default.
354   int alternative_job_net_error_ = OK;
355   // Set to true if the alternative job failed on the default network.
356   bool alternative_job_failed_on_default_network_ = false;
357   // Net error code of the DNS HTTPS ALPN job. Set to OK by default.
358   int dns_alpn_h3_job_net_error_ = OK;
359   // Set to true if the DNS HTTPS ALPN job failed on the default network.
360   bool dns_alpn_h3_job_failed_on_default_network_ = false;
361 
362   // True if a Job has ever been bound to the |request_|.
363   bool job_bound_ = false;
364 
365   // True if the main job has to wait for the alternative job: i.e., the main
366   // job must not create a connection until it is resumed.
367   bool main_job_is_blocked_ = false;
368 
369   // Handle for cancelling any posted delayed ResumeMainJob() task.
370   base::CancelableOnceClosure resume_main_job_callback_;
371   // True if the main job was blocked and has been resumed in ResumeMainJob().
372   bool main_job_is_resumed_ = false;
373 
374   // If true, delay main job even the request can be sent immediately on an
375   // available SPDY session.
376   bool delay_main_job_with_available_spdy_session_;
377 
378   // Set to true when `this` asked the request to use HttpStreamPool instead
379   // of `this`.
380   bool switched_to_http_stream_pool_ = false;
381 
382   // Waiting time for the main job before it is resumed.
383   base::TimeDelta main_job_wait_time_;
384 
385   // At the point where a Job is irrevocably tied to |request_|, we set this.
386   // It will be nulled when the |request_| is finished.
387   raw_ptr<Job> bound_job_ = nullptr;
388 
389   State next_state_ = STATE_RESOLVE_PROXY;
390   std::unique_ptr<ProxyResolutionRequest> proxy_resolve_request_;
391   // The URL from the input `http_request_info`.
392   // TODO(https://crbug.com/332724851): Remove this, and update code to use
393   // `origin_url_`.
394   const GURL http_request_info_url_;
395   // The same as `request_info_url_`, but with any applicable rules in
396   // HostMappingRules applied to it.
397   // TODO: Make this use SchemeHostPort instead, and rename it.
398   const GURL origin_url_;
399   const StreamRequestInfo request_info_;
400   ProxyInfo proxy_info_;
401   const std::vector<SSLConfig::CertAndStatus> allowed_bad_certs_;
402   int num_streams_ = 0;
403   HttpStreamRequest::StreamType stream_type_;
404   RequestPriority priority_ = IDLE;
405   const NetLogWithSource net_log_;
406 
407   base::WeakPtrFactory<JobController> ptr_factory_{this};
408 };
409 
410 }  // namespace net
411 
412 #endif  // NET_HTTP_HTTP_STREAM_FACTORY_JOB_CONTROLLER_H_
413