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

Side by Side 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, 6 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/safe_browsing/mojo_safe_browsing_impl.h"
6
7 #include <vector>
8
9 #include "base/memory/ptr_util.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/timer/timer.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/prerender/prerender_contents.h"
14 #include "chrome/browser/safe_browsing/ui_manager.h"
15 #include "components/safe_browsing_db/database_manager.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_frame_host.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/common/resource_type.h"
20 #include "mojo/public/cpp/bindings/strong_binding.h"
21 #include "net/base/load_flags.h"
22
23 namespace safe_browsing {
24 namespace {
25
26 // TODO(yzshen): Share such value with safe_browsing::BaseResourceThrottle.
27 // Maximum time in milliseconds to wait for the safe browsing service to
28 // verify a URL. After this amount of time the outstanding check will be
29 // aborted, and the URL will be treated as if it were safe.
30 const int kCheckUrlTimeoutMs = 5000;
31
32 content::WebContents* GetWebContentsFromID(int render_process_id,
33 int render_frame_id) {
34 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
35 content::RenderFrameHost* render_frame_host =
36 content::RenderFrameHost::FromID(render_process_id, render_frame_id);
37 if (!render_frame_host)
38 return nullptr;
39
40 return content::WebContents::FromRenderFrameHost(render_frame_host);
41 }
42
43 // TODO(yzshen): Handle the case where safe browsing is not enabled, or
44 // !database_manager()->IsSupported().
45 // TODO(yzshen): Make sure it also works on Andorid.
46 // TODO(yzshen): Do all the logging like what BaseResourceThrottle does.
47 class SafeBrowsingUrlCheckerImpl : public chrome::mojom::SafeBrowsingUrlChecker,
48 public SafeBrowsingDatabaseManager::Client {
49 public:
50 SafeBrowsingUrlCheckerImpl(
51 int load_flags,
52 content::ResourceType resource_type,
53 scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
54 scoped_refptr<SafeBrowsingUIManager> ui_manager,
55 int render_process_id,
56 int render_frame_id)
57 : load_flags_(load_flags),
58 resource_type_(resource_type),
59 render_process_id_(render_process_id),
60 render_frame_id_(render_frame_id),
61 database_manager_(std::move(database_manager)),
62 ui_manager_(std::move(ui_manager)),
63 weak_factory_(this) {
64 DCHECK_NE(resource_type, content::RESOURCE_TYPE_MAIN_FRAME);
65 DCHECK_NE(resource_type, content::RESOURCE_TYPE_SUB_FRAME);
66 }
67
68 ~SafeBrowsingUrlCheckerImpl() override {
69 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
70
71 if (state_ == STATE_CHECKING_URL)
72 database_manager_->CancelCheck(this);
73
74 for (size_t i = next_index_; i < callbacks_.size(); ++i)
75 std::move(callbacks_[i]).Run(false);
76 }
77
78 // chrome::mojom::SafeBrowsingUrlChecker implementation.
79 void CheckUrl(const GURL& url, CheckUrlCallback callback) override {
80 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
81
82 DVLOG(1) << "SafeBrowsingUrlCheckerImpl checks URL: " << url;
vakh (use Gerrit instead) 2017/05/31 23:53:09 Just for better clarity, could you change this to
yzshen1 2017/06/01 17:45:04 Do you mean DLOG(INFO)? DVLOG are always logged at
83 urls_.push_back(url);
84 callbacks_.push_back(std::move(callback));
85
86 ProcessUrls();
87 }
88
89 private:
90 // SafeBrowsingDatabaseManager::Client implementation:
91 void OnCheckBrowseUrlResult(const GURL& url,
92 SBThreatType threat_type,
93 const ThreatMetadata& metadata) override {
94 DCHECK_EQ(STATE_CHECKING_URL, state_);
95 DCHECK_LT(next_index_, urls_.size());
96 DCHECK_EQ(urls_[next_index_], url);
97
98 timer_.Stop();
99 if (threat_type == SB_THREAT_TYPE_SAFE) {
100 state_ = STATE_NONE;
101 std::move(callbacks_[next_index_]).Run(true);
102 next_index_++;
103 ProcessUrls();
104 return;
105 }
106
107 if (load_flags_ & net::LOAD_PREFETCH) {
108 BlockAndProcessUrls();
109 return;
110 }
111
112 security_interstitials::UnsafeResource resource;
vakh (use Gerrit instead) 2017/05/31 23:53:09 The code duplication here makes me slightly nervou
yzshen1 2017/06/01 17:45:04 Yeah, I would like to find ways to tackle the dupl
113 resource.url = url;
114 resource.original_url = urls_[0];
115 if (urls_.size() > 1)
116 resource.redirect_urls =
117 std::vector<GURL>(urls_.begin() + 1, urls_.end());
118 resource.is_subresource = true;
119 resource.is_subframe = false;
120 resource.threat_type = threat_type;
121 resource.threat_metadata = metadata;
122 resource.callback =
123 base::Bind(&SafeBrowsingUrlCheckerImpl::OnBlockingPageComplete,
124 weak_factory_.GetWeakPtr());
125 resource.callback_thread = content::BrowserThread::GetTaskRunnerForThread(
126 content::BrowserThread::IO);
127 resource.web_contents_getter =
128 base::Bind(&GetWebContentsFromID, render_process_id_, render_frame_id_);
129 resource.threat_source = database_manager_->GetThreatSource();
130
131 state_ = STATE_DISPLAYING_BLOCKING_PAGE;
132
133 content::BrowserThread::PostTask(
134 content::BrowserThread::UI, FROM_HERE,
135 base::Bind(&SafeBrowsingUrlCheckerImpl::StartDisplayingBlockingPage,
136 weak_factory_.GetWeakPtr(), ui_manager_, resource));
137 }
138
139 static void StartDisplayingBlockingPage(
140 const base::WeakPtr<SafeBrowsingUrlCheckerImpl>& checker,
141 scoped_refptr<BaseUIManager> ui_manager,
142 const security_interstitials::UnsafeResource& resource) {
143 content::WebContents* web_contents = resource.web_contents_getter.Run();
144 if (web_contents) {
145 prerender::PrerenderContents* prerender_contents =
146 prerender::PrerenderContents::FromWebContents(web_contents);
147 if (prerender_contents) {
148 prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
149 } else {
150 ui_manager->DisplayBlockingPage(resource);
151 return;
152 }
153 }
154
155 // Tab is gone or it's being prerendered.
156 content::BrowserThread::PostTask(
157 content::BrowserThread::IO, FROM_HERE,
158 base::BindOnce(&SafeBrowsingUrlCheckerImpl::BlockAndProcessUrls,
159 checker));
160 }
161
162 void OnCheckUrlTimeout() {
163 database_manager_->CancelCheck(this);
164
165 OnCheckBrowseUrlResult(urls_[next_index_],
166 safe_browsing::SB_THREAT_TYPE_SAFE,
167 ThreatMetadata());
168 }
169
170 void ProcessUrls() {
171 DCHECK_NE(STATE_BLOCKED, state_);
172
173 if (state_ == STATE_CHECKING_URL ||
174 state_ == STATE_DISPLAYING_BLOCKING_PAGE) {
175 return;
176 }
177
178 while (next_index_ < urls_.size()) {
179 DCHECK_EQ(STATE_NONE, state_);
180 // TODO(yzshen): Consider moving CanCheckResourceType() to the renderer
vakh (use Gerrit instead) 2017/05/31 23:53:09 Optional: Since you're the expert here and already
yzshen1 2017/06/01 17:45:04 Done.
181 // side. That would save some IPCs.
182 if (!database_manager_->CanCheckResourceType(resource_type_) ||
183 database_manager_->CheckBrowseUrl(urls_[next_index_], this)) {
184 std::move(callbacks_[next_index_]).Run(true);
185 next_index_++;
186 continue;
187 }
188
189 state_ = STATE_CHECKING_URL;
190 // Start a timer to abort the check if it takes too long.
191 timer_.Start(FROM_HERE,
192 base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), this,
193 &SafeBrowsingUrlCheckerImpl::OnCheckUrlTimeout);
194
195 break;
196 }
197 }
198
199 void BlockAndProcessUrls() {
200 DVLOG(1) << "SafeBrowsingUrlCheckerImpl blocks URL: " << urls_[next_index_];
201 state_ = STATE_BLOCKED;
202
203 // If user decided to not proceed through a warning, mark all the remaining
204 // redirects as "bad".
205 for (; next_index_ < callbacks_.size(); ++next_index_)
206 std::move(callbacks_[next_index_]).Run(false);
207 }
208
209 void OnBlockingPageComplete(bool proceed) {
210 DCHECK_EQ(STATE_DISPLAYING_BLOCKING_PAGE, state_);
211
212 if (proceed) {
213 state_ = STATE_NONE;
214 std::move(callbacks_[next_index_]).Run(true);
215 next_index_++;
216 ProcessUrls();
217 } else {
218 BlockAndProcessUrls();
219 }
220 }
221
222 enum State {
223 // Haven't started checking or checking is complete.
224 STATE_NONE,
225 // We have one outstanding URL-check.
226 STATE_CHECKING_URL,
227 // We're displaying a blocking page.
228 STATE_DISPLAYING_BLOCKING_PAGE,
229 // The blocking page has returned *not* to proceed.
230 STATE_BLOCKED
231 };
232
233 const int load_flags_;
234 const content::ResourceType resource_type_;
235 const int render_process_id_;
236 const int render_frame_id_;
237 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
238 scoped_refptr<BaseUIManager> ui_manager_;
239
240 // The redirect chain for this resource, including the original URL and
241 // subsequent redirect URLs.
242 std::vector<GURL> urls_;
243 // Callbacks corresponding to |urls_| to report check results. |urls_| and
244 // |callbacks_| are always of the same size.
245 std::vector<CheckUrlCallback> callbacks_;
246 // |urls_| before |next_index_| have been checked. If |next_index_| is smaller
247 // than the size of |urls_|, the URL at |next_index_| is being processed.
248 size_t next_index_ = 0;
249
250 State state_ = STATE_NONE;
251
252 // Timer to abort the safe browsing check if it takes too long.
253 base::OneShotTimer timer_;
254
255 base::WeakPtrFactory<SafeBrowsingUrlCheckerImpl> weak_factory_;
256
257 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingUrlCheckerImpl);
258 };
259
260 } // namespace
261
262 MojoSafeBrowsingImpl::MojoSafeBrowsingImpl(
263 scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
264 scoped_refptr<SafeBrowsingUIManager> ui_manager,
265 int render_process_id)
266 : database_manager_(std::move(database_manager)),
267 ui_manager_(std::move(ui_manager)),
268 render_process_id_(render_process_id) {}
269
270 MojoSafeBrowsingImpl::~MojoSafeBrowsingImpl() {
271 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
272 }
273
274 // static
275 void MojoSafeBrowsingImpl::Create(
276 scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
277 scoped_refptr<SafeBrowsingUIManager> ui_manager,
278 int render_process_id,
279 const service_manager::BindSourceInfo& source_info,
280 chrome::mojom::SafeBrowsingRequest request) {
281 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
282 mojo::MakeStrongBinding(base::MakeUnique<MojoSafeBrowsingImpl>(
283 std::move(database_manager),
284 std::move(ui_manager), render_process_id),
285 std::move(request));
286 }
287
288 void MojoSafeBrowsingImpl::CreateCheckerAndCheck(
289 int32_t render_frame_id,
290 chrome::mojom::SafeBrowsingUrlCheckerRequest request,
291 const GURL& url,
292 int32_t load_flags,
293 content::ResourceType resource_type,
294 CreateCheckerAndCheckCallback callback) {
295 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
296 auto checker_impl = base::MakeUnique<SafeBrowsingUrlCheckerImpl>(
297 load_flags, resource_type, database_manager_, ui_manager_,
298 render_process_id_, render_frame_id);
299 checker_impl->CheckUrl(url, std::move(callback));
300 mojo::MakeStrongBinding(std::move(checker_impl), std::move(request));
301 }
302
303 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698