// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CONTENT_BROWSER_LOADER_RESOURCE_LOADER_H_ #define CONTENT_BROWSER_LOADER_RESOURCE_LOADER_H_ #include #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" #include "base/time/time.h" #include "content/browser/loader/resource_controller.h" #include "content/browser/loader/resource_handler.h" #include "content/browser/ssl/ssl_client_auth_handler.h" #include "content/browser/ssl/ssl_error_handler.h" #include "content/common/content_export.h" #include "net/http/http_raw_request_headers.h" #include "net/url_request/url_request.h" #include "url/gurl.h" namespace net { class HttpResponseHeaders; class X509Certificate; } namespace network { class ScopedThrottlingToken; } namespace content { class LoginDelegate; class ResourceHandler; class ResourceLoaderDelegate; class ResourceRequestInfoImpl; // This class is responsible for driving the URLRequest (i.e., calling Start, // Read, and servicing events). It has a ResourceHandler, which is typically a // chain of ResourceHandlers, and is the ResourceController for its handler. class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate, public SSLErrorHandler::Delegate, public SSLClientAuthHandler::Delegate, public ResourceHandler::Delegate { public: ResourceLoader( std::unique_ptr request, std::unique_ptr handler, ResourceLoaderDelegate* delegate, ResourceContext* resource_context, std::unique_ptr throttling_token); ~ResourceLoader() override; void StartRequest(); void CancelRequest(bool from_renderer); net::URLRequest* request() { return request_.get(); } ResourceRequestInfoImpl* GetRequestInfo(); void ClearLoginDelegate(); // ResourceHandler::Delegate implementation: void OutOfBandCancel(int error_code, bool tell_renderer) override; void PauseReadingBodyFromNet() override; void ResumeReadingBodyFromNet() override; private: // ResourceController implementation for the ResourceLoader. class Controller; // net::URLRequest::Delegate implementation: void OnReceivedRedirect(net::URLRequest* request, const net::RedirectInfo& redirect_info, bool* defer) override; void OnAuthRequired(net::URLRequest* request, net::AuthChallengeInfo* info) override; void OnCertificateRequested(net::URLRequest* request, net::SSLCertRequestInfo* info) override; void OnSSLCertificateError(net::URLRequest* request, const net::SSLInfo& info, bool fatal) override; void OnResponseStarted(net::URLRequest* request, int net_error) override; void OnReadCompleted(net::URLRequest* request, int bytes_read) override; // SSLErrorHandler::Delegate implementation: void CancelSSLRequest(int error, const net::SSLInfo* ssl_info) override; void ContinueSSLRequest() override; // SSLClientAuthHandler::Delegate implementation. void ContinueWithCertificate( scoped_refptr cert, scoped_refptr private_key) override; void CancelCertificateSelection() override; // These correspond to Controller's methods. // TODO(mmenke): Seems like this could be simplified a little. // |called_from_resource_controller| is true if called directly from a // ResourceController, in which case |resource_handler_| must not be invoked // or destroyed synchronously to avoid re-entrancy issues, and false // otherwise. |modified_request_headers| is used for redirects only. void Resume( bool called_from_resource_controller, const base::Optional& modified_request_headers); void Cancel(); void CancelWithError(int error_code); void StartRequestInternal(); void CancelRequestInternal(int error, bool from_renderer); void FollowDeferredRedirectInternal( const base::Optional& modified_request_headers); void CompleteResponseStarted(); // If |handle_result_async| is true, the result of the following read will be // handled asynchronously if it completes synchronously, unless it's EOF or an // error. This is to prevent a single request from blocking the thread for too // long. void PrepareToReadMore(bool handle_result_async); void ReadMore(bool handle_result_async); void ResumeReading(); // Passes a read result to the handler. void CompleteRead(int bytes_read); void ResponseCompleted(); void CallDidFinishLoading(); void SetRawResponseHeaders( scoped_refptr headers); bool is_deferred() const { return deferred_stage_ != DEFERRED_NONE; } // Used for categorizing loading of prefetches for reporting in histograms. // NOTE: This enumeration is used in histograms, so please do not add entries // in the middle. enum PrefetchStatus { STATUS_UNDEFINED, STATUS_SUCCESS_FROM_CACHE, STATUS_SUCCESS_FROM_NETWORK, STATUS_CANCELED, STATUS_SUCCESS_ALREADY_PREFETCHED, STATUS_MAX, }; enum DeferredStage { DEFERRED_NONE, // Magic deferral "stage" which means that the code is currently in a // recursive call from the ResourceLoader. When in this state, Resume() does // nothing but update the deferral state, and when the stack is unwound back // up to the ResourceLoader, the request will be continued. This is used to // prevent the stack from getting too deep. DEFERRED_SYNC, DEFERRED_START, DEFERRED_REDIRECT, DEFERRED_ON_WILL_READ, DEFERRED_READ, DEFERRED_RESPONSE_COMPLETE, DEFERRED_FINISH }; DeferredStage deferred_stage_; class ScopedDeferral; std::unique_ptr request_; std::unique_ptr handler_; ResourceLoaderDelegate* delegate_; scoped_refptr login_delegate_; std::unique_ptr ssl_client_auth_handler_; base::TimeTicks read_deferral_start_time_; // Instrumentation add to investigate http://crbug.com/503306. // TODO(mmenke): Remove once bug is fixed. int times_cancelled_before_request_start_; bool started_request_; int times_cancelled_after_request_start_; // Stores the URL from a deferred redirect. GURL deferred_redirect_url_; // Read buffer and its size. Class members as OnWillRead can complete // asynchronously. scoped_refptr read_buffer_; int read_buffer_size_; net::HttpRawRequestHeaders raw_request_headers_; scoped_refptr raw_response_headers_; ResourceContext* resource_context_; std::unique_ptr throttling_token_; bool should_pause_reading_body_ = false; // The request is not deferred (i.e., DEFERRED_NONE) and is ready to read more // response body data. However, reading is paused because of // PauseReadingBodyFromNet(). bool read_more_body_supressed_ = false; // Whether to update |body_read_before_paused_| after the pending read is // completed (or when this resource loader is destroyed). bool update_body_read_before_paused_ = false; // The number of bytes obtained by the reads initiated before the last // PauseReadingBodyFromNet() call. -1 means the request hasn't been paused. // The body may be read from cache or network. So even if this value is not // -1, we still need to check whether it is from network before reporting it // as BodyReadFromNetBeforePaused. int64_t body_read_before_paused_ = -1; bool pending_read_ = false; base::ThreadChecker thread_checker_; base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ResourceLoader); }; } // namespace content #endif // CONTENT_BROWSER_LOADER_RESOURCE_LOADER_H_