OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 // URL request job for reading from resources and assets. |
| 6 |
| 7 #include "chrome/browser/android/android_protocol_adapter.h" |
| 8 |
| 9 #include "base/android/jni_android.h" |
| 10 #include "base/android/jni_helper.h" |
| 11 #include "base/android/jni_string.h" |
| 12 #include "base/string_util.h" |
| 13 #include "chrome/browser/android/android_stream_reader_url_request_job.h" |
| 14 #include "chrome/common/url_constants.h" |
| 15 #include "googleurl/src/gurl.h" |
| 16 #include "jni/AndroidProtocolAdapter_jni.h" |
| 17 #include "net/base/io_buffer.h" |
| 18 #include "net/base/mime_util.h" |
| 19 #include "net/base/net_errors.h" |
| 20 #include "net/base/net_util.h" |
| 21 #include "net/http/http_util.h" |
| 22 #include "net/url_request/url_request_error_job.h" |
| 23 #include "net/url_request/url_request_file_job.h" |
| 24 #include "net/url_request/url_request_job_manager.h" |
| 25 |
| 26 using base::android::AttachCurrentThread; |
| 27 using base::android::ClearException; |
| 28 using base::android::ConvertUTF8ToJavaString; |
| 29 using base::android::ScopedJavaGlobalRef; |
| 30 using base::android::ScopedJavaLocalRef; |
| 31 |
| 32 namespace { |
| 33 |
| 34 // Override resource context for reading resource and asset files. Used for |
| 35 // testing. |
| 36 JavaObjectWeakGlobalRef* g_resource_context = NULL; |
| 37 |
| 38 void ResetResourceContext(JavaObjectWeakGlobalRef* ref) { |
| 39 if (g_resource_context) |
| 40 delete g_resource_context; |
| 41 |
| 42 g_resource_context = ref; |
| 43 } |
| 44 |
| 45 class AndroidStreamReaderURLRequestJobDelegateImpl |
| 46 : public AndroidStreamReaderURLRequestJob::Delegate { |
| 47 public: |
| 48 AndroidStreamReaderURLRequestJobDelegateImpl(); |
| 49 |
| 50 virtual ScopedJavaLocalRef<jobject> OpenInputStream( |
| 51 JNIEnv* env, |
| 52 net::URLRequest* request) OVERRIDE; |
| 53 |
| 54 virtual bool GetMimeType(JNIEnv* env, |
| 55 net::URLRequest* request, |
| 56 jobject stream, |
| 57 std::string* mime_type) OVERRIDE; |
| 58 |
| 59 virtual bool GetCharset(JNIEnv* env, |
| 60 net::URLRequest* request, |
| 61 jobject stream, |
| 62 std::string* charset) OVERRIDE; |
| 63 |
| 64 virtual ~AndroidStreamReaderURLRequestJobDelegateImpl(); |
| 65 }; |
| 66 |
| 67 |
| 68 } // namespace |
| 69 |
| 70 static bool InitJNIBindings(JNIEnv* env) { |
| 71 return RegisterNativesImpl(env) && |
| 72 AndroidStreamReaderURLRequestJob::InitJNIBindings(env); |
| 73 } |
| 74 |
| 75 // static |
| 76 net::URLRequestJob* AndroidProtocolAdapter::Factory( |
| 77 net::URLRequest* request, const std::string& scheme) { |
| 78 DCHECK(scheme == chrome::kFileScheme || |
| 79 scheme == chrome::kContentScheme); |
| 80 JNIEnv* env = AttachCurrentThread(); |
| 81 DCHECK(env); |
| 82 // If this is a file:// URL we cannot handle, fall back to the default |
| 83 // handler. |
| 84 const std::string& url = request->url().spec(); |
| 85 std::string assetPrefix = std::string(chrome::kFileScheme) + "://" + |
| 86 chrome::kAndroidAssetPath; |
| 87 std::string resourcePrefix = std::string(chrome::kFileScheme) + "://" + |
| 88 chrome::kAndroidResourcePath; |
| 89 |
| 90 if (scheme == chrome::kFileScheme && |
| 91 !StartsWithASCII(url, assetPrefix, /*case_sensitive=*/ true) && |
| 92 !StartsWithASCII(url, resourcePrefix, /*case_sensitive=*/ true)) { |
| 93 return net::URLRequestFileJob::Factory(request, scheme); |
| 94 } |
| 95 |
| 96 return new AndroidStreamReaderURLRequestJob( |
| 97 request, |
| 98 scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>( |
| 99 new AndroidStreamReaderURLRequestJobDelegateImpl())); |
| 100 } |
| 101 |
| 102 // static |
| 103 bool AndroidProtocolAdapter::RegisterProtocols(JNIEnv* env) { |
| 104 DCHECK(env); |
| 105 |
| 106 if (!InitJNIBindings(env)) |
| 107 return false; |
| 108 |
| 109 // Register content:// and file://. Note that even though a scheme is |
| 110 // registered here, it cannot be used by child processes until access to it is |
| 111 // granted via ChildProcessSecurityPolicy::GrantScheme(). This is done in |
| 112 // RenderViewHost. |
| 113 net::URLRequestJobManager* job_manager = |
| 114 net::URLRequestJobManager::GetInstance(); |
| 115 job_manager->RegisterProtocolFactory(chrome::kContentScheme, |
| 116 &AndroidProtocolAdapter::Factory); |
| 117 job_manager->RegisterProtocolFactory( |
| 118 chrome::kFileScheme, &AndroidProtocolAdapter::Factory); |
| 119 |
| 120 return true; |
| 121 } |
| 122 |
| 123 // Set a context object to be used for resolving resource queries. This can |
| 124 // be used to override the default application context and redirect all |
| 125 // resource queries to a specific context object, e.g., for the purposes of |
| 126 // testing. |
| 127 // |
| 128 // |context| should be a android.content.Context instance or NULL to enable |
| 129 // the use of the standard application context. |
| 130 static void SetResourceContextForTesting(JNIEnv* env, jclass /*clazz*/, |
| 131 jobject context) { |
| 132 if (context) { |
| 133 ResetResourceContext(new JavaObjectWeakGlobalRef(env, context)); |
| 134 } else { |
| 135 ResetResourceContext(NULL); |
| 136 } |
| 137 } |
| 138 |
| 139 static jstring GetAndroidAssetPath(JNIEnv* env, jclass /*clazz*/) { |
| 140 // OK to release, JNI binding. |
| 141 return ConvertUTF8ToJavaString(env, chrome::kAndroidAssetPath).Release(); |
| 142 } |
| 143 |
| 144 static jstring GetAndroidResourcePath(JNIEnv* env, jclass /*clazz*/) { |
| 145 // OK to release, JNI binding. |
| 146 return ConvertUTF8ToJavaString(env, chrome::kAndroidResourcePath).Release(); |
| 147 } |
| 148 |
| 149 static ScopedJavaLocalRef<jobject> GetResourceContext(JNIEnv* env) { |
| 150 if (g_resource_context) |
| 151 return g_resource_context->get(env); |
| 152 ScopedJavaLocalRef<jobject> context; |
| 153 // We have to reset as GetApplicationContext() returns a jobject with a |
| 154 // global ref. The constructor that takes a jobject would expect a local ref |
| 155 // and would assert. |
| 156 context.Reset(env, base::android::GetApplicationContext()); |
| 157 return context; |
| 158 } |
| 159 |
| 160 AndroidStreamReaderURLRequestJobDelegateImpl:: |
| 161 AndroidStreamReaderURLRequestJobDelegateImpl() { |
| 162 } |
| 163 |
| 164 AndroidStreamReaderURLRequestJobDelegateImpl:: |
| 165 ~AndroidStreamReaderURLRequestJobDelegateImpl() { |
| 166 } |
| 167 |
| 168 ScopedJavaLocalRef<jobject> |
| 169 AndroidStreamReaderURLRequestJobDelegateImpl::OpenInputStream( |
| 170 JNIEnv* env, net::URLRequest* request) { |
| 171 DCHECK(request); |
| 172 DCHECK(env); |
| 173 |
| 174 // Open the input stream. |
| 175 ScopedJavaLocalRef<jstring> url = |
| 176 ConvertUTF8ToJavaString(env, request->url().spec()); |
| 177 ScopedJavaLocalRef<jobject> stream = Java_AndroidProtocolAdapter_open( |
| 178 env, |
| 179 GetResourceContext(env).obj(), |
| 180 url.obj()); |
| 181 |
| 182 // Check and clear pending exceptions. |
| 183 if (ClearException(env) || stream.is_null()) { |
| 184 DLOG(ERROR) << "Unable to open input stream for Android URL"; |
| 185 return ScopedJavaLocalRef<jobject>(env, NULL); |
| 186 } |
| 187 return stream; |
| 188 } |
| 189 |
| 190 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetMimeType( |
| 191 JNIEnv* env, |
| 192 net::URLRequest* request, |
| 193 jobject stream, |
| 194 std::string* mime_type) { |
| 195 DCHECK(env); |
| 196 DCHECK(request); |
| 197 DCHECK(mime_type); |
| 198 |
| 199 if (!stream) |
| 200 return false; |
| 201 |
| 202 // Query the mime type from the Java side. It is possible for the query to |
| 203 // fail, as the mime type cannot be determined for all supported schemes. |
| 204 ScopedJavaLocalRef<jstring> url = |
| 205 ConvertUTF8ToJavaString(env, request->url().spec()); |
| 206 ScopedJavaLocalRef<jstring> returned_type = |
| 207 Java_AndroidProtocolAdapter_getMimeType(env, |
| 208 GetResourceContext(env).obj(), |
| 209 stream, url.obj()); |
| 210 if (ClearException(env) || returned_type.is_null()) |
| 211 return false; |
| 212 |
| 213 *mime_type = base::android::ConvertJavaStringToUTF8(returned_type); |
| 214 return true; |
| 215 } |
| 216 |
| 217 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetCharset( |
| 218 JNIEnv* env, |
| 219 net::URLRequest* request, |
| 220 jobject stream, |
| 221 std::string* charset) { |
| 222 // TODO: We should probably be getting this from the managed side. |
| 223 return false; |
| 224 } |
OLD | NEW |