Linux: Depend on liberation-fonts package for RPMs.
[chromium-blink-merge.git] / android_webview / native / android_protocol_handler.cc
blob159534d4f02b96e8fc113292e0fa98401bf6cab3
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.
5 #include "android_webview/native/android_protocol_handler.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"
9 #include "android_webview/common/url_constants.h"
10 #include "android_webview/native/input_stream_impl.h"
11 #include "base/android/jni_android.h"
12 #include "base/android/jni_string.h"
13 #include "base/android/jni_weak_ref.h"
14 #include "content/public/common/url_constants.h"
15 #include "jni/AndroidProtocolHandler_jni.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/mime_util.h"
18 #include "net/base/net_errors.h"
19 #include "net/base/net_util.h"
20 #include "net/http/http_util.h"
21 #include "net/url_request/url_request.h"
22 #include "net/url_request/url_request_interceptor.h"
23 #include "url/gurl.h"
24 #include "url/url_constants.h"
26 using android_webview::AndroidStreamReaderURLRequestJob;
27 using android_webview::InputStream;
28 using android_webview::InputStreamImpl;
29 using base::android::AttachCurrentThread;
30 using base::android::ClearException;
31 using base::android::ConvertUTF8ToJavaString;
32 using base::android::ScopedJavaGlobalRef;
33 using base::android::ScopedJavaLocalRef;
35 namespace {
37 // Override resource context for reading resource and asset files. Used for
38 // testing.
39 JavaObjectWeakGlobalRef* g_resource_context = NULL;
41 void ResetResourceContext(JavaObjectWeakGlobalRef* ref) {
42 if (g_resource_context)
43 delete g_resource_context;
45 g_resource_context = ref;
48 void* kPreviouslyFailedKey = &kPreviouslyFailedKey;
50 void MarkRequestAsFailed(net::URLRequest* request) {
51 request->SetUserData(kPreviouslyFailedKey,
52 new base::SupportsUserData::Data());
55 bool HasRequestPreviouslyFailed(net::URLRequest* request) {
56 return request->GetUserData(kPreviouslyFailedKey) != NULL;
59 class AndroidStreamReaderURLRequestJobDelegateImpl
60 : public AndroidStreamReaderURLRequestJob::Delegate {
61 public:
62 AndroidStreamReaderURLRequestJobDelegateImpl();
64 scoped_ptr<InputStream> OpenInputStream(JNIEnv* env,
65 const GURL& url) override;
67 void OnInputStreamOpenFailed(net::URLRequest* request,
68 bool* restart) override;
70 bool GetMimeType(JNIEnv* env,
71 net::URLRequest* request,
72 InputStream* stream,
73 std::string* mime_type) override;
75 bool GetCharset(JNIEnv* env,
76 net::URLRequest* request,
77 InputStream* stream,
78 std::string* charset) override;
80 void AppendResponseHeaders(JNIEnv* env,
81 net::HttpResponseHeaders* headers) override;
83 ~AndroidStreamReaderURLRequestJobDelegateImpl() override;
86 class AndroidRequestInterceptorBase : public net::URLRequestInterceptor {
87 public:
88 net::URLRequestJob* MaybeInterceptRequest(
89 net::URLRequest* request,
90 net::NetworkDelegate* network_delegate) const override;
92 virtual bool ShouldHandleRequest(const net::URLRequest* request) const = 0;
95 class AssetFileRequestInterceptor : public AndroidRequestInterceptorBase {
96 public:
97 AssetFileRequestInterceptor();
98 bool ShouldHandleRequest(const net::URLRequest* request) const override;
101 // Protocol handler for content:// scheme requests.
102 class ContentSchemeRequestInterceptor : public AndroidRequestInterceptorBase {
103 public:
104 ContentSchemeRequestInterceptor();
105 bool ShouldHandleRequest(const net::URLRequest* request) const override;
108 static ScopedJavaLocalRef<jobject> GetResourceContext(JNIEnv* env) {
109 if (g_resource_context)
110 return g_resource_context->get(env);
111 ScopedJavaLocalRef<jobject> context;
112 // We have to reset as GetApplicationContext() returns a jobject with a
113 // global ref. The constructor that takes a jobject would expect a local ref
114 // and would assert.
115 context.Reset(env, base::android::GetApplicationContext());
116 return context;
119 // AndroidStreamReaderURLRequestJobDelegateImpl -------------------------------
121 AndroidStreamReaderURLRequestJobDelegateImpl::
122 AndroidStreamReaderURLRequestJobDelegateImpl() {}
124 AndroidStreamReaderURLRequestJobDelegateImpl::
125 ~AndroidStreamReaderURLRequestJobDelegateImpl() {
128 scoped_ptr<InputStream>
129 AndroidStreamReaderURLRequestJobDelegateImpl::OpenInputStream(
130 JNIEnv* env, const GURL& url) {
131 DCHECK(url.is_valid());
132 DCHECK(env);
134 // Open the input stream.
135 ScopedJavaLocalRef<jstring> jurl =
136 ConvertUTF8ToJavaString(env, url.spec());
137 ScopedJavaLocalRef<jobject> stream =
138 android_webview::Java_AndroidProtocolHandler_open(
139 env,
140 GetResourceContext(env).obj(),
141 jurl.obj());
143 if (stream.is_null()) {
144 DLOG(ERROR) << "Unable to open input stream for Android URL";
145 return scoped_ptr<InputStream>();
147 return make_scoped_ptr<InputStream>(new InputStreamImpl(stream));
150 void AndroidStreamReaderURLRequestJobDelegateImpl::OnInputStreamOpenFailed(
151 net::URLRequest* request,
152 bool* restart) {
153 DCHECK(!HasRequestPreviouslyFailed(request));
154 MarkRequestAsFailed(request);
155 *restart = true;
158 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetMimeType(
159 JNIEnv* env,
160 net::URLRequest* request,
161 android_webview::InputStream* stream,
162 std::string* mime_type) {
163 DCHECK(env);
164 DCHECK(request);
165 DCHECK(mime_type);
167 // Query the mime type from the Java side. It is possible for the query to
168 // fail, as the mime type cannot be determined for all supported schemes.
169 ScopedJavaLocalRef<jstring> url =
170 ConvertUTF8ToJavaString(env, request->url().spec());
171 const InputStreamImpl* stream_impl =
172 InputStreamImpl::FromInputStream(stream);
173 ScopedJavaLocalRef<jstring> returned_type =
174 android_webview::Java_AndroidProtocolHandler_getMimeType(
175 env,
176 GetResourceContext(env).obj(),
177 stream_impl->jobj(), url.obj());
178 if (returned_type.is_null())
179 return false;
181 *mime_type = base::android::ConvertJavaStringToUTF8(returned_type);
182 return true;
185 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetCharset(
186 JNIEnv* env,
187 net::URLRequest* request,
188 android_webview::InputStream* stream,
189 std::string* charset) {
190 // TODO: We should probably be getting this from the managed side.
191 return false;
194 void AndroidStreamReaderURLRequestJobDelegateImpl::AppendResponseHeaders(
195 JNIEnv* env,
196 net::HttpResponseHeaders* headers) {
197 // no-op
200 // AndroidRequestInterceptorBase ----------------------------------------------
202 net::URLRequestJob* AndroidRequestInterceptorBase::MaybeInterceptRequest(
203 net::URLRequest* request,
204 net::NetworkDelegate* network_delegate) const {
205 if (!ShouldHandleRequest(request))
206 return NULL;
208 // For WebViewClassic compatibility this job can only accept URLs that can be
209 // opened. URLs that cannot be opened should be resolved by the next handler.
211 // If a request is initially handled here but the job fails due to it being
212 // unable to open the InputStream for that request the request is marked as
213 // previously failed and restarted.
214 // Restarting a request involves creating a new job for that request. This
215 // handler will ignore requests know to have previously failed to 1) prevent
216 // an infinite loop, 2) ensure that the next handler in line gets the
217 // opportunity to create a job for the request.
218 if (HasRequestPreviouslyFailed(request))
219 return NULL;
221 scoped_ptr<AndroidStreamReaderURLRequestJobDelegateImpl> reader_delegate(
222 new AndroidStreamReaderURLRequestJobDelegateImpl());
224 return new AndroidStreamReaderURLRequestJob(
225 request, network_delegate, reader_delegate.Pass());
228 // AssetFileRequestInterceptor ------------------------------------------------
230 AssetFileRequestInterceptor::AssetFileRequestInterceptor() {
233 bool AssetFileRequestInterceptor::ShouldHandleRequest(
234 const net::URLRequest* request) const {
235 return android_webview::IsAndroidSpecialFileUrl(request->url());
238 // ContentSchemeRequestInterceptor --------------------------------------------
240 ContentSchemeRequestInterceptor::ContentSchemeRequestInterceptor() {
243 bool ContentSchemeRequestInterceptor::ShouldHandleRequest(
244 const net::URLRequest* request) const {
245 return request->url().SchemeIs(url::kContentScheme);
248 } // namespace
250 namespace android_webview {
252 bool RegisterAndroidProtocolHandler(JNIEnv* env) {
253 return RegisterNativesImpl(env);
256 // static
257 scoped_ptr<net::URLRequestInterceptor>
258 CreateContentSchemeRequestInterceptor() {
259 return make_scoped_ptr<net::URLRequestInterceptor>(
260 new ContentSchemeRequestInterceptor());
263 // static
264 scoped_ptr<net::URLRequestInterceptor> CreateAssetFileRequestInterceptor() {
265 return scoped_ptr<net::URLRequestInterceptor>(
266 new AssetFileRequestInterceptor());
269 // Set a context object to be used for resolving resource queries. This can
270 // be used to override the default application context and redirect all
271 // resource queries to a specific context object, e.g., for the purposes of
272 // testing.
274 // |context| should be a android.content.Context instance or NULL to enable
275 // the use of the standard application context.
276 static void SetResourceContextForTesting(JNIEnv* env,
277 const JavaParamRef<jclass>& /*clazz*/,
278 const JavaParamRef<jobject>& context) {
279 if (context) {
280 ResetResourceContext(new JavaObjectWeakGlobalRef(env, context));
281 } else {
282 ResetResourceContext(NULL);
286 static ScopedJavaLocalRef<jstring> GetAndroidAssetPath(
287 JNIEnv* env,
288 const JavaParamRef<jclass>& /*clazz*/) {
289 return ConvertUTF8ToJavaString(env, android_webview::kAndroidAssetPath);
292 static ScopedJavaLocalRef<jstring> GetAndroidResourcePath(
293 JNIEnv* env,
294 const JavaParamRef<jclass>& /*clazz*/) {
295 return ConvertUTF8ToJavaString(env, android_webview::kAndroidResourcePath);
298 } // namespace android_webview