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 ContentResolverWebRestrictionsProvider* provider); | |
59 void RequestSuccess(bool request_success); | |
60 void ShouldProceed(bool should_proceed, std::string error_page); | |
61 | |
62 private: | |
63 // Only the callback can delete itself. We must ensure it is indeed | |
64 // called back. | |
65 ~SelfDeletingCallback() {} | |
66 | |
67 GURL url_; | |
68 base::Callback<void(bool)> callback_; | |
69 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
70 ContentResolverWebRestrictionsProvider* provider_; | |
71 | |
72 DISALLOW_COPY_AND_ASSIGN(SelfDeletingCallback); | |
73 }; | |
74 | |
75 SelfDeletingCallback::SelfDeletingCallback( | |
76 const GURL& url, | |
77 const base::Callback<void(bool)>& callback, | |
78 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | |
79 ContentResolverWebRestrictionsProvider* provider) | |
80 : url_(url), | |
81 callback_(callback), | |
82 task_runner_(task_runner), | |
83 provider_(provider) {} | |
84 | |
85 void SelfDeletingCallback::ShouldProceed(bool should_proceed, | |
aberent
2016/02/03 19:26:22
Further to my previous threading comments. I think
knn
2016/02/03 21:23:21
Good catch! Fixed this now.
| |
86 std::string error_page) { | |
87 task_runner_->PostTask( | |
88 FROM_HERE, | |
89 base::Bind(&ContentResolverWebRestrictionsProvider::UpdateCache, | |
90 base::Unretained(provider_), url_, should_proceed, | |
91 error_page)); | |
aberent
2016/02/03 19:26:22
Even if we are still using the same authority when
knn
2016/02/03 21:23:21
Fixed.
| |
92 task_runner_->PostTask(FROM_HERE, base::Bind(callback_, should_proceed)); | |
aberent
2016/02/03 19:26:22
And the authority could change between the first a
knn
2016/02/03 21:23:21
So, we probably don't care about requests that wer
| |
93 delete this; | |
94 } | |
95 | |
96 void SelfDeletingCallback::RequestSuccess(bool request_success) { | |
97 task_runner_->PostTask(FROM_HERE, base::Bind(callback_, request_success)); | |
98 delete this; | |
99 } | |
100 | |
101 // static | |
102 bool ContentResolverWebRestrictionsProvider::Register(JNIEnv* env) { | |
103 return RegisterNativesImpl(env); | |
104 } | |
105 | |
106 ContentResolverWebRestrictionsProvider::ContentResolverWebRestrictionsProvider() | |
107 : initialized_(false), supports_request_(false) { | |
108 single_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
109 base::SequencedWorkerPool* worker_pool = | |
110 content::BrowserThread::GetBlockingPool(); | |
111 background_task_runner_ = | |
112 worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( | |
113 worker_pool->GetSequenceToken(), | |
114 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | |
115 } | |
116 | |
117 ContentResolverWebRestrictionsProvider:: | |
118 ~ContentResolverWebRestrictionsProvider() { | |
119 if (java_provider_.is_null()) | |
120 return; | |
121 JNIEnv* env = base::android::AttachCurrentThread(); | |
122 Java_ContentResolverWebRestrictionsProvider_onDestroy(env, | |
123 java_provider_.obj()); | |
124 } | |
125 | |
126 void ContentResolverWebRestrictionsProvider::SetAuthority( | |
127 const std::string& content_provider_authority) { | |
128 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
129 // Destroy any existing content resolver. | |
130 JNIEnv* env = base::android::AttachCurrentThread(); | |
131 if (!java_provider_.is_null()) { | |
132 Java_ContentResolverWebRestrictionsProvider_onDestroy(env, | |
133 java_provider_.obj()); | |
134 java_provider_.Reset(); | |
135 } | |
136 ClearCache(); | |
137 | |
138 // Initialize the content resolver. | |
139 initialized_ = !content_provider_authority.empty(); | |
140 if (!initialized_) | |
141 return; | |
142 java_provider_.Reset(Java_ContentResolverWebRestrictionsProvider_create( | |
143 env, | |
144 base::android::ConvertUTF8ToJavaString(env, content_provider_authority) | |
145 .obj(), | |
146 reinterpret_cast<jlong>(this))); | |
147 supports_request_ = false; | |
148 base::PostTaskAndReplyWithResult( | |
149 content::BrowserThread::GetBlockingPool(), FROM_HERE, | |
150 base::Bind(&AsyncCheckSupportsRequest, java_provider_), | |
151 base::Bind(&ContentResolverWebRestrictionsProvider::RequestSupportKnown, | |
152 base::Unretained(this))); | |
153 } | |
154 | |
155 UrlAccess ContentResolverWebRestrictionsProvider::ShouldProceed( | |
156 bool is_main_frame, | |
157 const GURL& url, | |
158 const base::Callback<void(bool)>& callback) { | |
159 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
160 if (!initialized_) | |
161 return ALLOW; | |
162 auto iter = url_access_cache_.find(url); | |
163 if (iter != url_access_cache_.end()) { | |
164 RecordURLAccess(url); | |
165 return iter->second ? ALLOW : DISALLOW; | |
166 } | |
167 SelfDeletingCallback* wrapped_callback = | |
168 new SelfDeletingCallback(url, callback, single_thread_task_runner_, this); | |
169 background_task_runner_->PostTask( | |
170 FROM_HERE, | |
171 base::Bind(&AsyncShouldProceed, url, | |
172 reinterpret_cast<jlong>(wrapped_callback), java_provider_)); | |
173 return PENDING; | |
174 } | |
175 | |
176 bool ContentResolverWebRestrictionsProvider::SupportsRequest() const { | |
177 return initialized_ && supports_request_; | |
178 } | |
179 | |
180 bool ContentResolverWebRestrictionsProvider::GetErrorHtml( | |
181 const GURL& url, | |
182 std::string* error_page) const { | |
183 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
184 if (!initialized_) | |
185 return false; | |
186 auto iter = error_page_cache_.find(url); | |
187 if (iter == error_page_cache_.end()) | |
188 return false; | |
189 *error_page = iter->second; | |
190 return true; | |
191 } | |
192 | |
193 void ContentResolverWebRestrictionsProvider::RequestPermission( | |
194 const GURL& url, | |
195 const base::Callback<void(bool)>& request_success) { | |
196 if (!initialized_) { | |
197 request_success.Run(false); | |
198 return; | |
199 } | |
200 SelfDeletingCallback* wrapped_callback = new SelfDeletingCallback( | |
201 url, request_success, single_thread_task_runner_, this); | |
202 background_task_runner_->PostTask( | |
203 FROM_HERE, | |
204 base::Bind(&AsyncRequestPermission, url, | |
205 reinterpret_cast<jlong>(wrapped_callback), java_provider_)); | |
206 } | |
207 | |
208 void ContentResolverWebRestrictionsProvider::OnWebRestrictionsChanged() { | |
209 single_thread_task_runner_->PostTask( | |
210 FROM_HERE, base::Bind(&ContentResolverWebRestrictionsProvider::ClearCache, | |
211 base::Unretained(this))); | |
212 } | |
213 | |
214 void ContentResolverWebRestrictionsProvider::RecordURLAccess(const GURL& url) { | |
215 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
216 // Move the URL to the front of the cache. | |
217 recent_urls_.remove(url); | |
218 recent_urls_.push_front(url); | |
219 } | |
220 | |
221 void ContentResolverWebRestrictionsProvider::UpdateCache( | |
222 const GURL& url, | |
223 bool should_proceed, | |
224 std::string error_page) { | |
225 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
226 RecordURLAccess(url); | |
227 if (recent_urls_.size() >= kMaxCacheSize) { | |
228 url_access_cache_.erase(recent_urls_.back()); | |
229 error_page_cache_.erase(recent_urls_.back()); | |
230 recent_urls_.pop_back(); | |
231 } | |
232 url_access_cache_[url] = should_proceed; | |
233 if (!error_page.empty()) { | |
234 error_page_cache_[url] = error_page; | |
235 } else { | |
236 error_page_cache_.erase(url); | |
237 } | |
238 } | |
239 | |
240 void ContentResolverWebRestrictionsProvider::RequestSupportKnown( | |
241 bool supports_request) { | |
242 // |supports_request_| is initialized to false. | |
243 DCHECK(!supports_request_); | |
244 supports_request_ = supports_request; | |
245 } | |
246 | |
247 void ContentResolverWebRestrictionsProvider::ClearCache() { | |
248 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
249 error_page_cache_.clear(); | |
250 url_access_cache_.clear(); | |
251 recent_urls_.clear(); | |
252 } | |
253 | |
254 void ShouldProceed(JNIEnv* env, | |
255 const base::android::JavaParamRef<jclass>& clazz, | |
256 jlong callback_ptr, | |
257 jboolean should_proceed, | |
258 const base::android::JavaParamRef<jstring>& j_error_page) { | |
259 SelfDeletingCallback* callback = | |
260 reinterpret_cast<SelfDeletingCallback*>(callback_ptr); | |
261 std::string error_page; | |
262 if (!j_error_page.is_null()) | |
263 error_page = base::android::ConvertJavaStringToUTF8(j_error_page); | |
264 callback->ShouldProceed(should_proceed, error_page); | |
265 } | |
266 | |
267 void RequestSuccess(JNIEnv* env, | |
268 const base::android::JavaParamRef<jclass>& clazz, | |
269 jlong callback_ptr, | |
270 jboolean request_success) { | |
271 SelfDeletingCallback* callback = | |
272 reinterpret_cast<SelfDeletingCallback*>(callback_ptr); | |
273 callback->RequestSuccess(request_success); | |
274 } | |
275 | |
276 void NotifyWebRestrictionsChanged( | |
277 JNIEnv* env, | |
278 const base::android::JavaParamRef<jclass>& clazz, | |
279 jlong provider_ptr) { | |
280 ContentResolverWebRestrictionsProvider* provider = | |
281 reinterpret_cast<ContentResolverWebRestrictionsProvider*>(provider_ptr); | |
282 // TODO(knn): Also reload existing interstitials/error pages. | |
283 provider->OnWebRestrictionsChanged(); | |
284 } | |
285 | |
286 } // namespace web_restrictions | |
OLD | NEW |