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

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, 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/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.
Nathan Parker 2017/05/31 17:17:06 nit: Can you add a class-level or file-level comme
yzshen1 2017/05/31 23:34:44 Done.
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
vakh (use Gerrit instead) 2017/05/31 23:53:08 SafeBrowsing service also checks things that are n
yzshen1 2017/06/01 17:45:04 Done.
29 // aborted, and the URL will be treated as if it were safe.
vakh (use Gerrit instead) 2017/05/31 23:53:08 s/URL/resource
yzshen1 2017/06/01 17:45:03 Done.
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;
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;
113 resource.url = url;
114 resource.original_url = urls_[0];
115 if (urls_.size() > 1)
116 resource.redirect_urls =
Nathan Parker 2017/05/31 17:17:06 I may be forgetting a detail of the design plan, b
yzshen1 2017/05/31 23:34:43 Yes. Eventually when the network service is enable
Nathan Parker 2017/06/01 18:22:03 Thanks. I think #2 is good. I'm mostly concerned
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 if (state_ == STATE_CHECKING_URL ||
172 state_ == STATE_DISPLAYING_BLOCKING_PAGE) {
173 return;
174 }
175
176 while (next_index_ < urls_.size()) {
177 if (state_ == STATE_BLOCKED) {
178 std::move(callbacks_[next_index_]).Run(false);
Nathan Parker 2017/05/31 17:17:06 Add comment (assuming this is correct): "If user d
yzshen1 2017/05/31 23:34:44 Done.
179 next_index_++;
180 continue;
181 }
182
183 DCHECK_EQ(STATE_NONE, state_);
184 // TODO(yzshen): Consider moving CanCheckResourceType() to the renderer
185 // side. That would save some IPCs.
186 if (!database_manager_->CanCheckResourceType(resource_type_) ||
187 database_manager_->CheckBrowseUrl(urls_[next_index_], this)) {
188 std::move(callbacks_[next_index_]).Run(true);
189 next_index_++;
190 continue;
191 }
192
193 state_ = STATE_CHECKING_URL;
194 // Start a timer to abort the check if it takes too long.
195 timer_.Start(FROM_HERE,
196 base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), this,
197 &SafeBrowsingUrlCheckerImpl::OnCheckUrlTimeout);
198
199 break;
200 }
201 }
202
203 void BlockAndProcessUrls() {
204 DVLOG(1) << "SafeBrowsingUrlCheckerImpl blocks URL: " << urls_[next_index_];
205 state_ = STATE_BLOCKED;
206 ProcessUrls();
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_;
Nathan Parker 2017/05/31 17:17:06 Q: Are the callbacks different for each url? It s
yzshen1 2017/05/31 23:34:44 Each mojo call has a separate base::OnceCallback i
243 std::vector<CheckUrlCallback> callbacks_;
244 size_t next_index_ = 0;
Nathan Parker 2017/05/31 17:17:06 Nit: add comment about what next_index refers to.
yzshen1 2017/05/31 23:34:44 Updated with comment. Thanks!
245
246 State state_ = STATE_NONE;
247
248 // Timer to abort the safe browsing check if it takes too long.
249 base::OneShotTimer timer_;
250
251 base::WeakPtrFactory<SafeBrowsingUrlCheckerImpl> weak_factory_;
252
253 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingUrlCheckerImpl);
254 };
255
256 } // namespace
257
258 SafeBrowsingImpl::SafeBrowsingImpl(
259 scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
260 scoped_refptr<SafeBrowsingUIManager> ui_manager,
261 int render_process_id)
262 : database_manager_(std::move(database_manager)),
263 ui_manager_(std::move(ui_manager)),
264 render_process_id_(render_process_id) {}
265
266 SafeBrowsingImpl::~SafeBrowsingImpl() {
267 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
268 }
269
270 // static
271 void SafeBrowsingImpl::Create(
272 scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
273 scoped_refptr<SafeBrowsingUIManager> ui_manager,
274 int render_process_id,
275 const service_manager::BindSourceInfo& source_info,
276 chrome::mojom::SafeBrowsingRequest request) {
277 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
278 mojo::MakeStrongBinding(base::MakeUnique<SafeBrowsingImpl>(
279 std::move(database_manager),
280 std::move(ui_manager), render_process_id),
281 std::move(request));
282 }
283
284 void SafeBrowsingImpl::CreateCheckerAndCheck(
285 int32_t render_frame_id,
286 chrome::mojom::SafeBrowsingUrlCheckerRequest request,
287 const GURL& url,
288 int32_t load_flags,
289 content::ResourceType resource_type,
290 CreateCheckerAndCheckCallback callback) {
291 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
292 auto checker_impl = base::MakeUnique<SafeBrowsingUrlCheckerImpl>(
293 load_flags, resource_type, database_manager_, ui_manager_,
294 render_process_id_, render_frame_id);
295 checker_impl->CheckUrl(url, std::move(callback));
296 mojo::MakeStrongBinding(std::move(checker_impl), std::move(request));
297 }
298
299 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698