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