Chromium Code Reviews| Index: components/web_restrictions/content_resolver_web_restrictions_provider.cc |
| diff --git a/components/web_restrictions/content_resolver_web_restrictions_provider.cc b/components/web_restrictions/content_resolver_web_restrictions_provider.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b4e750e7dac120f7528fc3f9a1a96e8417df5e54 |
| --- /dev/null |
| +++ b/components/web_restrictions/content_resolver_web_restrictions_provider.cc |
| @@ -0,0 +1,247 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "components/web_restrictions/content_resolver_web_restrictions_provider.h" |
| + |
| +#include "base/android/jni_string.h" |
| +#include "base/android/scoped_java_ref.h" |
| +#include "base/bind.h" |
| +#include "base/location.h" |
| +#include "base/thread_task_runner_handle.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "jni/ContentResolverWebRestrictionsProvider_jni.h" |
| + |
| +namespace web_restrictions { |
| + |
| +namespace { |
| + |
| +namespace cache_helper { |
|
Bernhard Bauer
2016/01/28 12:15:14
I don't think this namespace is necessary, as all
knn
2016/01/28 18:10:37
More for structure but redundant now, I have made
|
| + |
| +const size_t kMaxCacheSize = 100; |
| + |
| +void RecordAccess(std::list<GURL>* recent_urls, const GURL& url) { |
| + // Move the url to the front of the cache. |
|
Bernhard Bauer
2016/01/28 12:15:14
Nit: URL
knn
2016/01/28 18:10:37
Done.
|
| + recent_urls->remove(url); |
| + recent_urls->push_front(url); |
| +} |
| + |
| +void InsertValue(std::map<GURL, std::string>* error_page_cache, |
| + std::map<GURL, bool>* url_access_cache, |
| + std::list<GURL>* recent_urls, |
| + const GURL& url, |
| + bool should_proceed, |
| + const base::android::JavaParamRef<jstring>& j_error_page) { |
|
Bernhard Bauer
2016/01/28 12:15:14
Use JavaRef (JavaParamRef is only a temporary thin
knn
2016/01/28 18:10:37
Good catch!
|
| + RecordAccess(recent_urls, url); |
| + if (recent_urls->size() >= kMaxCacheSize) { |
| + url_access_cache->erase(recent_urls->back()); |
| + error_page_cache->erase(recent_urls->back()); |
| + recent_urls->pop_back(); |
| + } |
| + (*url_access_cache)[url] = should_proceed; |
| + if (!j_error_page.is_null()) { |
| + (*error_page_cache)[url] = |
| + base::android::ConvertJavaStringToUTF8(j_error_page); |
| + } else { |
| + error_page_cache->erase(url); |
| + } |
| +} |
| + |
| +} // namespace cache_helper |
| + |
| +namespace async_helper { |
| + |
| +void ShouldProceed(const GURL& url, |
| + jlong callback, |
| + const base::android::JavaRef<jobject>& java_provider) { |
| + JNIEnv* env = base::android::AttachCurrentThread(); |
| + Java_ContentResolverWebRestrictionsProvider_shouldProceed( |
| + env, java_provider.obj(), callback, |
| + base::android::ConvertUTF8ToJavaString(env, url.spec()).obj()); |
| +} |
| + |
| +void RequestPermission(const GURL& url, |
| + jlong callback, |
| + const base::android::JavaRef<jobject>& java_provider) { |
| + JNIEnv* env = base::android::AttachCurrentThread(); |
| + Java_ContentResolverWebRestrictionsProvider_requestPermission( |
| + env, java_provider.obj(), callback, |
| + base::android::ConvertUTF8ToJavaString(env, url.spec()).obj()); |
| +} |
| + |
| +} // namespace async_helper |
| + |
| +} // namespace |
| + |
| +// A wrapper to the callback class to facilitate getting a callback from java |
| +// into C++. Objects of this class delete itself only when they are called back |
| +// so we must ensure that happens even for error cases. |
| +class SelfDeletingCallback { |
| + public: |
| + SelfDeletingCallback(const GURL& url, |
| + const base::Callback<void(bool)>& callback, |
| + const scoped_refptr<base::TaskRunner>& callback_runner, |
| + ContentResolverWebRestrictionsProvider* provider); |
| + void RequestSuccess(bool request_success); |
| + void ShouldProceed(bool should_proceed, |
| + const base::android::JavaParamRef<jstring>& error_page); |
| + |
| + private: |
| + // Only the callback can delete itself. We must ensure it is indeed |
| + // called back. |
| + ~SelfDeletingCallback() {} |
| + |
| + GURL url_; |
| + base::Callback<void(bool)> callback_; |
| + scoped_refptr<base::TaskRunner> callback_runner_; |
| + ContentResolverWebRestrictionsProvider* provider_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(SelfDeletingCallback); |
| +}; |
| + |
| +SelfDeletingCallback::SelfDeletingCallback( |
| + const GURL& url, |
| + const base::Callback<void(bool)>& callback, |
| + const scoped_refptr<base::TaskRunner>& callback_runner, |
| + ContentResolverWebRestrictionsProvider* provider) |
| + : url_(url), |
| + callback_(callback), |
| + callback_runner_(callback_runner), |
| + provider_(provider) {} |
| + |
| +void SelfDeletingCallback::ShouldProceed( |
| + bool should_proceed, |
| + const base::android::JavaParamRef<jstring>& error_page) { |
| + cache_helper::InsertValue( |
|
Bernhard Bauer
2016/01/28 12:15:14
Just make this a method on |provider_|? That would
knn
2016/01/28 18:10:37
Done.
|
| + &provider_->error_page_cache_, &provider_->url_access_cache_, |
| + &provider_->recent_urls_, url_, should_proceed, error_page); |
| + callback_runner_->PostTask(FROM_HERE, base::Bind(callback_, should_proceed)); |
| + delete this; |
| +} |
| + |
| +void SelfDeletingCallback::RequestSuccess(bool request_success) { |
| + callback_runner_->PostTask(FROM_HERE, base::Bind(callback_, request_success)); |
| + delete this; |
| +} |
| + |
| +// static |
| +bool ContentResolverWebRestrictionsProvider::Register(JNIEnv* env) { |
| + return RegisterNativesImpl(env); |
| +} |
| + |
| +ContentResolverWebRestrictionsProvider::ContentResolverWebRestrictionsProvider() |
| + : initialized_(false), supports_request_(false) {} |
| + |
| +ContentResolverWebRestrictionsProvider:: |
| + ~ContentResolverWebRestrictionsProvider() {} |
| + |
| +void ContentResolverWebRestrictionsProvider::Initialize( |
| + const std::string& content_provider_authority) { |
| + ClearCache(); |
| + initialized_ = !content_provider_authority.empty(); |
| + if (!initialized_) |
| + return; |
| + JNIEnv* env = base::android::AttachCurrentThread(); |
| + java_provider_.Reset(Java_ContentResolverWebRestrictionsProvider_create( |
| + env, |
| + base::android::ConvertUTF8ToJavaString(env, content_provider_authority) |
| + .obj(), |
| + reinterpret_cast<jlong>(this))); |
| + supports_request_ = |
| + Java_ContentResolverWebRestrictionsProvider_supportsRequest( |
| + env, java_provider_.obj()); |
| +} |
| + |
| +UrlAccess ContentResolverWebRestrictionsProvider::ShouldProceed( |
| + bool is_main_frame, |
| + const GURL& url, |
| + const base::Callback<void(bool)>& callback) { |
| + if (!initialized_) |
| + return ALLOW; |
| + auto iter = url_access_cache_.find(url); |
| + if (iter != url_access_cache_.end()) { |
| + cache_helper::RecordAccess(&recent_urls_, url); |
| + return iter->second ? ALLOW : DISALLOW; |
| + } |
| + scoped_refptr<base::SingleThreadTaskRunner> callback_runner = |
| + base::ThreadTaskRunnerHandle::Get(); |
| + SelfDeletingCallback* wrapped_callback = |
| + new SelfDeletingCallback(url, callback, callback_runner, this); |
|
Bernhard Bauer
2016/01/28 12:15:14
I was going to write, "please mention that this de
knn
2016/01/28 18:10:37
Indeed we do not need to make it self deleting giv
|
| + content::BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( |
|
Bernhard Bauer
2016/01/28 12:15:14
Speaking of multiple threads, you want to use a Se
knn
2016/01/28 18:10:37
Done.
|
| + FROM_HERE, |
| + base::Bind(&async_helper::ShouldProceed, url, |
| + reinterpret_cast<jlong>(wrapped_callback), java_provider_), |
| + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
| + return PENDING; |
| +} |
| + |
| +bool ContentResolverWebRestrictionsProvider::SupportsRequest() const { |
| + return initialized_ && supports_request_; |
| +} |
| + |
| +bool ContentResolverWebRestrictionsProvider::GetErrorHtml( |
| + const GURL& url, |
| + std::string* error_page) const { |
| + if (!initialized_) |
| + return false; |
| + auto iter = error_page_cache_.find(url); |
| + if (iter == error_page_cache_.end()) |
| + return false; |
| + *error_page = iter->second; |
| + return true; |
| +} |
| + |
| +void ContentResolverWebRestrictionsProvider::RequestPermission( |
| + const GURL& url, |
| + const base::Callback<void(bool)>& request_success) { |
| + if (!initialized_) { |
| + request_success.Run(false); |
| + return; |
| + } |
| + scoped_refptr<base::SingleThreadTaskRunner> callback_runner = |
| + base::ThreadTaskRunnerHandle::Get(); |
| + SelfDeletingCallback* wrapped_callback = |
| + new SelfDeletingCallback(url, request_success, callback_runner, this); |
| + content::BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( |
| + FROM_HERE, |
| + base::Bind(&async_helper::RequestPermission, url, |
| + reinterpret_cast<jlong>(wrapped_callback), java_provider_), |
| + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
| +} |
| + |
| +void ContentResolverWebRestrictionsProvider::ClearCache() { |
| + error_page_cache_.clear(); |
| + url_access_cache_.clear(); |
| + recent_urls_.clear(); |
| +} |
| + |
| +void ShouldProceed(JNIEnv* env, |
| + const base::android::JavaParamRef<jclass>& clazz, |
| + jlong callback_ptr, |
| + jboolean should_proceed, |
| + const base::android::JavaParamRef<jstring>& error_page) { |
| + SelfDeletingCallback* callback = |
| + reinterpret_cast<SelfDeletingCallback*>(callback_ptr); |
| + callback->ShouldProceed(should_proceed, error_page); |
| +} |
| + |
| +void RequestSuccess(JNIEnv* env, |
| + const base::android::JavaParamRef<jclass>& clazz, |
| + jlong callback_ptr, |
| + jboolean request_success) { |
| + SelfDeletingCallback* callback = |
| + reinterpret_cast<SelfDeletingCallback*>(callback_ptr); |
| + callback->RequestSuccess(request_success); |
| +} |
| + |
| +void NotifyWebRestrictionsChanged( |
| + JNIEnv* env, |
| + const base::android::JavaParamRef<jclass>& clazz, |
| + jlong provider_ptr) { |
| + ContentResolverWebRestrictionsProvider* provider = |
| + reinterpret_cast<ContentResolverWebRestrictionsProvider*>(provider_ptr); |
| + // TODO(knn): Also reload existing interstitials/error pages. |
| + provider->ClearCache(); |
| +} |
| + |
| +} // namespace web_restrictions |