Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "android_webview/native/android_protocol_handler.h" | 5 #include "android_webview/native/android_protocol_handler.h" |
| 6 | 6 |
| 7 #include "android_webview/browser/net/android_stream_reader_url_request_job.h" | 7 #include "android_webview/browser/net/android_stream_reader_url_request_job.h" |
| 8 #include "android_webview/browser/net/aw_url_request_job_factory.h" | 8 #include "android_webview/browser/net/aw_url_request_job_factory.h" |
| 9 #include "android_webview/common/url_constants.h" | 9 #include "android_webview/common/url_constants.h" |
| 10 #include "android_webview/native/input_stream_impl.h" | 10 #include "android_webview/native/input_stream_impl.h" |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 // testing. | 37 // testing. |
| 38 JavaObjectWeakGlobalRef* g_resource_context = NULL; | 38 JavaObjectWeakGlobalRef* g_resource_context = NULL; |
| 39 | 39 |
| 40 void ResetResourceContext(JavaObjectWeakGlobalRef* ref) { | 40 void ResetResourceContext(JavaObjectWeakGlobalRef* ref) { |
| 41 if (g_resource_context) | 41 if (g_resource_context) |
| 42 delete g_resource_context; | 42 delete g_resource_context; |
| 43 | 43 |
| 44 g_resource_context = ref; | 44 g_resource_context = ref; |
| 45 } | 45 } |
| 46 | 46 |
| 47 void* kPreviouslyFailedKey = &kPreviouslyFailedKey; | |
| 48 | |
| 49 void MarkRequestAsFailed(net::URLRequest* request) { | |
| 50 request->SetUserData(kPreviouslyFailedKey, | |
| 51 new base::SupportsUserData::Data()); | |
| 52 } | |
| 53 | |
| 54 bool HasRequestPreviouslyFailed(net::URLRequest* request) { | |
| 55 return request->GetUserData(kPreviouslyFailedKey) != NULL; | |
| 56 } | |
| 57 | |
| 47 class AndroidStreamReaderURLRequestJobDelegateImpl | 58 class AndroidStreamReaderURLRequestJobDelegateImpl |
| 48 : public AndroidStreamReaderURLRequestJob::Delegate { | 59 : public AndroidStreamReaderURLRequestJob::Delegate { |
| 49 public: | 60 public: |
| 50 AndroidStreamReaderURLRequestJobDelegateImpl(); | 61 AndroidStreamReaderURLRequestJobDelegateImpl(); |
| 51 | 62 |
| 52 virtual scoped_ptr<InputStream> OpenInputStream( | 63 virtual scoped_ptr<InputStream> OpenInputStream( |
| 53 JNIEnv* env, | 64 JNIEnv* env, |
| 54 net::URLRequest* request) OVERRIDE; | 65 const GURL& url) OVERRIDE; |
| 66 | |
| 67 virtual void OnInputStreamOpenFailed(net::URLRequest* request, | |
| 68 bool* restart) OVERRIDE; | |
| 55 | 69 |
| 56 virtual bool GetMimeType(JNIEnv* env, | 70 virtual bool GetMimeType(JNIEnv* env, |
| 57 net::URLRequest* request, | 71 net::URLRequest* request, |
| 58 InputStream* stream, | 72 InputStream* stream, |
| 59 std::string* mime_type) OVERRIDE; | 73 std::string* mime_type) OVERRIDE; |
| 60 | 74 |
| 61 virtual bool GetCharset(JNIEnv* env, | 75 virtual bool GetCharset(JNIEnv* env, |
| 62 net::URLRequest* request, | 76 net::URLRequest* request, |
| 63 InputStream* stream, | 77 InputStream* stream, |
| 64 std::string* charset) OVERRIDE; | 78 std::string* charset) OVERRIDE; |
| 65 | 79 |
| 66 virtual ~AndroidStreamReaderURLRequestJobDelegateImpl(); | 80 virtual ~AndroidStreamReaderURLRequestJobDelegateImpl(); |
| 81 | |
| 82 private: | |
| 83 scoped_ptr<InputStream> DoOpenInputStream(JNIEnv* env, const GURL& url); | |
| 67 }; | 84 }; |
| 68 | 85 |
| 69 class AssetFileProtocolInterceptor : | 86 class AndroidProtocolHandlerBase : |
| 70 public net::URLRequestJobFactory::ProtocolHandler { | 87 public net::URLRequestJobFactory::ProtocolHandler { |
| 71 public: | 88 public: |
| 72 virtual ~AssetFileProtocolInterceptor() OVERRIDE; | |
| 73 static scoped_ptr<net::URLRequestJobFactory> CreateURLRequestJobFactory( | |
| 74 scoped_ptr<net::URLRequestJobFactory> base_job_factory); | |
| 75 virtual net::URLRequestJob* MaybeCreateJob( | 89 virtual net::URLRequestJob* MaybeCreateJob( |
| 76 net::URLRequest* request, | 90 net::URLRequest* request, |
| 77 net::NetworkDelegate* network_delegate) const OVERRIDE; | 91 net::NetworkDelegate* network_delegate) const OVERRIDE; |
| 78 | 92 |
| 93 virtual bool CanHandleRequest(const net::URLRequest* request) const = 0; | |
| 94 }; | |
| 95 | |
| 96 class AssetFileProtocolHandler : public AndroidProtocolHandlerBase { | |
| 97 public: | |
| 98 AssetFileProtocolHandler(); | |
| 99 | |
| 100 virtual ~AssetFileProtocolHandler() OVERRIDE; | |
| 101 virtual bool CanHandleRequest(const net::URLRequest* request) const OVERRIDE; | |
| 102 | |
| 79 private: | 103 private: |
| 80 AssetFileProtocolInterceptor(); | |
| 81 | |
| 82 // file:///android_asset/ | 104 // file:///android_asset/ |
| 83 const std::string asset_prefix_; | 105 const std::string asset_prefix_; |
| 84 // file:///android_res/ | 106 // file:///android_res/ |
| 85 const std::string resource_prefix_; | 107 const std::string resource_prefix_; |
| 86 }; | 108 }; |
| 87 | 109 |
| 88 // Protocol handler for content:// scheme requests. | 110 // Protocol handler for content:// scheme requests. |
| 89 class ContentSchemeProtocolHandler : | 111 class ContentSchemeProtocolHandler : public AndroidProtocolHandlerBase { |
| 90 public net::URLRequestJobFactory::ProtocolHandler { | |
| 91 public: | 112 public: |
| 92 ContentSchemeProtocolHandler() {} | 113 ContentSchemeProtocolHandler(); |
| 93 | 114 virtual bool CanHandleRequest(const net::URLRequest* request) const OVERRIDE; |
| 94 virtual net::URLRequestJob* MaybeCreateJob( | |
| 95 net::URLRequest* request, | |
| 96 net::NetworkDelegate* network_delegate) const OVERRIDE { | |
| 97 DCHECK(request->url().SchemeIs(android_webview::kContentScheme)); | |
| 98 return new AndroidStreamReaderURLRequestJob( | |
| 99 request, | |
| 100 network_delegate, | |
| 101 scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>( | |
| 102 new AndroidStreamReaderURLRequestJobDelegateImpl())); | |
| 103 } | |
| 104 }; | 115 }; |
| 105 | 116 |
| 106 static ScopedJavaLocalRef<jobject> GetResourceContext(JNIEnv* env) { | 117 static ScopedJavaLocalRef<jobject> GetResourceContext(JNIEnv* env) { |
| 107 if (g_resource_context) | 118 if (g_resource_context) |
| 108 return g_resource_context->get(env); | 119 return g_resource_context->get(env); |
| 109 ScopedJavaLocalRef<jobject> context; | 120 ScopedJavaLocalRef<jobject> context; |
| 110 // We have to reset as GetApplicationContext() returns a jobject with a | 121 // We have to reset as GetApplicationContext() returns a jobject with a |
| 111 // global ref. The constructor that takes a jobject would expect a local ref | 122 // global ref. The constructor that takes a jobject would expect a local ref |
| 112 // and would assert. | 123 // and would assert. |
| 113 context.Reset(env, base::android::GetApplicationContext()); | 124 context.Reset(env, base::android::GetApplicationContext()); |
| 114 return context; | 125 return context; |
| 115 } | 126 } |
| 116 | 127 |
| 128 // AndroidStreamReaderURLRequestJobDelegateImpl ------------------------------- | |
| 129 | |
| 117 AndroidStreamReaderURLRequestJobDelegateImpl:: | 130 AndroidStreamReaderURLRequestJobDelegateImpl:: |
| 118 AndroidStreamReaderURLRequestJobDelegateImpl() { | 131 AndroidStreamReaderURLRequestJobDelegateImpl() {} |
| 119 } | |
| 120 | 132 |
| 121 AndroidStreamReaderURLRequestJobDelegateImpl:: | 133 AndroidStreamReaderURLRequestJobDelegateImpl:: |
| 122 ~AndroidStreamReaderURLRequestJobDelegateImpl() { | 134 ~AndroidStreamReaderURLRequestJobDelegateImpl() { |
| 123 } | 135 } |
| 124 | 136 |
| 125 scoped_ptr<InputStream> | 137 scoped_ptr<InputStream> |
| 126 AndroidStreamReaderURLRequestJobDelegateImpl::OpenInputStream( | 138 AndroidStreamReaderURLRequestJobDelegateImpl::OpenInputStream( |
| 127 JNIEnv* env, net::URLRequest* request) { | 139 JNIEnv* env, const GURL& url) { |
| 128 DCHECK(request); | 140 DCHECK(url.is_valid()); |
| 129 DCHECK(env); | 141 DCHECK(env); |
| 130 | 142 |
| 131 // Open the input stream. | 143 // Open the input stream. |
| 132 ScopedJavaLocalRef<jstring> url = | 144 ScopedJavaLocalRef<jstring> jurl = |
| 133 ConvertUTF8ToJavaString(env, request->url().spec()); | 145 ConvertUTF8ToJavaString(env, url.spec()); |
| 134 ScopedJavaLocalRef<jobject> stream = | 146 ScopedJavaLocalRef<jobject> stream = |
| 135 android_webview::Java_AndroidProtocolHandler_open( | 147 android_webview::Java_AndroidProtocolHandler_open( |
| 136 env, | 148 env, |
| 137 GetResourceContext(env).obj(), | 149 GetResourceContext(env).obj(), |
| 138 url.obj()); | 150 jurl.obj()); |
| 139 | 151 |
| 140 // Check and clear pending exceptions. | 152 // Check and clear pending exceptions. |
| 141 if (ClearException(env) || stream.is_null()) { | 153 if (ClearException(env) || stream.is_null()) { |
| 142 DLOG(ERROR) << "Unable to open input stream for Android URL"; | 154 DLOG(ERROR) << "Unable to open input stream for Android URL"; |
| 143 return scoped_ptr<InputStream>(); | 155 return scoped_ptr<InputStream>(); |
| 144 } | 156 } |
| 145 return make_scoped_ptr<InputStream>(new InputStreamImpl(stream)); | 157 return make_scoped_ptr<InputStream>(new InputStreamImpl(stream)); |
| 146 } | 158 } |
| 147 | 159 |
| 160 void AndroidStreamReaderURLRequestJobDelegateImpl::OnInputStreamOpenFailed( | |
| 161 net::URLRequest* request, | |
| 162 bool* restart) { | |
| 163 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!
| |
| 164 *restart = true; | |
| 165 } | |
| 166 | |
| 148 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetMimeType( | 167 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetMimeType( |
| 149 JNIEnv* env, | 168 JNIEnv* env, |
| 150 net::URLRequest* request, | 169 net::URLRequest* request, |
| 151 android_webview::InputStream* stream, | 170 android_webview::InputStream* stream, |
| 152 std::string* mime_type) { | 171 std::string* mime_type) { |
| 153 DCHECK(env); | 172 DCHECK(env); |
| 154 DCHECK(request); | 173 DCHECK(request); |
| 155 DCHECK(mime_type); | 174 DCHECK(mime_type); |
| 156 | 175 |
| 157 // Query the mime type from the Java side. It is possible for the query to | 176 // Query the mime type from the Java side. It is possible for the query to |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 174 | 193 |
| 175 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetCharset( | 194 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetCharset( |
| 176 JNIEnv* env, | 195 JNIEnv* env, |
| 177 net::URLRequest* request, | 196 net::URLRequest* request, |
| 178 android_webview::InputStream* stream, | 197 android_webview::InputStream* stream, |
| 179 std::string* charset) { | 198 std::string* charset) { |
| 180 // TODO: We should probably be getting this from the managed side. | 199 // TODO: We should probably be getting this from the managed side. |
| 181 return false; | 200 return false; |
| 182 } | 201 } |
| 183 | 202 |
| 184 AssetFileProtocolInterceptor::AssetFileProtocolInterceptor() | 203 // AndroidProtocolHandlerBase ------------------------------------------------- |
| 204 | |
| 205 net::URLRequestJob* AndroidProtocolHandlerBase::MaybeCreateJob( | |
| 206 net::URLRequest* request, | |
| 207 net::NetworkDelegate* network_delegate) const { | |
| 208 if (!CanHandleRequest(request)) return NULL; | |
| 209 | |
| 210 // For WebViewClassic compatibility this job can only accept URLs that can be | |
| 211 // opened. URLs that cannot be opened should be resolved by the next handler. | |
| 212 // | |
| 213 // If a request is initially handled here but the job fails due to it being | |
| 214 // unable to open the InputStream for that request the request is marked as | |
| 215 // previously failed and restarted. | |
| 216 // Restarting a request involves creating a new job for that request. This | |
| 217 // handler will ignore requests know to have previously failed to 1) prevent | |
| 218 // an infinite loop, 2) ensure that the next handler in line gets the | |
| 219 // opportunity to create a job for the request. | |
| 220 if (HasRequestPreviouslyFailed(request)) return NULL; | |
| 221 | |
| 222 scoped_ptr<AndroidStreamReaderURLRequestJobDelegateImpl> reader_delegate( | |
| 223 new AndroidStreamReaderURLRequestJobDelegateImpl()); | |
| 224 | |
| 225 return new AndroidStreamReaderURLRequestJob( | |
| 226 request, | |
| 227 network_delegate, | |
| 228 reader_delegate.PassAs<AndroidStreamReaderURLRequestJob::Delegate>()); | |
| 229 } | |
| 230 | |
| 231 // AssetFileProtocolHandler --------------------------------------------------- | |
| 232 | |
| 233 AssetFileProtocolHandler::AssetFileProtocolHandler() | |
| 185 : asset_prefix_(std::string(chrome::kFileScheme) + | 234 : asset_prefix_(std::string(chrome::kFileScheme) + |
| 186 std::string(content::kStandardSchemeSeparator) + | 235 std::string(content::kStandardSchemeSeparator) + |
| 187 android_webview::kAndroidAssetPath), | 236 android_webview::kAndroidAssetPath), |
| 188 resource_prefix_(std::string(chrome::kFileScheme) + | 237 resource_prefix_(std::string(chrome::kFileScheme) + |
| 189 std::string(content::kStandardSchemeSeparator) + | 238 std::string(content::kStandardSchemeSeparator) + |
| 190 android_webview::kAndroidResourcePath) { | 239 android_webview::kAndroidResourcePath) { |
| 191 } | 240 } |
| 192 | 241 |
| 193 AssetFileProtocolInterceptor::~AssetFileProtocolInterceptor() { | 242 AssetFileProtocolHandler::~AssetFileProtocolHandler() { |
| 194 } | 243 } |
| 195 | 244 |
| 196 // static | 245 bool AssetFileProtocolHandler::CanHandleRequest( |
| 197 scoped_ptr<net::URLRequestJobFactory> | 246 const net::URLRequest* request) const { |
| 198 AssetFileProtocolInterceptor::CreateURLRequestJobFactory( | 247 if (!request->url().SchemeIsFile()) |
| 199 scoped_ptr<net::URLRequestJobFactory> base_job_factory) { | 248 return false; |
| 200 scoped_ptr<net::URLRequestJobFactory> top_job_factory( | |
| 201 new net::ProtocolInterceptJobFactory( | |
| 202 base_job_factory.Pass(), | |
| 203 scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>( | |
| 204 new AssetFileProtocolInterceptor()))); | |
| 205 return top_job_factory.Pass(); | |
| 206 } | |
| 207 | |
| 208 net::URLRequestJob* AssetFileProtocolInterceptor::MaybeCreateJob( | |
| 209 net::URLRequest* request, net::NetworkDelegate* network_delegate) const { | |
| 210 if (!request->url().SchemeIsFile()) return NULL; | |
| 211 | 249 |
| 212 const std::string& url = request->url().spec(); | 250 const std::string& url = request->url().spec(); |
| 213 if (!StartsWithASCII(url, asset_prefix_, /*case_sensitive=*/ true) && | 251 if (!StartsWithASCII(url, asset_prefix_, /*case_sensitive=*/ true) && |
| 214 !StartsWithASCII(url, resource_prefix_, /*case_sensitive=*/ true)) { | 252 !StartsWithASCII(url, resource_prefix_, /*case_sensitive=*/ true)) { |
| 215 return NULL; | 253 return false; |
| 216 } | 254 } |
| 217 | 255 |
| 218 return new AndroidStreamReaderURLRequestJob( | 256 return true; |
| 219 request, | 257 } |
| 220 network_delegate, | 258 |
| 221 scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>( | 259 // ContentSchemeProtocolHandler ----------------------------------------------- |
| 222 new AndroidStreamReaderURLRequestJobDelegateImpl())); | 260 |
| 261 ContentSchemeProtocolHandler::ContentSchemeProtocolHandler() { | |
| 262 } | |
| 263 | |
| 264 bool ContentSchemeProtocolHandler::CanHandleRequest( | |
| 265 const net::URLRequest* request) const { | |
| 266 return request->url().SchemeIs(android_webview::kContentScheme); | |
| 223 } | 267 } |
| 224 | 268 |
| 225 } // namespace | 269 } // namespace |
| 226 | 270 |
| 227 namespace android_webview { | 271 namespace android_webview { |
| 228 | 272 |
| 229 bool RegisterAndroidProtocolHandler(JNIEnv* env) { | 273 bool RegisterAndroidProtocolHandler(JNIEnv* env) { |
| 230 return RegisterNativesImpl(env); | 274 return RegisterNativesImpl(env); |
| 231 } | 275 } |
| 232 | 276 |
| 233 // static | 277 // static |
| 234 scoped_ptr<net::URLRequestJobFactory> CreateAndroidRequestJobFactory( | 278 scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> |
| 235 scoped_ptr<AwURLRequestJobFactory> job_factory) { | 279 CreateContentSchemeProtocolHandler() { |
| 236 // Register content://. Note that even though a scheme is | 280 return make_scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>( |
| 237 // registered here, it cannot be used by child processes until access to it is | 281 new ContentSchemeProtocolHandler()); |
| 238 // granted via ChildProcessSecurityPolicy::GrantScheme(). This is done in | 282 } |
| 239 // AwContentBrowserClient. | 283 |
| 240 // The job factory takes ownership of the handler. | 284 // static |
| 241 bool set_protocol = job_factory->SetProtocolHandler( | 285 scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> |
| 242 android_webview::kContentScheme, new ContentSchemeProtocolHandler()); | 286 CreateAssetFileProtocolHandler() { |
| 243 DCHECK(set_protocol); | 287 return make_scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>( |
| 244 return AssetFileProtocolInterceptor::CreateURLRequestJobFactory( | 288 new AssetFileProtocolHandler()); |
| 245 job_factory.PassAs<net::URLRequestJobFactory>()); | |
| 246 } | 289 } |
| 247 | 290 |
| 248 // Set a context object to be used for resolving resource queries. This can | 291 // Set a context object to be used for resolving resource queries. This can |
| 249 // be used to override the default application context and redirect all | 292 // be used to override the default application context and redirect all |
| 250 // resource queries to a specific context object, e.g., for the purposes of | 293 // resource queries to a specific context object, e.g., for the purposes of |
| 251 // testing. | 294 // testing. |
| 252 // | 295 // |
| 253 // |context| should be a android.content.Context instance or NULL to enable | 296 // |context| should be a android.content.Context instance or NULL to enable |
| 254 // the use of the standard application context. | 297 // the use of the standard application context. |
| 255 static void SetResourceContextForTesting(JNIEnv* env, jclass /*clazz*/, | 298 static void SetResourceContextForTesting(JNIEnv* env, jclass /*clazz*/, |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 267 env, android_webview::kAndroidAssetPath).Release(); | 310 env, android_webview::kAndroidAssetPath).Release(); |
| 268 } | 311 } |
| 269 | 312 |
| 270 static jstring GetAndroidResourcePath(JNIEnv* env, jclass /*clazz*/) { | 313 static jstring GetAndroidResourcePath(JNIEnv* env, jclass /*clazz*/) { |
| 271 // OK to release, JNI binding. | 314 // OK to release, JNI binding. |
| 272 return ConvertUTF8ToJavaString( | 315 return ConvertUTF8ToJavaString( |
| 273 env, android_webview::kAndroidResourcePath).Release(); | 316 env, android_webview::kAndroidResourcePath).Release(); |
| 274 } | 317 } |
| 275 | 318 |
| 276 } // namespace android_webview | 319 } // namespace android_webview |
| OLD | NEW |