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

Side by Side Diff: chrome/browser/safe_browsing/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 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/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 callbacks_[i].Run(false);
76 }
77
78 // chrome::mojom::SafeBrowsingUrlChecker implementation.
79 void CheckUrl(const GURL& url, const CheckUrlCallback& callback) override {
80 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
81
82 DVLOG(1) << "SafeBrowsingUrlCheckerImpl checks URL: " << url;
83 urls_.push_back(url);
84 callbacks_.push_back(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 callbacks_[next_index_].Run(true);
102 callbacks_[next_index_].Reset();
kinuko 2017/05/29 13:36:50 Can we use OnceCallback here?
yzshen1 2017/05/31 00:30:01 Done. I split this mojom into a separate GN target
103 next_index_++;
104 ProcessUrls();
105 return;
106 }
107
108 if (load_flags_ & net::LOAD_PREFETCH) {
109 BlockAndProcessUrls();
110 return;
111 }
112
113 security_interstitials::UnsafeResource resource;
114 resource.url = url;
115 resource.original_url = urls_[0];
116 if (urls_.size() > 1)
117 resource.redirect_urls =
118 std::vector<GURL>(urls_.begin() + 1, urls_.end());
119 resource.is_subresource = true;
120 resource.is_subframe = false;
121 resource.threat_type = threat_type;
122 resource.threat_metadata = metadata;
123 resource.callback =
124 base::Bind(&SafeBrowsingUrlCheckerImpl::OnBlockingPageComplete,
125 weak_factory_.GetWeakPtr());
126 resource.callback_thread = content::BrowserThread::GetTaskRunnerForThread(
127 content::BrowserThread::IO);
128 resource.web_contents_getter =
129 base::Bind(&GetWebContentsFromID, render_process_id_, render_frame_id_);
130 resource.threat_source = database_manager_->GetThreatSource();
131
132 state_ = STATE_DISPLAYING_BLOCKING_PAGE;
133
134 content::BrowserThread::PostTask(
135 content::BrowserThread::UI, FROM_HERE,
136 base::Bind(&SafeBrowsingUrlCheckerImpl::StartDisplayingBlockingPage,
137 weak_factory_.GetWeakPtr(), ui_manager_, resource));
138 }
139
140 static void StartDisplayingBlockingPage(
141 const base::WeakPtr<SafeBrowsingUrlCheckerImpl>& checker,
142 scoped_refptr<BaseUIManager> ui_manager,
143 const security_interstitials::UnsafeResource& resource) {
144 content::WebContents* web_contents = resource.web_contents_getter.Run();
145 if (web_contents) {
146 prerender::PrerenderContents* prerender_contents =
147 prerender::PrerenderContents::FromWebContents(web_contents);
148 if (prerender_contents) {
149 prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
150 } else {
151 ui_manager->DisplayBlockingPage(resource);
152 return;
153 }
154 }
155
156 // Tab is gone or it's being prerendered.
157 content::BrowserThread::PostTask(
158 content::BrowserThread::IO, FROM_HERE,
159 base::BindOnce(&SafeBrowsingUrlCheckerImpl::BlockAndProcessUrls,
160 checker));
161 }
162
163 void OnCheckUrlTimeout() {
164 database_manager_->CancelCheck(this);
165
166 OnCheckBrowseUrlResult(urls_[next_index_],
167 safe_browsing::SB_THREAT_TYPE_SAFE,
168 ThreatMetadata());
169 }
170
171 void ProcessUrls() {
172 if (state_ == STATE_CHECKING_URL ||
173 state_ == STATE_DISPLAYING_BLOCKING_PAGE) {
174 return;
175 }
176
177 while (next_index_ < urls_.size()) {
178 if (state_ == STATE_BLOCKED) {
179 callbacks_[next_index_].Run(false);
180 callbacks_[next_index_].Reset();
181 next_index_++;
182 continue;
183 }
184
185 DCHECK_EQ(STATE_NONE, state_);
186 // TODO(yzshen): Consider moving CanCheckResourceType() to the renderer
187 // side. That would save some IPCs.
188 if (!database_manager_->CanCheckResourceType(resource_type_) ||
189 database_manager_->CheckBrowseUrl(urls_[next_index_], this)) {
190 callbacks_[next_index_].Run(true);
191 callbacks_[next_index_].Reset();
192 next_index_++;
193 continue;
194 }
195
196 state_ = STATE_CHECKING_URL;
197 // Start a timer to abort the check if it takes too long.
198 timer_.Start(FROM_HERE,
199 base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), this,
200 &SafeBrowsingUrlCheckerImpl::OnCheckUrlTimeout);
201
202 break;
203 }
204 }
205
206 void BlockAndProcessUrls() {
207 DVLOG(1) << "SafeBrowsingUrlCheckerImpl blocks URL: " << urls_[next_index_];
208 state_ = STATE_BLOCKED;
209 ProcessUrls();
210 }
211
212 void OnBlockingPageComplete(bool proceed) {
213 DCHECK_EQ(STATE_DISPLAYING_BLOCKING_PAGE, state_);
214
215 if (proceed) {
216 state_ = STATE_NONE;
217 callbacks_[next_index_].Run(true);
218 callbacks_[next_index_].Reset();
219 next_index_++;
220 ProcessUrls();
221 } else {
222 BlockAndProcessUrls();
223 }
224 }
225
226 enum State {
227 // Haven't started checking or checking is complete.
228 STATE_NONE,
229 // We have one outstanding URL-check.
230 STATE_CHECKING_URL,
231 // We're displaying a blocking page.
232 STATE_DISPLAYING_BLOCKING_PAGE,
233 // The blocking page has returned *not* to proceed.
234 STATE_BLOCKED
235 };
236
237 const int load_flags_;
238 const content::ResourceType resource_type_;
239 const int render_process_id_;
240 const int render_frame_id_;
241 scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
242 scoped_refptr<BaseUIManager> ui_manager_;
243
244 // The redirect chain for this resource, including the original URL and
245 // subsequent redirect URLs.
246 std::vector<GURL> urls_;
247 std::vector<CheckUrlCallback> callbacks_;
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 SafeBrowsingImpl::SafeBrowsingImpl(
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 SafeBrowsingImpl::~SafeBrowsingImpl() {
271 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
272 }
273
274 // static
275 void SafeBrowsingImpl::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<SafeBrowsingImpl>(
283 std::move(database_manager),
284 std::move(ui_manager), render_process_id),
285 std::move(request));
286 }
287
288 void SafeBrowsingImpl::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 const 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, 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