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 data from an Android Java InputStream. |
| 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 "chrome/browser/android/android_stream_reader_url_request_job.h" |
| 13 #include "content/public/common/url_constants.h" |
| 14 #include "googleurl/src/gurl.h" |
| 15 #include "net/base/io_buffer.h" |
| 16 #include "net/base/mime_util.h" |
| 17 #include "net/base/net_errors.h" |
| 18 #include "net/base/net_util.h" |
| 19 #include "net/http/http_util.h" |
| 20 #include "net/url_request/url_request.h" |
| 21 #include "net/url_request/url_request_error_job.h" |
| 22 #include "net/url_request/url_request_file_job.h" |
| 23 #include "net/url_request/url_request_job_manager.h" |
| 24 #include "jni/AndroidProtocolAdapter_jni.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 == content::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 content::kAndroidAssetPath; |
| 87 std::string resourcePrefix = std::string(chrome::kFileScheme) + "://" + |
| 88 content::kAndroidResourcePath; |
| 89 if (scheme == chrome::kFileScheme && url.find(assetPrefix) != 0 && |
| 90 url.find(resourcePrefix) != 0) { |
| 91 return net::URLRequestFileJob::Factory(request, scheme); |
| 92 } |
| 93 |
| 94 return new AndroidStreamReaderURLRequestJob( |
| 95 request, |
| 96 scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>( |
| 97 new AndroidStreamReaderURLRequestJobDelegateImpl())); |
| 98 } |
| 99 |
| 100 // static |
| 101 bool AndroidProtocolAdapter::RegisterProtocols(JNIEnv* env) { |
| 102 DCHECK(env); |
| 103 |
| 104 if (!InitJNIBindings(env)) |
| 105 return false; |
| 106 |
| 107 // Register content:// and file://. Note that even though a scheme is |
| 108 // registered here, it cannot be used by child processes until access to it is |
| 109 // granted via ChildProcessSecurityPolicy::GrantScheme(). This is done in |
| 110 // RenderViewHost. |
| 111 net::URLRequestJobManager* job_manager = |
| 112 net::URLRequestJobManager::GetInstance(); |
| 113 job_manager->RegisterProtocolFactory(content::kContentScheme, |
| 114 &AndroidProtocolAdapter::Factory); |
| 115 job_manager->RegisterProtocolFactory( |
| 116 chrome::kFileScheme, &AndroidProtocolAdapter::Factory); |
| 117 |
| 118 return true; |
| 119 } |
| 120 |
| 121 // Set a context object to be used for resolving resource queries. This can |
| 122 // be used to override the default application context and redirect all |
| 123 // resource queries to a specific context object, e.g., for the purposes of |
| 124 // testing. |
| 125 // |
| 126 // |context| should be a android.content.Context instance or NULL to enable |
| 127 // the use of the standard application context. |
| 128 static void SetResourceContext(JNIEnv* env, jclass /*clazz*/, jobject context) { |
| 129 if (context) { |
| 130 ResetResourceContext(new JavaObjectWeakGlobalRef(env, context)); |
| 131 } else { |
| 132 ResetResourceContext(NULL); |
| 133 } |
| 134 } |
| 135 |
| 136 static jstring GetAndroidAssetPath(JNIEnv* env, jclass /*clazz*/) { |
| 137 // OK to release, JNI binding. |
| 138 return ConvertUTF8ToJavaString(env, content::kAndroidAssetPath).Release(); |
| 139 } |
| 140 |
| 141 static jstring GetAndroidResourcePath(JNIEnv* env, jclass /*clazz*/) { |
| 142 // OK to release, JNI binding. |
| 143 return ConvertUTF8ToJavaString(env, content::kAndroidResourcePath).Release(); |
| 144 } |
| 145 |
| 146 static ScopedJavaLocalRef<jobject> GetResourceContext(JNIEnv* env) { |
| 147 if (g_resource_context) |
| 148 return g_resource_context->get(env); |
| 149 ScopedJavaLocalRef<jobject> context; |
| 150 // We have to reset as GetApplicationContext() returns a jobject with a |
| 151 // global ref. The constructor that takes a jobject would expect a local ref |
| 152 // and would assert. |
| 153 context.Reset(env, base::android::GetApplicationContext()); |
| 154 return context; |
| 155 } |
| 156 |
| 157 AndroidStreamReaderURLRequestJobDelegateImpl:: |
| 158 AndroidStreamReaderURLRequestJobDelegateImpl() { |
| 159 } |
| 160 |
| 161 AndroidStreamReaderURLRequestJobDelegateImpl:: |
| 162 ~AndroidStreamReaderURLRequestJobDelegateImpl() { |
| 163 } |
| 164 |
| 165 ScopedJavaLocalRef<jobject> |
| 166 AndroidStreamReaderURLRequestJobDelegateImpl::OpenInputStream( |
| 167 JNIEnv* env, net::URLRequest* request) { |
| 168 DCHECK(request); |
| 169 DCHECK(env); |
| 170 |
| 171 // Open the input stream. |
| 172 ScopedJavaLocalRef<jstring> url = |
| 173 ConvertUTF8ToJavaString(env, request->url().spec()); |
| 174 ScopedJavaLocalRef<jobject> stream = Java_AndroidProtocolAdapter_open( |
| 175 env, |
| 176 GetResourceContext(env).obj(), |
| 177 url.obj()); |
| 178 |
| 179 // Check and clear pending exceptions. |
| 180 if (ClearException(env) || stream.is_null()) { |
| 181 DLOG(ERROR) << "Unable to open input stream for Android URL"; |
| 182 return ScopedJavaLocalRef<jobject>(env, NULL); |
| 183 } |
| 184 return stream; |
| 185 } |
| 186 |
| 187 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetMimeType( |
| 188 JNIEnv* env, |
| 189 net::URLRequest* request, |
| 190 jobject stream, |
| 191 std::string* mime_type) { |
| 192 DCHECK(env); |
| 193 DCHECK(request); |
| 194 DCHECK(mime_type); |
| 195 |
| 196 if (!stream) |
| 197 return false; |
| 198 |
| 199 // Query the mime type from the Java side. It is possible for the query to |
| 200 // fail, as the mime type cannot be determined for all supported schemes. |
| 201 ScopedJavaLocalRef<jstring> url = |
| 202 ConvertUTF8ToJavaString(env, request->url().spec()); |
| 203 ScopedJavaLocalRef<jstring> returned_type = |
| 204 Java_AndroidProtocolAdapter_getMimeType(env, |
| 205 GetResourceContext(env).obj(), |
| 206 stream, url.obj()); |
| 207 if (ClearException(env) || returned_type.is_null()) |
| 208 return false; |
| 209 |
| 210 *mime_type = base::android::ConvertJavaStringToUTF8(returned_type); |
| 211 return true; |
| 212 } |
| 213 |
| 214 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetCharset( |
| 215 JNIEnv* env, |
| 216 net::URLRequest* request, |
| 217 jobject stream, |
| 218 std::string* charset) { |
| 219 // TODO: We should probably be getting this from the managed side. |
| 220 return false; |
| 221 } |
OLD | NEW |