// 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 CHROME_BROWSER_RENDERER_HOST_SAFE_BROWSING_RESOURCE_THROTTLE_H_ #define CHROME_BROWSER_RENDERER_HOST_SAFE_BROWSING_RESOURCE_THROTTLE_H_ #include #include #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/safe_browsing/ui_manager.h" #include "components/safe_browsing_db/database_manager.h" #include "content/public/browser/resource_throttle.h" #include "content/public/common/resource_type.h" #include "net/log/net_log.h" class ResourceDispatcherHost; namespace net { class URLRequest; } // SafeBrowsingResourceThrottle checks that URLs are "safe" before // navigating to them. To be considered "safe", a URL must not appear in the // malware/phishing blacklists (see SafeBrowsingService for details). // // On desktop (ifdef SAFE_BROWSING_DB_LOCAL) // ----------------------------------------- // This check is done before requesting the original URL, and additionally // before following any subsequent redirect. In the common case the check // completes synchronously (no match in the in-memory DB), so the request's // flow is un-interrupted. However if the URL fails this quick check, it // has the possibility of being on the blacklist. Now the request is // deferred (prevented from starting), and a more expensive safe browsing // check is begun (fetches the full hashes). // // On mobile (ifdef SAFE_BROWSING_DB_REMOTE): // ----------------------------------------- // The check is started and runs in parallel with the resource load. If the // check is not complete by the time the headers are loaded, the request is // suspended until the URL is classified. We let the headers load on mobile // since the RemoteSafeBrowsingDatabase checks always have some non-zero // latency -- there no synchronous pass. This parallelism helps // performance. Redirects are handled the same way as desktop so they // always defer. // // // Note that the safe browsing check takes at most kCheckUrlTimeoutMs // milliseconds. If it takes longer than this, then the system defaults to // treating the URL as safe. // // If the URL is classified as dangerous, a warning page is thrown up and // the request remains suspended. If the user clicks "proceed" on warning // page, we resume the request. // // Note: The ResourceThrottle interface is called in this order: // WillStartRequest once, WillRedirectRequest zero or more times, and then // WillProcessReponse once. class SafeBrowsingResourceThrottle : public content::ResourceThrottle, public safe_browsing::SafeBrowsingDatabaseManager::Client, public base::SupportsWeakPtr { public: // Will construct a SafeBrowsingResourceThrottle, or return NULL // if on Android and not in the field trial. static SafeBrowsingResourceThrottle* MaybeCreate( net::URLRequest* request, content::ResourceType resource_type, safe_browsing::SafeBrowsingService* sb_service); // content::ResourceThrottle implementation (called on IO thread): void WillStartRequest(bool* defer) override; void WillRedirectRequest(const net::RedirectInfo& redirect_info, bool* defer) override; void WillProcessResponse(bool* defer) override; const char* GetNameForLogging() const override; // SafeBrowsingDabaseManager::Client implementation (called on IO thread): void OnCheckBrowseUrlResult(const GURL& url, safe_browsing::SBThreatType result, const std::string& metadata) override; protected: SafeBrowsingResourceThrottle(const net::URLRequest* request, content::ResourceType resource_type, safe_browsing::SafeBrowsingService* sb_service); private: // Describes what phase of the check a throttle is in. enum State { // Haven't started checking or checking is complete. Not deferred. STATE_NONE, // We have one outstanding URL-check. Could be deferred. STATE_CHECKING_URL, // We're displaying a blocking page. Could be deferred. STATE_DISPLAYING_BLOCKING_PAGE, }; // Describes what stage of the request got paused by the check. enum DeferState { DEFERRED_NONE, DEFERRED_START, DEFERRED_REDIRECT, DEFERRED_UNCHECKED_REDIRECT, // unchecked_redirect_url_ is populated. DEFERRED_PROCESSING, }; ~SafeBrowsingResourceThrottle() override; // SafeBrowsingService::UrlCheckCallback implementation. void OnBlockingPageComplete(bool proceed); // Starts running |url| through the safe browsing check. Returns true if the // URL is safe to visit. Otherwise returns false and will call // OnBrowseUrlResult() when the check has completed. bool CheckUrl(const GURL& url); // Callback for when the safe browsing check (which was initiated by // StartCheckingUrl()) has taken longer than kCheckUrlTimeoutMs. void OnCheckUrlTimeout(); // Starts displaying the safe browsing interstitial page if it's not // prerendering. Called on the UI thread. static void StartDisplayingBlockingPage( const base::WeakPtr& throttle, scoped_refptr ui_manager, const safe_browsing::SafeBrowsingUIManager::UnsafeResource& resource); // Called on the IO thread if the request turned out to be for a prerendered // page. void Cancel(); // Resumes the request, by continuing the deferred action (either starting the // request, or following a redirect). void ResumeRequest(); // For marking network events. |name| and |value| can be null. void BeginNetLogEvent(net::NetLog::EventType type, const GURL& url, const char* name, const char* value); void EndNetLogEvent(net::NetLog::EventType type, const char* name, const char* value); State state_; DeferState defer_state_; // The result of the most recent safe browsing check. Only valid to read this // when state_ != STATE_CHECKING_URL. safe_browsing::SBThreatType threat_type_; // The time when we started deferring the request. base::TimeTicks defer_start_time_; // Timer to abort the safe browsing check if it takes too long. base::OneShotTimer timer_; // The redirect chain for this resource std::vector redirect_urls_; // If in DEFERRED_UNCHECKED_REDIRECT state, this is the // URL we still need to check before resuming. GURL unchecked_redirect_url_; GURL url_being_checked_; scoped_refptr database_manager_; scoped_refptr ui_manager_; const net::URLRequest* request_; const content::ResourceType resource_type_; net::BoundNetLog bound_net_log_; DISALLOW_COPY_AND_ASSIGN(SafeBrowsingResourceThrottle); }; #endif // CHROME_BROWSER_RENDERER_HOST_SAFE_BROWSING_RESOURCE_THROTTLE_H_