Chromium Code Reviews| Index: android_webview/native/android_protocol_handler.cc |
| diff --git a/android_webview/native/android_protocol_handler.cc b/android_webview/native/android_protocol_handler.cc |
| index 907881bae85822301eb9d1d435e0c8d1e23f7443..d7a672b2fbc106286849a9f3b997d181137d8116 100644 |
| --- a/android_webview/native/android_protocol_handler.cc |
| +++ b/android_webview/native/android_protocol_handler.cc |
| @@ -44,6 +44,17 @@ void ResetResourceContext(JavaObjectWeakGlobalRef* ref) { |
| g_resource_context = ref; |
| } |
| +void* kPreviouslyFailedKey = &kPreviouslyFailedKey; |
| + |
| +void MarkRequestAsFailed(net::URLRequest* request) { |
| + request->SetUserData(kPreviouslyFailedKey, |
| + new base::SupportsUserData::Data()); |
| +} |
| + |
| +bool HasRequestPreviouslyFailed(net::URLRequest* request) { |
| + return request->GetUserData(kPreviouslyFailedKey) != NULL; |
| +} |
| + |
| class AndroidStreamReaderURLRequestJobDelegateImpl |
| : public AndroidStreamReaderURLRequestJob::Delegate { |
| public: |
| @@ -51,7 +62,10 @@ class AndroidStreamReaderURLRequestJobDelegateImpl |
| virtual scoped_ptr<InputStream> OpenInputStream( |
| JNIEnv* env, |
| - net::URLRequest* request) OVERRIDE; |
| + const GURL& url) OVERRIDE; |
| + |
| + virtual void OnInputStreamOpenFailed(net::URLRequest* request, |
| + bool* restart) OVERRIDE; |
| virtual bool GetMimeType(JNIEnv* env, |
| net::URLRequest* request, |
| @@ -64,21 +78,29 @@ class AndroidStreamReaderURLRequestJobDelegateImpl |
| std::string* charset) OVERRIDE; |
| virtual ~AndroidStreamReaderURLRequestJobDelegateImpl(); |
| + |
| + private: |
| + scoped_ptr<InputStream> DoOpenInputStream(JNIEnv* env, const GURL& url); |
| }; |
| -class AssetFileProtocolInterceptor : |
| - public net::URLRequestJobFactory::ProtocolHandler { |
| +class AndroidProtocolHandlerBase : |
| + public net::URLRequestJobFactory::ProtocolHandler { |
| public: |
| - virtual ~AssetFileProtocolInterceptor() OVERRIDE; |
| - static scoped_ptr<net::URLRequestJobFactory> CreateURLRequestJobFactory( |
| - scoped_ptr<net::URLRequestJobFactory> base_job_factory); |
| virtual net::URLRequestJob* MaybeCreateJob( |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) const OVERRIDE; |
| - private: |
| - AssetFileProtocolInterceptor(); |
| + virtual bool CanHandleRequest(const net::URLRequest* request) const = 0; |
| +}; |
| +class AssetFileProtocolHandler : public AndroidProtocolHandlerBase { |
| + public: |
| + AssetFileProtocolHandler(); |
| + |
| + virtual ~AssetFileProtocolHandler() OVERRIDE; |
| + virtual bool CanHandleRequest(const net::URLRequest* request) const OVERRIDE; |
| + |
| + private: |
| // file:///android_asset/ |
| const std::string asset_prefix_; |
| // file:///android_res/ |
| @@ -86,21 +108,10 @@ class AssetFileProtocolInterceptor : |
| }; |
| // Protocol handler for content:// scheme requests. |
| -class ContentSchemeProtocolHandler : |
| - public net::URLRequestJobFactory::ProtocolHandler { |
| +class ContentSchemeProtocolHandler : public AndroidProtocolHandlerBase { |
| public: |
| - ContentSchemeProtocolHandler() {} |
| - |
| - virtual net::URLRequestJob* MaybeCreateJob( |
| - net::URLRequest* request, |
| - net::NetworkDelegate* network_delegate) const OVERRIDE { |
| - DCHECK(request->url().SchemeIs(android_webview::kContentScheme)); |
| - return new AndroidStreamReaderURLRequestJob( |
| - request, |
| - network_delegate, |
| - scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>( |
| - new AndroidStreamReaderURLRequestJobDelegateImpl())); |
| - } |
| + ContentSchemeProtocolHandler(); |
| + virtual bool CanHandleRequest(const net::URLRequest* request) const OVERRIDE; |
| }; |
| static ScopedJavaLocalRef<jobject> GetResourceContext(JNIEnv* env) { |
| @@ -114,9 +125,10 @@ static ScopedJavaLocalRef<jobject> GetResourceContext(JNIEnv* env) { |
| return context; |
| } |
| +// AndroidStreamReaderURLRequestJobDelegateImpl ------------------------------- |
| + |
| AndroidStreamReaderURLRequestJobDelegateImpl:: |
| -AndroidStreamReaderURLRequestJobDelegateImpl() { |
| -} |
| + AndroidStreamReaderURLRequestJobDelegateImpl() {} |
| AndroidStreamReaderURLRequestJobDelegateImpl:: |
| ~AndroidStreamReaderURLRequestJobDelegateImpl() { |
| @@ -124,18 +136,18 @@ AndroidStreamReaderURLRequestJobDelegateImpl:: |
| scoped_ptr<InputStream> |
| AndroidStreamReaderURLRequestJobDelegateImpl::OpenInputStream( |
| - JNIEnv* env, net::URLRequest* request) { |
| - DCHECK(request); |
| + JNIEnv* env, const GURL& url) { |
| + DCHECK(url.is_valid()); |
| DCHECK(env); |
| // Open the input stream. |
| - ScopedJavaLocalRef<jstring> url = |
| - ConvertUTF8ToJavaString(env, request->url().spec()); |
| + ScopedJavaLocalRef<jstring> jurl = |
| + ConvertUTF8ToJavaString(env, url.spec()); |
| ScopedJavaLocalRef<jobject> stream = |
| android_webview::Java_AndroidProtocolHandler_open( |
| env, |
| GetResourceContext(env).obj(), |
| - url.obj()); |
| + jurl.obj()); |
| // Check and clear pending exceptions. |
| if (ClearException(env) || stream.is_null()) { |
| @@ -145,6 +157,13 @@ AndroidStreamReaderURLRequestJobDelegateImpl::OpenInputStream( |
| return make_scoped_ptr<InputStream>(new InputStreamImpl(stream)); |
| } |
| +void AndroidStreamReaderURLRequestJobDelegateImpl::OnInputStreamOpenFailed( |
| + net::URLRequest* request, |
| + bool* restart) { |
| + MarkRequestAsFailed(request); |
|
boliu
2013/03/06 02:30:18
Should put a DCHECK(!HasRequestPreviouslyFailed(re
mkosiba (inactive)
2013/03/06 19:05:27
good idea!
|
| + *restart = true; |
| +} |
| + |
| bool AndroidStreamReaderURLRequestJobDelegateImpl::GetMimeType( |
| JNIEnv* env, |
| net::URLRequest* request, |
| @@ -181,7 +200,37 @@ bool AndroidStreamReaderURLRequestJobDelegateImpl::GetCharset( |
| return false; |
| } |
| -AssetFileProtocolInterceptor::AssetFileProtocolInterceptor() |
| +// AndroidProtocolHandlerBase ------------------------------------------------- |
| + |
| +net::URLRequestJob* AndroidProtocolHandlerBase::MaybeCreateJob( |
| + net::URLRequest* request, |
| + net::NetworkDelegate* network_delegate) const { |
| + if (!CanHandleRequest(request)) return NULL; |
| + |
| + // For WebViewClassic compatibility this job can only accept URLs that can be |
| + // opened. URLs that cannot be opened should be resolved by the next handler. |
| + // |
| + // If a request is initially handled here but the job fails due to it being |
| + // unable to open the InputStream for that request the request is marked as |
| + // previously failed and restarted. |
| + // Restarting a request involves creating a new job for that request. This |
| + // handler will ignore requests know to have previously failed to 1) prevent |
| + // an infinite loop, 2) ensure that the next handler in line gets the |
| + // opportunity to create a job for the request. |
| + if (HasRequestPreviouslyFailed(request)) return NULL; |
| + |
| + scoped_ptr<AndroidStreamReaderURLRequestJobDelegateImpl> reader_delegate( |
| + new AndroidStreamReaderURLRequestJobDelegateImpl()); |
| + |
| + return new AndroidStreamReaderURLRequestJob( |
| + request, |
| + network_delegate, |
| + reader_delegate.PassAs<AndroidStreamReaderURLRequestJob::Delegate>()); |
| +} |
| + |
| +// AssetFileProtocolHandler --------------------------------------------------- |
| + |
| +AssetFileProtocolHandler::AssetFileProtocolHandler() |
| : asset_prefix_(std::string(chrome::kFileScheme) + |
| std::string(content::kStandardSchemeSeparator) + |
| android_webview::kAndroidAssetPath), |
| @@ -190,36 +239,31 @@ AssetFileProtocolInterceptor::AssetFileProtocolInterceptor() |
| android_webview::kAndroidResourcePath) { |
| } |
| -AssetFileProtocolInterceptor::~AssetFileProtocolInterceptor() { |
| -} |
| - |
| -// static |
| -scoped_ptr<net::URLRequestJobFactory> |
| -AssetFileProtocolInterceptor::CreateURLRequestJobFactory( |
| - scoped_ptr<net::URLRequestJobFactory> base_job_factory) { |
| - scoped_ptr<net::URLRequestJobFactory> top_job_factory( |
| - new net::ProtocolInterceptJobFactory( |
| - base_job_factory.Pass(), |
| - scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>( |
| - new AssetFileProtocolInterceptor()))); |
| - return top_job_factory.Pass(); |
| +AssetFileProtocolHandler::~AssetFileProtocolHandler() { |
| } |
| -net::URLRequestJob* AssetFileProtocolInterceptor::MaybeCreateJob( |
| - net::URLRequest* request, net::NetworkDelegate* network_delegate) const { |
| - if (!request->url().SchemeIsFile()) return NULL; |
| +bool AssetFileProtocolHandler::CanHandleRequest( |
| + const net::URLRequest* request) const { |
| + if (!request->url().SchemeIsFile()) |
| + return false; |
| const std::string& url = request->url().spec(); |
| if (!StartsWithASCII(url, asset_prefix_, /*case_sensitive=*/ true) && |
| - !StartsWithASCII(url, resource_prefix_, /*case_sensitive=*/ true)) { |
| - return NULL; |
| + !StartsWithASCII(url, resource_prefix_, /*case_sensitive=*/ true)) { |
| + return false; |
| } |
| - return new AndroidStreamReaderURLRequestJob( |
| - request, |
| - network_delegate, |
| - scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>( |
| - new AndroidStreamReaderURLRequestJobDelegateImpl())); |
| + return true; |
| +} |
| + |
| +// ContentSchemeProtocolHandler ----------------------------------------------- |
| + |
| +ContentSchemeProtocolHandler::ContentSchemeProtocolHandler() { |
| +} |
| + |
| +bool ContentSchemeProtocolHandler::CanHandleRequest( |
| + const net::URLRequest* request) const { |
| + return request->url().SchemeIs(android_webview::kContentScheme); |
| } |
| } // namespace |
| @@ -231,18 +275,17 @@ bool RegisterAndroidProtocolHandler(JNIEnv* env) { |
| } |
| // static |
| -scoped_ptr<net::URLRequestJobFactory> CreateAndroidRequestJobFactory( |
| - scoped_ptr<AwURLRequestJobFactory> job_factory) { |
| - // Register content://. Note that even though a scheme is |
| - // registered here, it cannot be used by child processes until access to it is |
| - // granted via ChildProcessSecurityPolicy::GrantScheme(). This is done in |
| - // AwContentBrowserClient. |
| - // The job factory takes ownership of the handler. |
| - bool set_protocol = job_factory->SetProtocolHandler( |
| - android_webview::kContentScheme, new ContentSchemeProtocolHandler()); |
| - DCHECK(set_protocol); |
| - return AssetFileProtocolInterceptor::CreateURLRequestJobFactory( |
| - job_factory.PassAs<net::URLRequestJobFactory>()); |
| +scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> |
| +CreateContentSchemeProtocolHandler() { |
| + return make_scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>( |
| + new ContentSchemeProtocolHandler()); |
| +} |
| + |
| +// static |
| +scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> |
| +CreateAssetFileProtocolHandler() { |
| + return make_scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>( |
| + new AssetFileProtocolHandler()); |
| } |
| // Set a context object to be used for resolving resource queries. This can |