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(const GURL& url, | |
55 const base::Callback<void(bool)>& callback, | |
56 const scoped_refptr<base::TaskRunner>& callback_runner, | |
57 ContentResolverWebRestrictionsProvider* provider); | |
58 void RequestSuccess(bool request_success); | |
59 void ShouldProceed(bool should_proceed, | |
60 const base::android::JavaRef<jstring>& 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::TaskRunner> callback_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::TaskRunner>& callback_runner, | |
Bernhard Bauer
2016/02/03 16:15:42
If the contract of ContentResolverWebRestrictionsP
knn
2016/02/03 17:15:09
Done.
| |
79 ContentResolverWebRestrictionsProvider* provider) | |
80 : url_(url), | |
81 callback_(callback), | |
82 callback_runner_(callback_runner), | |
83 provider_(provider) {} | |
84 | |
85 void SelfDeletingCallback::ShouldProceed( | |
86 bool should_proceed, | |
87 const base::android::JavaRef<jstring>& j_error_page) { | |
88 std::string* error_page = nullptr; | |
89 if (!j_error_page.is_null()) { | |
90 // Will be owned by the callback to which it is passed. | |
91 error_page = new std::string(); | |
92 *error_page = base::android::ConvertJavaStringToUTF8(j_error_page); | |
93 } | |
94 content::BrowserThread::PostTask( | |
95 content::BrowserThread::IO, FROM_HERE, | |
96 base::Bind(&ContentResolverWebRestrictionsProvider::UpdateCache, | |
97 base::Unretained(provider_), url_, should_proceed, | |
aberent
2016/02/03 16:22:07
Is |provider_| still guaranteed to still exist? Do
knn
2016/02/03 16:26:07
Yes, it is like a singleton should only be reset w
aberent
2016/02/03 17:56:15
I am confused. It is the lifetime of the C++ Conte
knn
2016/02/03 18:51:13
Yes, what you are saying is correct there are no *
| |
98 base::Owned(error_page))); | |
Bernhard Bauer
2016/02/03 16:15:42
Could we wrap this in a scoped_ptr to make sure no
knn
2016/02/03 17:15:08
Passing by value now.
| |
99 callback_runner_->PostTask(FROM_HERE, base::Bind(callback_, should_proceed)); | |
100 delete this; | |
101 } | |
102 | |
103 void SelfDeletingCallback::RequestSuccess(bool request_success) { | |
104 callback_runner_->PostTask(FROM_HERE, base::Bind(callback_, request_success)); | |
105 delete this; | |
106 } | |
107 | |
108 // static | |
109 bool ContentResolverWebRestrictionsProvider::Register(JNIEnv* env) { | |
110 return RegisterNativesImpl(env); | |
111 } | |
112 | |
113 ContentResolverWebRestrictionsProvider::ContentResolverWebRestrictionsProvider() | |
114 : initialized_(false), supports_request_(false) { | |
115 base::SequencedWorkerPool* worker_pool = | |
116 content::BrowserThread::GetBlockingPool(); | |
117 background_task_runner_ = | |
118 worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( | |
119 worker_pool->GetSequenceToken(), | |
120 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | |
121 } | |
122 | |
123 ContentResolverWebRestrictionsProvider:: | |
124 ~ContentResolverWebRestrictionsProvider() { | |
125 if (java_provider_.is_null()) | |
126 return; | |
127 JNIEnv* env = base::android::AttachCurrentThread(); | |
128 Java_ContentResolverWebRestrictionsProvider_onDestroy(env, | |
129 java_provider_.obj()); | |
130 } | |
131 | |
132 void ContentResolverWebRestrictionsProvider::SetAuthority( | |
133 const std::string& content_provider_authority) { | |
134 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
135 // Destroy any existing content resolver. | |
136 JNIEnv* env = base::android::AttachCurrentThread(); | |
137 if (!java_provider_.is_null()) { | |
138 Java_ContentResolverWebRestrictionsProvider_onDestroy(env, | |
139 java_provider_.obj()); | |
140 java_provider_.Reset(); | |
141 } | |
142 ClearCache(); | |
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))); | |
159 } | |
160 | |
161 UrlAccess ContentResolverWebRestrictionsProvider::ShouldProceed( | |
162 bool is_main_frame, | |
163 const GURL& url, | |
164 const base::Callback<void(bool)>& callback) { | |
165 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
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 scoped_refptr<base::SingleThreadTaskRunner> callback_runner = | |
174 base::ThreadTaskRunnerHandle::Get(); | |
175 SelfDeletingCallback* wrapped_callback = | |
176 new SelfDeletingCallback(url, callback, callback_runner, this); | |
177 background_task_runner_->PostTask( | |
178 FROM_HERE, | |
179 base::Bind(&AsyncShouldProceed, url, | |
180 reinterpret_cast<jlong>(wrapped_callback), java_provider_)); | |
181 return PENDING; | |
182 } | |
183 | |
184 bool ContentResolverWebRestrictionsProvider::SupportsRequest() const { | |
185 return initialized_ && supports_request_; | |
186 } | |
187 | |
188 bool ContentResolverWebRestrictionsProvider::GetErrorHtml( | |
189 const GURL& url, | |
190 std::string* error_page) const { | |
191 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
192 if (!initialized_) | |
193 return false; | |
194 auto iter = error_page_cache_.find(url); | |
195 if (iter == error_page_cache_.end()) | |
196 return false; | |
197 *error_page = iter->second; | |
198 return true; | |
199 } | |
200 | |
201 void ContentResolverWebRestrictionsProvider::RequestPermission( | |
202 const GURL& url, | |
203 const base::Callback<void(bool)>& request_success) { | |
204 if (!initialized_) { | |
205 request_success.Run(false); | |
206 return; | |
207 } | |
208 scoped_refptr<base::SingleThreadTaskRunner> callback_runner = | |
209 base::ThreadTaskRunnerHandle::Get(); | |
210 SelfDeletingCallback* wrapped_callback = | |
211 new SelfDeletingCallback(url, request_success, callback_runner, this); | |
212 background_task_runner_->PostTask( | |
213 FROM_HERE, | |
214 base::Bind(&AsyncRequestPermission, url, | |
215 reinterpret_cast<jlong>(wrapped_callback), java_provider_)); | |
216 } | |
217 | |
218 void ContentResolverWebRestrictionsProvider::ClearCache() { | |
219 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
220 error_page_cache_.clear(); | |
221 url_access_cache_.clear(); | |
222 recent_urls_.clear(); | |
223 } | |
224 | |
225 void ContentResolverWebRestrictionsProvider::RecordURLAccess(const GURL& url) { | |
226 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
227 // Move the URL to the front of the cache. | |
228 recent_urls_.remove(url); | |
229 recent_urls_.push_front(url); | |
230 } | |
231 | |
232 void ContentResolverWebRestrictionsProvider::UpdateCache( | |
233 const GURL& url, | |
234 bool should_proceed, | |
235 std::string* error_page /* owned by the callback */) { | |
236 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); | |
237 RecordURLAccess(url); | |
238 if (recent_urls_.size() >= kMaxCacheSize) { | |
239 url_access_cache_.erase(recent_urls_.back()); | |
240 error_page_cache_.erase(recent_urls_.back()); | |
241 recent_urls_.pop_back(); | |
242 } | |
243 url_access_cache_[url] = should_proceed; | |
244 if (error_page) { | |
245 error_page_cache_[url] = *error_page; | |
Bernhard Bauer
2016/02/03 16:15:42
Hm... We pass this as a pointer to this method to
knn
2016/02/03 16:23:56
I am using pointers mostly to indicate missing val
Bernhard Bauer
2016/02/03 16:26:49
Yeah, I don't think anyone would legitimately want
knn
2016/02/03 17:15:09
Acknowledged.
| |
246 } else { | |
247 error_page_cache_.erase(url); | |
248 } | |
249 } | |
250 | |
251 void ContentResolverWebRestrictionsProvider::RequestSupportKnown( | |
252 bool supports_request) { | |
253 // |supports_request_| is initialized to false. | |
254 DCHECK(!supports_request_); | |
255 supports_request_ = supports_request; | |
256 } | |
257 | |
258 void ShouldProceed(JNIEnv* env, | |
259 const base::android::JavaParamRef<jclass>& clazz, | |
260 jlong callback_ptr, | |
261 jboolean should_proceed, | |
262 const base::android::JavaParamRef<jstring>& error_page) { | |
263 SelfDeletingCallback* callback = | |
264 reinterpret_cast<SelfDeletingCallback*>(callback_ptr); | |
265 callback->ShouldProceed(should_proceed, error_page); | |
266 } | |
267 | |
268 void RequestSuccess(JNIEnv* env, | |
269 const base::android::JavaParamRef<jclass>& clazz, | |
270 jlong callback_ptr, | |
271 jboolean request_success) { | |
272 SelfDeletingCallback* callback = | |
273 reinterpret_cast<SelfDeletingCallback*>(callback_ptr); | |
274 callback->RequestSuccess(request_success); | |
275 } | |
276 | |
277 void NotifyWebRestrictionsChanged( | |
278 JNIEnv* env, | |
279 const base::android::JavaParamRef<jclass>& clazz, | |
280 jlong provider_ptr) { | |
281 ContentResolverWebRestrictionsProvider* provider = | |
282 reinterpret_cast<ContentResolverWebRestrictionsProvider*>(provider_ptr); | |
283 // TODO(knn): Also reload existing interstitials/error pages. | |
284 content::BrowserThread::PostTask( | |
285 content::BrowserThread::IO, FROM_HERE, | |
286 base::Bind(&ContentResolverWebRestrictionsProvider::ClearCache, | |
287 base::Unretained(provider))); | |
aberent
2016/02/03 16:22:07
As above; do we know that |provider| hasn't been d
| |
288 } | |
289 | |
290 } // namespace web_restrictions | |
OLD | NEW |