OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 "components/web_restrictions/content_resolver_web_restrictions_provider .h" | |
6 | |
7 #include "base/android/jni_string.h" | |
8 #include "base/android/scoped_java_ref.h" | |
9 #include "base/bind.h" | |
10 #include "base/location.h" | |
11 #include "base/thread_task_runner_handle.h" | |
12 #include "content/public/browser/browser_thread.h" | |
13 #include "jni/ContentResolverWebRestrictionsProvider_jni.h" | |
14 | |
15 namespace web_restrictions { | |
16 | |
17 namespace { | |
18 | |
19 const size_t kMaxCacheSize = 100; | |
20 | |
21 void AsyncShouldProceed(const GURL& url, | |
22 jlong callback, | |
23 const base::android::JavaRef<jobject>& java_provider) { | |
24 JNIEnv* env = base::android::AttachCurrentThread(); | |
25 Java_ContentResolverWebRestrictionsProvider_shouldProceed( | |
26 env, java_provider.obj(), callback, | |
27 base::android::ConvertUTF8ToJavaString(env, url.spec()).obj()); | |
28 } | |
29 | |
30 void AsyncRequestPermission( | |
31 const GURL& url, | |
32 jlong callback, | |
33 const base::android::JavaRef<jobject>& java_provider) { | |
34 JNIEnv* env = base::android::AttachCurrentThread(); | |
35 Java_ContentResolverWebRestrictionsProvider_requestPermission( | |
36 env, java_provider.obj(), callback, | |
37 base::android::ConvertUTF8ToJavaString(env, url.spec()).obj()); | |
38 } | |
39 | |
40 bool AsyncCheckSupportsRequest( | |
41 const base::android::JavaRef<jobject>& java_provider) { | |
42 JNIEnv* env = base::android::AttachCurrentThread(); | |
43 return Java_ContentResolverWebRestrictionsProvider_supportsRequest( | |
44 env, java_provider.obj()); | |
45 } | |
46 | |
47 } // namespace | |
48 | |
49 // A wrapper to the callback class to facilitate getting a callback from java | |
50 // into C++. Objects of this class delete itself only when they are called back | |
51 // so we must ensure that happens even for error cases. | |
52 class SelfDeletingCallback { | |
53 public: | |
54 SelfDeletingCallback( | |
55 const GURL& url, | |
56 const base::Callback<void(bool)>& callback, | |
57 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | |
58 const std::string& provider_authority, | |
59 ContentResolverWebRestrictionsProvider* provider); | |
60 void RequestSuccess(bool request_success); | |
61 void ShouldProceed(bool should_proceed, std::string error_page); | |
62 | |
63 private: | |
64 // Only the callback can delete itself. We must ensure it is indeed | |
65 // called back. | |
66 ~SelfDeletingCallback() {} | |
67 | |
68 GURL url_; | |
69 base::Callback<void(bool)> callback_; | |
70 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
71 std::string provider_authority_; | |
72 ContentResolverWebRestrictionsProvider* provider_; | |
73 | |
74 DISALLOW_COPY_AND_ASSIGN(SelfDeletingCallback); | |
75 }; | |
76 | |
77 SelfDeletingCallback::SelfDeletingCallback( | |
78 const GURL& url, | |
79 const base::Callback<void(bool)>& callback, | |
80 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | |
81 const std::string& provider_authority, | |
82 ContentResolverWebRestrictionsProvider* provider) | |
83 : url_(url), | |
84 callback_(callback), | |
85 task_runner_(task_runner), | |
86 provider_authority_(provider_authority), | |
87 provider_(provider) {} | |
88 | |
89 void SelfDeletingCallback::ShouldProceed(bool should_proceed, | |
90 std::string error_page) { | |
91 task_runner_->PostTask( | |
92 FROM_HERE, | |
93 base::Bind(&ContentResolverWebRestrictionsProvider::UpdateCache, | |
94 base::Unretained(provider_), provider_authority_, url_, | |
95 should_proceed, error_page)); | |
96 task_runner_->PostTask(FROM_HERE, base::Bind(callback_, should_proceed)); | |
97 delete this; | |
98 } | |
99 | |
100 void SelfDeletingCallback::RequestSuccess(bool request_success) { | |
101 task_runner_->PostTask(FROM_HERE, base::Bind(callback_, request_success)); | |
102 delete this; | |
103 } | |
104 | |
105 // static | |
106 bool ContentResolverWebRestrictionsProvider::Register(JNIEnv* env) { | |
107 return RegisterNativesImpl(env); | |
108 } | |
109 | |
110 ContentResolverWebRestrictionsProvider::ContentResolverWebRestrictionsProvider() | |
111 : initialized_(false), supports_request_(false) { | |
112 single_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
113 base::SequencedWorkerPool* worker_pool = | |
114 content::BrowserThread::GetBlockingPool(); | |
115 background_task_runner_ = | |
116 worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( | |
117 worker_pool->GetSequenceToken(), | |
118 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | |
119 } | |
120 | |
121 ContentResolverWebRestrictionsProvider:: | |
122 ~ContentResolverWebRestrictionsProvider() { | |
123 if (java_provider_.is_null()) | |
124 return; | |
125 JNIEnv* env = base::android::AttachCurrentThread(); | |
126 Java_ContentResolverWebRestrictionsProvider_onDestroy(env, | |
127 java_provider_.obj()); | |
128 java_provider_.Reset(); | |
129 } | |
130 | |
131 void ContentResolverWebRestrictionsProvider::SetAuthority( | |
132 const std::string& content_provider_authority) { | |
133 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
134 // Destroy any existing content resolver. | |
135 JNIEnv* env = base::android::AttachCurrentThread(); | |
136 if (!java_provider_.is_null()) { | |
137 Java_ContentResolverWebRestrictionsProvider_onDestroy(env, | |
138 java_provider_.obj()); | |
139 java_provider_.Reset(); | |
140 } | |
141 ClearCache(); | |
142 provider_authority_ = content_provider_authority; | |
143 | |
144 // Initialize the content resolver. | |
145 initialized_ = !content_provider_authority.empty(); | |
146 if (!initialized_) | |
147 return; | |
148 java_provider_.Reset(Java_ContentResolverWebRestrictionsProvider_create( | |
149 env, | |
150 base::android::ConvertUTF8ToJavaString(env, content_provider_authority) | |
151 .obj(), | |
152 reinterpret_cast<jlong>(this))); | |
153 supports_request_ = false; | |
154 base::PostTaskAndReplyWithResult( | |
155 content::BrowserThread::GetBlockingPool(), FROM_HERE, | |
156 base::Bind(&AsyncCheckSupportsRequest, java_provider_), | |
157 base::Bind(&ContentResolverWebRestrictionsProvider::RequestSupportKnown, | |
158 base::Unretained(this), provider_authority_)); | |
159 } | |
160 | |
161 UrlAccess ContentResolverWebRestrictionsProvider::ShouldProceed( | |
162 bool is_main_frame, | |
163 const GURL& url, | |
164 const base::Callback<void(bool)>& callback) { | |
165 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
166 if (!initialized_) | |
167 return ALLOW; | |
168 auto iter = url_access_cache_.find(url); | |
169 if (iter != url_access_cache_.end()) { | |
170 RecordURLAccess(url); | |
171 return iter->second ? ALLOW : DISALLOW; | |
172 } | |
173 SelfDeletingCallback* wrapped_callback = new SelfDeletingCallback( | |
174 url, callback, single_thread_task_runner_, provider_authority_, this); | |
175 background_task_runner_->PostTask( | |
176 FROM_HERE, | |
177 base::Bind(&AsyncShouldProceed, url, | |
178 reinterpret_cast<jlong>(wrapped_callback), java_provider_)); | |
179 return PENDING; | |
180 } | |
181 | |
182 bool ContentResolverWebRestrictionsProvider::SupportsRequest() const { | |
183 return initialized_ && supports_request_; | |
184 } | |
185 | |
186 bool ContentResolverWebRestrictionsProvider::GetErrorHtml( | |
187 const GURL& url, | |
188 std::string* error_page) const { | |
189 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
190 if (!initialized_) | |
191 return false; | |
192 auto iter = error_page_cache_.find(url); | |
193 if (iter == error_page_cache_.end()) | |
194 return false; | |
195 *error_page = iter->second; | |
196 return true; | |
197 } | |
198 | |
199 void ContentResolverWebRestrictionsProvider::RequestPermission( | |
200 const GURL& url, | |
201 const base::Callback<void(bool)>& request_success) { | |
202 if (!initialized_) { | |
203 request_success.Run(false); | |
204 return; | |
205 } | |
206 SelfDeletingCallback* wrapped_callback = | |
207 new SelfDeletingCallback(url, request_success, single_thread_task_runner_, | |
208 provider_authority_, this); | |
209 background_task_runner_->PostTask( | |
210 FROM_HERE, | |
211 base::Bind(&AsyncRequestPermission, url, | |
212 reinterpret_cast<jlong>(wrapped_callback), java_provider_)); | |
213 } | |
214 | |
215 void ContentResolverWebRestrictionsProvider::OnWebRestrictionsChanged() { | |
216 single_thread_task_runner_->PostTask( | |
217 FROM_HERE, base::Bind(&ContentResolverWebRestrictionsProvider::ClearCache, | |
218 base::Unretained(this))); | |
219 } | |
220 | |
221 void ContentResolverWebRestrictionsProvider::RecordURLAccess(const GURL& url) { | |
222 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
223 // Move the URL to the front of the cache. | |
224 recent_urls_.remove(url); | |
225 recent_urls_.push_front(url); | |
226 } | |
227 | |
228 void ContentResolverWebRestrictionsProvider::UpdateCache( | |
229 std::string provider_authority, | |
230 GURL url, | |
231 bool should_proceed, | |
232 std::string error_page) { | |
233 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
234 if (provider_authority != provider_authority_) | |
Bernhard Bauer
2016/02/04 11:13:53
You could add a comment about why we do this.
knn
2016/02/04 13:09:27
Feels a bit verbose to me but, Done.
| |
235 return; | |
236 RecordURLAccess(url); | |
237 if (recent_urls_.size() >= kMaxCacheSize) { | |
238 url_access_cache_.erase(recent_urls_.back()); | |
239 error_page_cache_.erase(recent_urls_.back()); | |
240 recent_urls_.pop_back(); | |
241 } | |
242 url_access_cache_[url] = should_proceed; | |
243 if (!error_page.empty()) { | |
244 error_page_cache_[url] = error_page; | |
245 } else { | |
246 error_page_cache_.erase(url); | |
247 } | |
248 } | |
249 | |
250 void ContentResolverWebRestrictionsProvider::RequestSupportKnown( | |
251 std::string provider_authority, | |
252 bool supports_request) { | |
253 // |supports_request_| is initialized to false. | |
254 DCHECK(!supports_request_); | |
255 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
256 if (provider_authority != provider_authority_) | |
257 return; | |
258 supports_request_ = supports_request; | |
259 } | |
260 | |
261 void ContentResolverWebRestrictionsProvider::ClearCache() { | |
262 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
263 error_page_cache_.clear(); | |
264 url_access_cache_.clear(); | |
265 recent_urls_.clear(); | |
266 } | |
267 | |
268 void ShouldProceed(JNIEnv* env, | |
269 const base::android::JavaParamRef<jclass>& clazz, | |
270 jlong callback_ptr, | |
271 jboolean should_proceed, | |
272 const base::android::JavaParamRef<jstring>& j_error_page) { | |
273 SelfDeletingCallback* callback = | |
274 reinterpret_cast<SelfDeletingCallback*>(callback_ptr); | |
275 std::string error_page; | |
276 if (!j_error_page.is_null()) | |
277 error_page = base::android::ConvertJavaStringToUTF8(j_error_page); | |
278 callback->ShouldProceed(should_proceed, error_page); | |
279 } | |
280 | |
281 void RequestSuccess(JNIEnv* env, | |
282 const base::android::JavaParamRef<jclass>& clazz, | |
283 jlong callback_ptr, | |
284 jboolean request_success) { | |
285 SelfDeletingCallback* callback = | |
286 reinterpret_cast<SelfDeletingCallback*>(callback_ptr); | |
287 callback->RequestSuccess(request_success); | |
288 } | |
289 | |
290 void NotifyWebRestrictionsChanged( | |
291 JNIEnv* env, | |
292 const base::android::JavaParamRef<jclass>& clazz, | |
293 jlong provider_ptr) { | |
294 ContentResolverWebRestrictionsProvider* provider = | |
295 reinterpret_cast<ContentResolverWebRestrictionsProvider*>(provider_ptr); | |
296 // TODO(knn): Also reload existing interstitials/error pages. | |
297 provider->OnWebRestrictionsChanged(); | |
298 } | |
299 | |
300 } // namespace web_restrictions | |
OLD | NEW |