| 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, | 28 env, java_provider, |
| 28 base::android::ConvertUTF8ToJavaString(env, url.spec())); | 29 base::android::ConvertUTF8ToJavaString(env, url)); |
| 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); | 35 return Java_WebRestrictionsClient_supportsRequest(env, java_provider); |
| 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_); | 59 Java_WebRestrictionsClient_onDestroy(env, java_provider_); |
| 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_); | 79 Java_WebRestrictionsClient_onDestroy(env, java_provider_); |
| 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 reinterpret_cast<jlong>(this))); | 92 reinterpret_cast<jlong>(this))); |
| 83 supports_request_ = false; | 93 supports_request_ = false; |
| 84 base::PostTaskAndReplyWithResult( | 94 base::PostTaskAndReplyWithResult( |
| 85 content::BrowserThread::GetBlockingPool(), FROM_HERE, | 95 content::BrowserThread::GetBlockingPool(), FROM_HERE, |
| 86 base::Bind(&CheckSupportsRequestTask, java_provider_), | 96 base::Bind(&CheckSupportsRequestTask, java_provider_), |
| 87 base::Bind(&WebRestrictionsClient::RequestSupportKnown, | 97 base::Bind(&WebRestrictionsClient::RequestSupportKnown, |
| 88 base::Unretained(this), provider_authority_)); | 98 base::Unretained(this), provider_authority_)); |
| 89 } | 99 } |
| 90 | 100 |
| 91 UrlAccess WebRestrictionsClient::ShouldProceed( | 101 UrlAccess WebRestrictionsClient::ShouldProceed( |
| 92 bool is_main_frame, | 102 bool is_main_frame, |
| 93 const GURL& url, | 103 const std::string& url, |
| 94 const base::Callback<void(bool)>& callback) { | 104 const base::Callback<void(bool)>& callback) { |
| 95 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 105 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 96 if (!initialized_) | 106 if (!initialized_) |
| 97 return ALLOW; | 107 return ALLOW; |
| 98 auto iter = cache_.find(url); | 108 |
| 99 if (iter != cache_.end()) { | 109 std::unique_ptr<const WebRestrictionsClientResult> result = |
| 110 cache_.GetCacheEntry(url); |
| 111 if (result) { |
| 100 RecordURLAccess(url); | 112 RecordURLAccess(url); |
| 101 JNIEnv* env = base::android::AttachCurrentThread(); | 113 return result->ShouldProceed() ? ALLOW : DISALLOW; |
| 102 return Java_ShouldProceedResult_shouldProceed(env, iter->second) ? ALLOW | |
| 103 : DISALLOW; | |
| 104 } | 114 } |
| 105 base::PostTaskAndReplyWithResult( | 115 base::PostTaskAndReplyWithResult( |
| 106 background_task_runner_.get(), FROM_HERE, | 116 background_task_runner_.get(), FROM_HERE, |
| 107 base::Bind(&WebRestrictionsClient::ShouldProceedTask, url, | 117 base::Bind(&WebRestrictionsClient::ShouldProceedTask, url, |
| 108 java_provider_), | 118 java_provider_), |
| 109 base::Bind(&WebRestrictionsClient::OnShouldProceedComplete, | 119 base::Bind(&WebRestrictionsClient::OnShouldProceedComplete, |
| 110 base::Unretained(this), provider_authority_, url, callback)); | 120 base::Unretained(this), provider_authority_, url, callback)); |
| 111 | 121 |
| 112 return PENDING; | 122 return PENDING; |
| 113 } | 123 } |
| 114 | 124 |
| 115 bool WebRestrictionsClient::SupportsRequest() const { | 125 bool WebRestrictionsClient::SupportsRequest() const { |
| 116 return initialized_ && supports_request_; | 126 return initialized_ && supports_request_; |
| 117 } | 127 } |
| 118 | 128 |
| 119 int WebRestrictionsClient::GetResultColumnCount(const GURL& url) const { | |
| 120 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
| 121 if (!initialized_) | |
| 122 return 0; | |
| 123 auto iter = cache_.find(url); | |
| 124 if (iter == cache_.end()) | |
| 125 return 0; | |
| 126 return Java_ShouldProceedResult_getColumnCount( | |
| 127 base::android::AttachCurrentThread(), iter->second); | |
| 128 } | |
| 129 | |
| 130 std::string WebRestrictionsClient::GetResultColumnName(const GURL& url, | |
| 131 int column) const { | |
| 132 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
| 133 if (!initialized_) | |
| 134 return std::string(); | |
| 135 auto iter = cache_.find(url); | |
| 136 if (iter == cache_.end()) | |
| 137 return std::string(); | |
| 138 | |
| 139 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 140 return base::android::ConvertJavaStringToUTF8( | |
| 141 env, | |
| 142 Java_ShouldProceedResult_getColumnName(env, iter->second, column).obj()); | |
| 143 } | |
| 144 | |
| 145 int WebRestrictionsClient::GetResultIntValue(const GURL& url, | |
| 146 int column) const { | |
| 147 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
| 148 if (!initialized_) | |
| 149 return 0; | |
| 150 auto iter = cache_.find(url); | |
| 151 if (iter == cache_.end()) | |
| 152 return 0; | |
| 153 return Java_ShouldProceedResult_getInt(base::android::AttachCurrentThread(), | |
| 154 iter->second, column); | |
| 155 } | |
| 156 | |
| 157 std::string WebRestrictionsClient::GetResultStringValue(const GURL& url, | |
| 158 int column) const { | |
| 159 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | |
| 160 if (!initialized_) | |
| 161 return std::string(); | |
| 162 auto iter = cache_.find(url); | |
| 163 if (iter == cache_.end()) | |
| 164 return std::string(); | |
| 165 | |
| 166 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 167 return base::android::ConvertJavaStringToUTF8( | |
| 168 env, Java_ShouldProceedResult_getString(env, iter->second, column).obj()); | |
| 169 } | |
| 170 | |
| 171 void WebRestrictionsClient::RequestPermission( | 129 void WebRestrictionsClient::RequestPermission( |
| 172 const GURL& url, | 130 const std::string& url, |
| 173 const base::Callback<void(bool)>& request_success) { | 131 const base::Callback<void(bool)>& request_success) { |
| 174 if (!initialized_) { | 132 if (!initialized_) { |
| 175 request_success.Run(false); | 133 request_success.Run(false); |
| 176 return; | 134 return; |
| 177 } | 135 } |
| 178 base::PostTaskAndReplyWithResult( | 136 base::PostTaskAndReplyWithResult( |
| 179 background_task_runner_.get(), FROM_HERE, | 137 background_task_runner_.get(), FROM_HERE, |
| 180 base::Bind(&RequestPermissionTask, url, java_provider_), request_success); | 138 base::Bind(&RequestPermissionTask, url, java_provider_), request_success); |
| 181 } | 139 } |
| 182 | 140 |
| 183 void WebRestrictionsClient::OnWebRestrictionsChanged() { | 141 void WebRestrictionsClient::OnWebRestrictionsChanged( |
| 184 single_thread_task_runner_->PostTask( | 142 JNIEnv* env, |
| 185 FROM_HERE, | 143 const base::android::JavaParamRef<jobject>& obj) { |
| 144 content::BrowserThread::PostTask( |
| 145 content::BrowserThread::IO, FROM_HERE, |
| 186 base::Bind(&WebRestrictionsClient::ClearCache, base::Unretained(this))); | 146 base::Bind(&WebRestrictionsClient::ClearCache, base::Unretained(this))); |
| 187 } | 147 } |
| 188 | 148 |
| 189 void WebRestrictionsClient::RecordURLAccess(const GURL& url) { | 149 void WebRestrictionsClient::RecordURLAccess(const std::string& url) { |
| 190 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 150 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 191 // Move the URL to the front of the cache. | 151 // Move the URL to the front of the cache. |
| 192 recent_urls_.remove(url); | 152 recent_urls_.remove(url); |
| 193 recent_urls_.push_front(url); | 153 recent_urls_.push_front(url); |
| 194 } | 154 } |
| 195 | 155 |
| 196 void WebRestrictionsClient::UpdateCache(std::string provider_authority, | 156 void WebRestrictionsClient::UpdateCache(const std::string& provider_authority, |
| 197 GURL url, | 157 const std::string& url, |
| 198 ScopedJavaGlobalRef<jobject> result) { | 158 ScopedJavaGlobalRef<jobject> result) { |
| 199 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 159 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 200 // If the webrestrictions provider changed when the old one was being queried, | 160 // If the webrestrictions provider changed when the old one was being queried, |
| 201 // do not update the cache for the new provider. | 161 // do not update the cache for the new provider. |
| 202 if (provider_authority != provider_authority_) | 162 if (provider_authority != provider_authority_) |
| 203 return; | 163 return; |
| 204 RecordURLAccess(url); | 164 RecordURLAccess(url); |
| 205 if (recent_urls_.size() >= kMaxCacheSize) { | 165 if (recent_urls_.size() >= kMaxCacheSize) { |
| 206 cache_.erase(recent_urls_.back()); | 166 cache_.RemoveCacheEntry(recent_urls_.back()); |
| 207 recent_urls_.pop_back(); | 167 recent_urls_.pop_back(); |
| 208 } | 168 } |
| 209 cache_[url] = result; | 169 cache_.SetCacheEntry(url, WebRestrictionsClientResult(result)); |
| 210 } | 170 } |
| 211 | 171 |
| 212 void WebRestrictionsClient::RequestSupportKnown(std::string provider_authority, | 172 void WebRestrictionsClient::RequestSupportKnown( |
| 213 bool supports_request) { | 173 const std::string& provider_authority, |
| 174 bool supports_request) { |
| 214 // |supports_request_| is initialized to false. | 175 // |supports_request_| is initialized to false. |
| 215 DCHECK(!supports_request_); | 176 DCHECK(!supports_request_); |
| 216 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 177 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 217 // If the webrestrictions provider changed when the old one was being queried, | 178 // If the webrestrictions provider changed when the old one was being queried, |
| 218 // ignore the result. | 179 // ignore the result. |
| 219 if (provider_authority != provider_authority_) | 180 if (provider_authority != provider_authority_) |
| 220 return; | 181 return; |
| 221 supports_request_ = supports_request; | 182 supports_request_ = supports_request; |
| 222 } | 183 } |
| 223 | 184 |
| 224 void WebRestrictionsClient::OnShouldProceedComplete( | 185 void WebRestrictionsClient::OnShouldProceedComplete( |
| 225 std::string provider_authority, | 186 std::string provider_authority, |
| 226 const GURL& url, | 187 const std::string& url, |
| 227 const base::Callback<void(bool)>& callback, | 188 const base::Callback<void(bool)>& callback, |
| 228 const ScopedJavaGlobalRef<jobject>& result) { | 189 const ScopedJavaGlobalRef<jobject>& result) { |
| 229 UpdateCache(provider_authority, url, result); | 190 UpdateCache(provider_authority, url, result); |
| 230 JNIEnv* env = base::android::AttachCurrentThread(); | 191 callback.Run(cache_.GetCacheEntry(url)->ShouldProceed()); |
| 231 callback.Run(Java_ShouldProceedResult_shouldProceed(env, result)); | |
| 232 } | 192 } |
| 233 | 193 |
| 234 void WebRestrictionsClient::ClearCache() { | 194 void WebRestrictionsClient::ClearCache() { |
| 235 DCHECK(single_thread_task_runner_->BelongsToCurrentThread()); | 195 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 236 cache_.clear(); | 196 cache_.Clear(); |
| 237 recent_urls_.clear(); | 197 recent_urls_.clear(); |
| 238 } | 198 } |
| 239 | 199 |
| 200 std::unique_ptr<WebRestrictionsClientResult> |
| 201 WebRestrictionsClient::GetCachedWebRestrictionsResult(const std::string& url) { |
| 202 return cache_.GetCacheEntry(url); |
| 203 } |
| 204 |
| 240 // static | 205 // static |
| 241 ScopedJavaGlobalRef<jobject> WebRestrictionsClient::ShouldProceedTask( | 206 ScopedJavaGlobalRef<jobject> WebRestrictionsClient::ShouldProceedTask( |
| 242 const GURL& url, | 207 const std::string& url, |
| 243 const base::android::JavaRef<jobject>& java_provider) { | 208 const base::android::JavaRef<jobject>& java_provider) { |
| 244 JNIEnv* env = base::android::AttachCurrentThread(); | 209 JNIEnv* env = base::android::AttachCurrentThread(); |
| 245 base::android::ScopedJavaGlobalRef<jobject> result( | 210 base::android::ScopedJavaGlobalRef<jobject> result( |
| 246 Java_WebRestrictionsClient_shouldProceed( | 211 Java_WebRestrictionsClient_shouldProceed( |
| 247 env, java_provider, | 212 env, java_provider, |
| 248 base::android::ConvertUTF8ToJavaString(env, url.spec()))); | 213 base::android::ConvertUTF8ToJavaString(env, url))); |
| 249 return result; | 214 return result; |
| 250 } | 215 } |
| 251 | 216 |
| 252 void NotifyWebRestrictionsChanged( | 217 WebRestrictionsClient::Cache::Cache() = default; |
| 253 JNIEnv* env, | 218 |
| 254 const base::android::JavaParamRef<jobject>& clazz, | 219 WebRestrictionsClient::Cache::~Cache() = default; |
| 255 jlong provider_ptr) { | 220 |
| 256 WebRestrictionsClient* provider = | 221 std::unique_ptr<WebRestrictionsClientResult> |
| 257 reinterpret_cast<WebRestrictionsClient*>(provider_ptr); | 222 WebRestrictionsClient::Cache::GetCacheEntry(const std::string& url) { |
| 258 // TODO(knn): Also reload existing interstitials/error pages. | 223 base::AutoLock lock(lock_); |
| 259 provider->OnWebRestrictionsChanged(); | 224 auto iter = cache_data_.find(url); |
| 225 if (iter == cache_data_.end()) |
| 226 return nullptr; |
| 227 // This has to be thread-safe, so copy the data. |
| 228 return std::unique_ptr<WebRestrictionsClientResult>( |
| 229 new WebRestrictionsClientResult(iter->second)); |
| 230 } |
| 231 |
| 232 void WebRestrictionsClient::Cache::SetCacheEntry( |
| 233 const std::string& url, |
| 234 const WebRestrictionsClientResult& entry) { |
| 235 base::AutoLock lock(lock_); |
| 236 cache_data_.emplace(url, entry); |
| 237 } |
| 238 |
| 239 void WebRestrictionsClient::Cache::RemoveCacheEntry(const std::string& url) { |
| 240 base::AutoLock lock(lock_); |
| 241 cache_data_.erase(url); |
| 242 } |
| 243 |
| 244 void WebRestrictionsClient::Cache::Clear() { |
| 245 base::AutoLock lock(lock_); |
| 246 cache_data_.clear(); |
| 260 } | 247 } |
| 261 | 248 |
| 262 } // namespace web_restrictions | 249 } // namespace web_restrictions |
| OLD | NEW |