Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8467)

Unified Diff: chrome/browser/safe_browsing/mojo_safe_browsing_impl.cc

Issue 2900563002: Network service: Safe browsing check for sub-resources from renderer. (Closed)
Patch Set: . Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/safe_browsing/mojo_safe_browsing_impl.h ('k') | chrome/common/BUILD.gn » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/safe_browsing/mojo_safe_browsing_impl.cc
diff --git a/chrome/browser/safe_browsing/mojo_safe_browsing_impl.cc b/chrome/browser/safe_browsing/mojo_safe_browsing_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..165bb38a939822d545b956ace5c0cedea2ff5cb4
--- /dev/null
+++ b/chrome/browser/safe_browsing/mojo_safe_browsing_impl.cc
@@ -0,0 +1,304 @@
+// Copyright 2017 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.
+
+#include "chrome/browser/safe_browsing/mojo_safe_browsing_impl.h"
+
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prerender/prerender_contents.h"
+#include "chrome/browser/safe_browsing/ui_manager.h"
+#include "components/safe_browsing_db/database_manager.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/resource_type.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "net/base/load_flags.h"
+
+namespace safe_browsing {
+namespace {
+
+// TODO(yzshen): Share such value with safe_browsing::BaseResourceThrottle.
+// Maximum time in milliseconds to wait for the SafeBrowsing service reputation
+// check. After this amount of time the outstanding check will be aborted, and
+// the resource will be treated as if it were safe.
+const int kCheckUrlTimeoutMs = 5000;
+
+content::WebContents* GetWebContentsFromID(int render_process_id,
+ int render_frame_id) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ content::RenderFrameHost* render_frame_host =
+ content::RenderFrameHost::FromID(render_process_id, render_frame_id);
+ if (!render_frame_host)
+ return nullptr;
+
+ return content::WebContents::FromRenderFrameHost(render_frame_host);
+}
+
+// TODO(yzshen): Handle the case where SafeBrowsing is not enabled, or
+// !database_manager()->IsSupported().
+// TODO(yzshen): Make sure it also works on Andorid.
+// TODO(yzshen): Do all the logging like what BaseResourceThrottle does.
+class SafeBrowsingUrlCheckerImpl : public chrome::mojom::SafeBrowsingUrlChecker,
+ public SafeBrowsingDatabaseManager::Client {
+ public:
+ SafeBrowsingUrlCheckerImpl(
+ int load_flags,
+ content::ResourceType resource_type,
+ scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+ scoped_refptr<SafeBrowsingUIManager> ui_manager,
+ int render_process_id,
+ int render_frame_id)
+ : load_flags_(load_flags),
+ resource_type_(resource_type),
+ render_process_id_(render_process_id),
+ render_frame_id_(render_frame_id),
+ database_manager_(std::move(database_manager)),
+ ui_manager_(std::move(ui_manager)),
+ weak_factory_(this) {
+ DCHECK_NE(resource_type, content::RESOURCE_TYPE_MAIN_FRAME);
+ DCHECK_NE(resource_type, content::RESOURCE_TYPE_SUB_FRAME);
+ }
+
+ ~SafeBrowsingUrlCheckerImpl() override {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ if (state_ == STATE_CHECKING_URL)
+ database_manager_->CancelCheck(this);
+
+ for (size_t i = next_index_; i < callbacks_.size(); ++i)
+ std::move(callbacks_[i]).Run(false);
+ }
+
+ // chrome::mojom::SafeBrowsingUrlChecker implementation.
+ void CheckUrl(const GURL& url, CheckUrlCallback callback) override {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ DVLOG(1) << "SafeBrowsingUrlCheckerImpl checks URL: " << url;
+ urls_.push_back(url);
+ callbacks_.push_back(std::move(callback));
+
+ ProcessUrls();
+ }
+
+ private:
+ // SafeBrowsingDatabaseManager::Client implementation:
+ void OnCheckBrowseUrlResult(const GURL& url,
+ SBThreatType threat_type,
+ const ThreatMetadata& metadata) override {
+ DCHECK_EQ(STATE_CHECKING_URL, state_);
+ DCHECK_LT(next_index_, urls_.size());
+ DCHECK_EQ(urls_[next_index_], url);
+
+ timer_.Stop();
+ if (threat_type == SB_THREAT_TYPE_SAFE) {
+ state_ = STATE_NONE;
+ std::move(callbacks_[next_index_]).Run(true);
+ next_index_++;
+ ProcessUrls();
+ return;
+ }
+
+ if (load_flags_ & net::LOAD_PREFETCH) {
+ BlockAndProcessUrls();
+ return;
+ }
+
+ security_interstitials::UnsafeResource resource;
+ resource.url = url;
+ resource.original_url = urls_[0];
+ if (urls_.size() > 1)
+ resource.redirect_urls =
+ std::vector<GURL>(urls_.begin() + 1, urls_.end());
+ resource.is_subresource = true;
+ resource.is_subframe = false;
+ resource.threat_type = threat_type;
+ resource.threat_metadata = metadata;
+ resource.callback =
+ base::Bind(&SafeBrowsingUrlCheckerImpl::OnBlockingPageComplete,
+ weak_factory_.GetWeakPtr());
+ resource.callback_thread = content::BrowserThread::GetTaskRunnerForThread(
+ content::BrowserThread::IO);
+ resource.web_contents_getter =
+ base::Bind(&GetWebContentsFromID, render_process_id_, render_frame_id_);
+ resource.threat_source = database_manager_->GetThreatSource();
+
+ state_ = STATE_DISPLAYING_BLOCKING_PAGE;
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&SafeBrowsingUrlCheckerImpl::StartDisplayingBlockingPage,
+ weak_factory_.GetWeakPtr(), ui_manager_, resource));
+ }
+
+ static void StartDisplayingBlockingPage(
+ const base::WeakPtr<SafeBrowsingUrlCheckerImpl>& checker,
+ scoped_refptr<BaseUIManager> ui_manager,
+ const security_interstitials::UnsafeResource& resource) {
+ content::WebContents* web_contents = resource.web_contents_getter.Run();
+ if (web_contents) {
+ prerender::PrerenderContents* prerender_contents =
+ prerender::PrerenderContents::FromWebContents(web_contents);
+ if (prerender_contents) {
+ prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
+ } else {
+ ui_manager->DisplayBlockingPage(resource);
+ return;
+ }
+ }
+
+ // Tab is gone or it's being prerendered.
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&SafeBrowsingUrlCheckerImpl::BlockAndProcessUrls,
+ checker));
+ }
+
+ void OnCheckUrlTimeout() {
+ database_manager_->CancelCheck(this);
+
+ OnCheckBrowseUrlResult(urls_[next_index_],
+ safe_browsing::SB_THREAT_TYPE_SAFE,
+ ThreatMetadata());
+ }
+
+ void ProcessUrls() {
+ DCHECK_NE(STATE_BLOCKED, state_);
+
+ if (state_ == STATE_CHECKING_URL ||
+ state_ == STATE_DISPLAYING_BLOCKING_PAGE) {
+ return;
+ }
+
+ while (next_index_ < urls_.size()) {
+ DCHECK_EQ(STATE_NONE, state_);
+ // TODO(yzshen): Consider moving CanCheckResourceType() to the renderer
+ // side. That would save some IPCs. It requires a method on the
+ // SafeBrowsing mojo interface to query all supported resource types.
+ if (!database_manager_->CanCheckResourceType(resource_type_) ||
+ database_manager_->CheckBrowseUrl(urls_[next_index_], this)) {
+ std::move(callbacks_[next_index_]).Run(true);
+ next_index_++;
+ continue;
+ }
+
+ state_ = STATE_CHECKING_URL;
+ // Start a timer to abort the check if it takes too long.
+ timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), this,
+ &SafeBrowsingUrlCheckerImpl::OnCheckUrlTimeout);
+
+ break;
+ }
+ }
+
+ void BlockAndProcessUrls() {
+ DVLOG(1) << "SafeBrowsingUrlCheckerImpl blocks URL: " << urls_[next_index_];
+ state_ = STATE_BLOCKED;
+
+ // If user decided to not proceed through a warning, mark all the remaining
+ // redirects as "bad".
+ for (; next_index_ < callbacks_.size(); ++next_index_)
+ std::move(callbacks_[next_index_]).Run(false);
+ }
+
+ void OnBlockingPageComplete(bool proceed) {
+ DCHECK_EQ(STATE_DISPLAYING_BLOCKING_PAGE, state_);
+
+ if (proceed) {
+ state_ = STATE_NONE;
+ std::move(callbacks_[next_index_]).Run(true);
+ next_index_++;
+ ProcessUrls();
+ } else {
+ BlockAndProcessUrls();
+ }
+ }
+
+ enum State {
+ // Haven't started checking or checking is complete.
+ STATE_NONE,
+ // We have one outstanding URL-check.
+ STATE_CHECKING_URL,
+ // We're displaying a blocking page.
+ STATE_DISPLAYING_BLOCKING_PAGE,
+ // The blocking page has returned *not* to proceed.
+ STATE_BLOCKED
+ };
+
+ const int load_flags_;
+ const content::ResourceType resource_type_;
+ const int render_process_id_;
+ const int render_frame_id_;
+ scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
+ scoped_refptr<BaseUIManager> ui_manager_;
+
+ // The redirect chain for this resource, including the original URL and
+ // subsequent redirect URLs.
+ std::vector<GURL> urls_;
+ // Callbacks corresponding to |urls_| to report check results. |urls_| and
+ // |callbacks_| are always of the same size.
+ std::vector<CheckUrlCallback> callbacks_;
+ // |urls_| before |next_index_| have been checked. If |next_index_| is smaller
+ // than the size of |urls_|, the URL at |next_index_| is being processed.
+ size_t next_index_ = 0;
+
+ State state_ = STATE_NONE;
+
+ // Timer to abort the SafeBrowsing check if it takes too long.
+ base::OneShotTimer timer_;
+
+ base::WeakPtrFactory<SafeBrowsingUrlCheckerImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SafeBrowsingUrlCheckerImpl);
+};
+
+} // namespace
+
+MojoSafeBrowsingImpl::MojoSafeBrowsingImpl(
+ scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+ scoped_refptr<SafeBrowsingUIManager> ui_manager,
+ int render_process_id)
+ : database_manager_(std::move(database_manager)),
+ ui_manager_(std::move(ui_manager)),
+ render_process_id_(render_process_id) {}
+
+MojoSafeBrowsingImpl::~MojoSafeBrowsingImpl() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+}
+
+// static
+void MojoSafeBrowsingImpl::Create(
+ scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+ scoped_refptr<SafeBrowsingUIManager> ui_manager,
+ int render_process_id,
+ const service_manager::BindSourceInfo& source_info,
+ chrome::mojom::SafeBrowsingRequest request) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ mojo::MakeStrongBinding(base::MakeUnique<MojoSafeBrowsingImpl>(
+ std::move(database_manager),
+ std::move(ui_manager), render_process_id),
+ std::move(request));
+}
+
+void MojoSafeBrowsingImpl::CreateCheckerAndCheck(
+ int32_t render_frame_id,
+ chrome::mojom::SafeBrowsingUrlCheckerRequest request,
+ const GURL& url,
+ int32_t load_flags,
Nathan Parker 2017/06/01 18:22:04 load_flags is int32_t here, and int above. Want t
yzshen1 2017/06/01 18:36:52 Yeah. That is a good question. I used it as int32_
Nathan Parker 2017/06/01 18:38:49 I assume all our platforms have 32-bit "ints" so i
yzshen1 2017/06/01 18:44:44 Done. I added static_cast to be explicit. Thanks!
+ content::ResourceType resource_type,
+ CreateCheckerAndCheckCallback callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ auto checker_impl = base::MakeUnique<SafeBrowsingUrlCheckerImpl>(
+ load_flags, resource_type, database_manager_, ui_manager_,
+ render_process_id_, render_frame_id);
+ checker_impl->CheckUrl(url, std::move(callback));
+ mojo::MakeStrongBinding(std::move(checker_impl), std::move(request));
+}
+
+} // namespace safe_browsing
« no previous file with comments | « chrome/browser/safe_browsing/mojo_safe_browsing_impl.h ('k') | chrome/common/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698