OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/web_restrictions/browser/web_restrictions_client.h" | 5 #include "components/web_restrictions/browser/web_restrictions_client.h" |
6 | 6 |
7 #include "base/android/jni_string.h" | 7 #include "base/android/jni_string.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/logging.h" |
10 #include "base/threading/thread_task_runner_handle.h" | 11 #include "base/threading/thread_task_runner_handle.h" |
11 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
12 #include "jni/WebRestrictionsClient_jni.h" | 13 #include "jni/WebRestrictionsClient_jni.h" |
13 | 14 |
14 using base::android::ScopedJavaGlobalRef; | 15 using base::android::ScopedJavaGlobalRef; |
15 | 16 |
16 namespace web_restrictions { | 17 namespace web_restrictions { |
17 | 18 |
18 namespace { | 19 namespace { |
19 | 20 |
20 const size_t kMaxCacheSize = 100; | 21 const size_t kMaxCacheSize = 100; |
21 | 22 |
22 bool RequestPermissionTask( | 23 bool RequestPermissionTask( |
23 const GURL& url, | 24 const std::string& url, |
24 const base::android::JavaRef<jobject>& java_provider) { | 25 const base::android::JavaRef<jobject>& java_provider) { |
25 JNIEnv* env = base::android::AttachCurrentThread(); | 26 JNIEnv* env = base::android::AttachCurrentThread(); |
26 return Java_WebRestrictionsClient_requestPermission( | 27 return Java_WebRestrictionsClient_requestPermission( |
27 env, java_provider.obj(), | 28 env, java_provider.obj(), |
28 base::android::ConvertUTF8ToJavaString(env, url.spec()).obj()); | 29 base::android::ConvertUTF8ToJavaString(env, url).obj()); |
29 } | 30 } |
30 | 31 |
31 bool CheckSupportsRequestTask( | 32 bool CheckSupportsRequestTask( |
32 const base::android::JavaRef<jobject>& java_provider) { | 33 const base::android::JavaRef<jobject>& java_provider) { |
33 JNIEnv* env = base::android::AttachCurrentThread(); | 34 JNIEnv* env = base::android::AttachCurrentThread(); |
34 return Java_WebRestrictionsClient_supportsRequest(env, java_provider.obj()); | 35 return Java_WebRestrictionsClient_supportsRequest(env, java_provider.obj()); |
35 } | 36 } |
36 | 37 |
37 } // namespace | 38 } // namespace |
38 | 39 |
39 // static | 40 // static |
40 bool WebRestrictionsClient::Register(JNIEnv* env) { | 41 bool WebRestrictionsClient::Register(JNIEnv* env) { |
41 return RegisterNativesImpl(env); | 42 return RegisterNativesImpl(env); |
42 } | 43 } |
43 | 44 |
44 WebRestrictionsClient::WebRestrictionsClient() | 45 WebRestrictionsClient::WebRestrictionsClient() |
45 : initialized_(false), supports_request_(false) { | 46 : initialized_(false), supports_request_(false) { |
46 single_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
47 base::SequencedWorkerPool* worker_pool = | 47 base::SequencedWorkerPool* worker_pool = |
48 content::BrowserThread::GetBlockingPool(); | 48 content::BrowserThread::GetBlockingPool(); |
49 background_task_runner_ = | 49 background_task_runner_ = |
50 worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( | 50 worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( |
51 worker_pool->GetSequenceToken(), | 51 worker_pool->GetSequenceToken(), |
52 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | 52 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
53 } | 53 } |
54 | 54 |
55 WebRestrictionsClient::~WebRestrictionsClient() { | 55 WebRestrictionsClient::~WebRestrictionsClient() { |
56 if (java_provider_.is_null()) | 56 if (java_provider_.is_null()) |
57 return; | 57 return; |
58 JNIEnv* env = base::android::AttachCurrentThread(); | 58 JNIEnv* env = base::android::AttachCurrentThread(); |
59 Java_WebRestrictionsClient_onDestroy(env, java_provider_.obj()); | 59 Java_WebRestrictionsClient_onDestroy(env, java_provider_.obj()); |
60 java_provider_.Reset(); | 60 java_provider_.Reset(); |
61 } | 61 } |
62 | 62 |
63 void WebRestrictionsClient::SetAuthority( | 63 void WebRestrictionsClient::SetAuthority( |
64 const std::string& content_provider_authority) { | 64 const std::string& content_provider_authority) { |
65 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 65 // This is called from the UI thread, but class members should only be |
| 66 // accessed from the IO thread. |
| 67 content::BrowserThread::PostTask( |
| 68 content::BrowserThread::IO, FROM_HERE, |
| 69 base::Bind(&WebRestrictionsClient::SetAuthorityTask, |
| 70 base::Unretained(this), content_provider_authority)); |
| 71 } |
| 72 |
| 73 void WebRestrictionsClient::SetAuthorityTask( |
| 74 const std::string& content_provider_authority) { |
| 75 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
66 // Destroy any existing content resolver. | 76 // Destroy any existing content resolver. |
67 JNIEnv* env = base::android::AttachCurrentThread(); | 77 JNIEnv* env = base::android::AttachCurrentThread(); |
68 if (!java_provider_.is_null()) { | 78 if (!java_provider_.is_null()) { |
69 Java_WebRestrictionsClient_onDestroy(env, java_provider_.obj()); | 79 Java_WebRestrictionsClient_onDestroy(env, java_provider_.obj()); |
70 java_provider_.Reset(); | 80 java_provider_.Reset(); |
71 } | 81 } |
72 ClearCache(); | 82 ClearCache(); |
73 provider_authority_ = content_provider_authority; | 83 provider_authority_ = content_provider_authority; |
74 | 84 |
75 // Initialize the content resolver. | 85 // Initialize the content resolver. |
76 initialized_ = !content_provider_authority.empty(); | 86 initialized_ = !content_provider_authority.empty(); |
77 if (!initialized_) | 87 if (!initialized_) |
78 return; | 88 return; |
79 java_provider_.Reset(Java_WebRestrictionsClient_create( | 89 java_provider_.Reset(Java_WebRestrictionsClient_create( |
80 env, | 90 env, |
81 base::android::ConvertUTF8ToJavaString(env, content_provider_authority) | 91 base::android::ConvertUTF8ToJavaString(env, content_provider_authority) |
82 .obj(), | 92 .obj(), |
83 reinterpret_cast<jlong>(this))); | 93 reinterpret_cast<jlong>(this))); |
84 supports_request_ = false; | 94 supports_request_ = false; |
85 base::PostTaskAndReplyWithResult( | 95 base::PostTaskAndReplyWithResult( |
86 content::BrowserThread::GetBlockingPool(), FROM_HERE, | 96 content::BrowserThread::GetBlockingPool(), FROM_HERE, |
87 base::Bind(&CheckSupportsRequestTask, java_provider_), | 97 base::Bind(&CheckSupportsRequestTask, java_provider_), |
88 base::Bind(&WebRestrictionsClient::RequestSupportKnown, | 98 base::Bind(&WebRestrictionsClient::RequestSupportKnown, |
89 base::Unretained(this), provider_authority_)); | 99 base::Unretained(this), provider_authority_)); |
90 } | 100 } |
91 | 101 |
92 UrlAccess WebRestrictionsClient::ShouldProceed( | 102 UrlAccess WebRestrictionsClient::ShouldProceed( |
93 bool is_main_frame, | 103 bool is_main_frame, |
94 const GURL& url, | 104 const std::string& url, |
95 const base::Callback<void(bool)>& callback) { | 105 const base::Callback<void(bool)>& callback) { |
96 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 106 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
97 if (!initialized_) | 107 if (!initialized_) |
98 return ALLOW; | 108 return ALLOW; |
99 auto iter = cache_.find(url); | 109 |
100 if (iter != cache_.end()) { | 110 std::unique_ptr<const WebRestrictionsClientResult> result = |
| 111 cache_.GetCacheEntry(url); |
| 112 if (result) { |
101 RecordURLAccess(url); | 113 RecordURLAccess(url); |
102 JNIEnv* env = base::android::AttachCurrentThread(); | 114 return result->ShouldProceed() ? ALLOW : DISALLOW; |
103 return Java_ShouldProceedResult_shouldProceed(env, iter->second.obj()) | |
104 ? ALLOW | |
105 : DISALLOW; | |
106 } | 115 } |
107 base::PostTaskAndReplyWithResult( | 116 base::PostTaskAndReplyWithResult( |
108 background_task_runner_.get(), FROM_HERE, | 117 background_task_runner_.get(), FROM_HERE, |
109 base::Bind(&WebRestrictionsClient::ShouldProceedTask, url, | 118 base::Bind(&WebRestrictionsClient::ShouldProceedTask, url, |
110 java_provider_), | 119 java_provider_), |
111 base::Bind(&WebRestrictionsClient::OnShouldProceedComplete, | 120 base::Bind(&WebRestrictionsClient::OnShouldProceedComplete, |
112 base::Unretained(this), provider_authority_, url, callback)); | 121 base::Unretained(this), provider_authority_, url, callback)); |
113 | 122 |
114 return PENDING; | 123 return PENDING; |
115 } | 124 } |
116 | 125 |
117 bool WebRestrictionsClient::SupportsRequest() const { | 126 bool WebRestrictionsClient::SupportsRequest() const { |
118 return initialized_ && supports_request_; | 127 return initialized_ && supports_request_; |
119 } | 128 } |
120 | 129 |
121 int WebRestrictionsClient::GetResultColumnCount(const GURL& url) const { | |
122 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
123 if (!initialized_) | |
124 return 0; | |
125 auto iter = cache_.find(url); | |
126 if (iter == cache_.end()) | |
127 return 0; | |
128 return Java_ShouldProceedResult_getColumnCount( | |
129 base::android::AttachCurrentThread(), iter->second.obj()); | |
130 } | |
131 | |
132 std::string WebRestrictionsClient::GetResultColumnName(const GURL& url, | |
133 int column) const { | |
134 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
135 if (!initialized_) | |
136 return std::string(); | |
137 auto iter = cache_.find(url); | |
138 if (iter == cache_.end()) | |
139 return std::string(); | |
140 | |
141 JNIEnv* env = base::android::AttachCurrentThread(); | |
142 return base::android::ConvertJavaStringToUTF8( | |
143 env, | |
144 Java_ShouldProceedResult_getColumnName(env, iter->second.obj(), column) | |
145 .obj()); | |
146 } | |
147 | |
148 int WebRestrictionsClient::GetResultIntValue(const GURL& url, | |
149 int column) const { | |
150 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
151 if (!initialized_) | |
152 return 0; | |
153 auto iter = cache_.find(url); | |
154 if (iter == cache_.end()) | |
155 return 0; | |
156 return Java_ShouldProceedResult_getInt(base::android::AttachCurrentThread(), | |
157 iter->second.obj(), column); | |
158 } | |
159 | |
160 std::string WebRestrictionsClient::GetResultStringValue(const GURL& url, | |
161 int column) const { | |
162 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
163 if (!initialized_) | |
164 return std::string(); | |
165 auto iter = cache_.find(url); | |
166 if (iter == cache_.end()) | |
167 return std::string(); | |
168 | |
169 JNIEnv* env = base::android::AttachCurrentThread(); | |
170 return base::android::ConvertJavaStringToUTF8( | |
171 env, Java_ShouldProceedResult_getString(env, iter->second.obj(), column) | |
172 .obj()); | |
173 } | |
174 | |
175 void WebRestrictionsClient::RequestPermission( | 130 void WebRestrictionsClient::RequestPermission( |
176 const GURL& url, | 131 const std::string& url, |
177 const base::Callback<void(bool)>& request_success) { | 132 const base::Callback<void(bool)>& request_success) { |
178 if (!initialized_) { | 133 if (!initialized_) { |
179 request_success.Run(false); | 134 request_success.Run(false); |
180 return; | 135 return; |
181 } | 136 } |
182 base::PostTaskAndReplyWithResult( | 137 base::PostTaskAndReplyWithResult( |
183 background_task_runner_.get(), FROM_HERE, | 138 background_task_runner_.get(), FROM_HERE, |
184 base::Bind(&RequestPermissionTask, url, java_provider_), request_success); | 139 base::Bind(&RequestPermissionTask, url, java_provider_), request_success); |
185 } | 140 } |
186 | 141 |
187 void WebRestrictionsClient::OnWebRestrictionsChanged() { | 142 void WebRestrictionsClient::OnWebRestrictionsChanged( |
188 single_thread_task_runner_->PostTask( | 143 JNIEnv* env, |
189 FROM_HERE, | 144 const base::android::JavaParamRef<jobject>& obj) { |
| 145 content::BrowserThread::PostTask( |
| 146 content::BrowserThread::IO, FROM_HERE, |
190 base::Bind(&WebRestrictionsClient::ClearCache, base::Unretained(this))); | 147 base::Bind(&WebRestrictionsClient::ClearCache, base::Unretained(this))); |
191 } | 148 } |
192 | 149 |
193 void WebRestrictionsClient::RecordURLAccess(const GURL& url) { | 150 void WebRestrictionsClient::RecordURLAccess(const std::string& url) { |
194 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 151 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
195 // Move the URL to the front of the cache. | 152 // Move the URL to the front of the cache. |
196 recent_urls_.remove(url); | 153 recent_urls_.remove(url); |
197 recent_urls_.push_front(url); | 154 recent_urls_.push_front(url); |
198 } | 155 } |
199 | 156 |
200 void WebRestrictionsClient::UpdateCache(std::string provider_authority, | 157 void WebRestrictionsClient::UpdateCache(const std::string& provider_authority, |
201 GURL url, | 158 const std::string& url, |
202 ScopedJavaGlobalRef<jobject> result) { | 159 ScopedJavaGlobalRef<jobject> result) { |
203 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 160 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
204 // If the webrestrictions provider changed when the old one was being queried, | 161 // If the webrestrictions provider changed when the old one was being queried, |
205 // do not update the cache for the new provider. | 162 // do not update the cache for the new provider. |
206 if (provider_authority != provider_authority_) | 163 if (provider_authority != provider_authority_) |
207 return; | 164 return; |
208 RecordURLAccess(url); | 165 RecordURLAccess(url); |
209 if (recent_urls_.size() >= kMaxCacheSize) { | 166 if (recent_urls_.size() >= kMaxCacheSize) { |
210 cache_.erase(recent_urls_.back()); | 167 cache_.RemoveCacheEntry(recent_urls_.back()); |
211 recent_urls_.pop_back(); | 168 recent_urls_.pop_back(); |
212 } | 169 } |
213 cache_[url] = result; | 170 cache_.SetCacheEntry(url, WebRestrictionsClientResult(result)); |
214 } | 171 } |
215 | 172 |
216 void WebRestrictionsClient::RequestSupportKnown(std::string provider_authority, | 173 void WebRestrictionsClient::RequestSupportKnown( |
217 bool supports_request) { | 174 const std::string& provider_authority, |
| 175 bool supports_request) { |
218 // |supports_request_| is initialized to false. | 176 // |supports_request_| is initialized to false. |
219 DCHECK(!supports_request_); | 177 DCHECK(!supports_request_); |
220 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 178 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
221 // If the webrestrictions provider changed when the old one was being queried, | 179 // If the webrestrictions provider changed when the old one was being queried, |
222 // ignore the result. | 180 // ignore the result. |
223 if (provider_authority != provider_authority_) | 181 if (provider_authority != provider_authority_) |
224 return; | 182 return; |
225 supports_request_ = supports_request; | 183 supports_request_ = supports_request; |
226 } | 184 } |
227 | 185 |
228 void WebRestrictionsClient::OnShouldProceedComplete( | 186 void WebRestrictionsClient::OnShouldProceedComplete( |
229 std::string provider_authority, | 187 std::string provider_authority, |
230 const GURL& url, | 188 const std::string& url, |
231 const base::Callback<void(bool)>& callback, | 189 const base::Callback<void(bool)>& callback, |
232 const ScopedJavaGlobalRef<jobject>& result) { | 190 const ScopedJavaGlobalRef<jobject>& result) { |
233 UpdateCache(provider_authority, url, result); | 191 UpdateCache(provider_authority, url, result); |
234 JNIEnv* env = base::android::AttachCurrentThread(); | 192 callback.Run(cache_.GetCacheEntry(url)->ShouldProceed()); |
235 callback.Run(Java_ShouldProceedResult_shouldProceed(env, result.obj())); | |
236 } | 193 } |
237 | 194 |
238 void WebRestrictionsClient::ClearCache() { | 195 void WebRestrictionsClient::ClearCache() { |
239 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 196 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
240 cache_.clear(); | 197 cache_.Clear(); |
241 recent_urls_.clear(); | 198 recent_urls_.clear(); |
242 } | 199 } |
243 | 200 |
| 201 std::unique_ptr<WebRestrictionsClientResult> |
| 202 WebRestrictionsClient::GetCachedWebRestrictionsResult(const std::string& url) { |
| 203 return cache_.GetCacheEntry(url); |
| 204 } |
| 205 |
244 // static | 206 // static |
245 ScopedJavaGlobalRef<jobject> WebRestrictionsClient::ShouldProceedTask( | 207 ScopedJavaGlobalRef<jobject> WebRestrictionsClient::ShouldProceedTask( |
246 const GURL& url, | 208 const std::string& url, |
247 const base::android::JavaRef<jobject>& java_provider) { | 209 const base::android::JavaRef<jobject>& java_provider) { |
248 JNIEnv* env = base::android::AttachCurrentThread(); | 210 JNIEnv* env = base::android::AttachCurrentThread(); |
249 base::android::ScopedJavaGlobalRef<jobject> result( | 211 base::android::ScopedJavaGlobalRef<jobject> result( |
250 Java_WebRestrictionsClient_shouldProceed( | 212 Java_WebRestrictionsClient_shouldProceed( |
251 env, java_provider.obj(), | 213 env, java_provider.obj(), |
252 base::android::ConvertUTF8ToJavaString(env, url.spec()).obj())); | 214 base::android::ConvertUTF8ToJavaString(env, url).obj())); |
253 return result; | 215 return result; |
254 } | 216 } |
255 | 217 |
256 void NotifyWebRestrictionsChanged( | 218 std::unique_ptr<WebRestrictionsClientResult> |
257 JNIEnv* env, | 219 WebRestrictionsClient::Cache::GetCacheEntry(const std::string& url) { |
258 const base::android::JavaParamRef<jobject>& clazz, | 220 base::AutoLock lock(lock_); |
259 jlong provider_ptr) { | 221 auto iter = cache_data_.find(url); |
260 WebRestrictionsClient* provider = | 222 if (iter == cache_data_.end()) |
261 reinterpret_cast<WebRestrictionsClient*>(provider_ptr); | 223 return nullptr; |
262 // TODO(knn): Also reload existing interstitials/error pages. | 224 // This has to be thread-safe, so copy the data. |
263 provider->OnWebRestrictionsChanged(); | 225 return std::unique_ptr<WebRestrictionsClientResult>( |
| 226 new WebRestrictionsClientResult(iter->second)); |
| 227 } |
| 228 |
| 229 void WebRestrictionsClient::Cache::SetCacheEntry( |
| 230 const std::string& url, |
| 231 const WebRestrictionsClientResult& entry) { |
| 232 base::AutoLock lock(lock_); |
| 233 cache_data_.emplace(url, entry); |
| 234 } |
| 235 |
| 236 void WebRestrictionsClient::Cache::RemoveCacheEntry(const std::string& url) { |
| 237 base::AutoLock lock(lock_); |
| 238 cache_data_.erase(url); |
| 239 } |
| 240 |
| 241 void WebRestrictionsClient::Cache::Clear() { |
| 242 base::AutoLock lock(lock_); |
| 243 cache_data_.clear(); |
264 } | 244 } |
265 | 245 |
266 } // namespace web_restrictions | 246 } // namespace web_restrictions |
OLD | NEW |