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(); |
67 }; | 81 }; |
68 | 82 |
69 class AssetFileProtocolInterceptor : | 83 class AndroidProtocolHandlerBase : |
70 public net::URLRequestJobFactory::ProtocolHandler { | 84 public net::URLRequestJobFactory::ProtocolHandler { |
71 public: | 85 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( | 86 virtual net::URLRequestJob* MaybeCreateJob( |
76 net::URLRequest* request, | 87 net::URLRequest* request, |
77 net::NetworkDelegate* network_delegate) const OVERRIDE; | 88 net::NetworkDelegate* network_delegate) const OVERRIDE; |
78 | 89 |
| 90 virtual bool CanHandleRequest(const net::URLRequest* request) const = 0; |
| 91 }; |
| 92 |
| 93 class AssetFileProtocolHandler : public AndroidProtocolHandlerBase { |
| 94 public: |
| 95 AssetFileProtocolHandler(); |
| 96 |
| 97 virtual ~AssetFileProtocolHandler() OVERRIDE; |
| 98 virtual bool CanHandleRequest(const net::URLRequest* request) const OVERRIDE; |
| 99 |
79 private: | 100 private: |
80 AssetFileProtocolInterceptor(); | |
81 | |
82 // file:///android_asset/ | 101 // file:///android_asset/ |
83 const std::string asset_prefix_; | 102 const std::string asset_prefix_; |
84 // file:///android_res/ | 103 // file:///android_res/ |
85 const std::string resource_prefix_; | 104 const std::string resource_prefix_; |
86 }; | 105 }; |
87 | 106 |
88 // Protocol handler for content:// scheme requests. | 107 // Protocol handler for content:// scheme requests. |
89 class ContentSchemeProtocolHandler : | 108 class ContentSchemeProtocolHandler : public AndroidProtocolHandlerBase { |
90 public net::URLRequestJobFactory::ProtocolHandler { | |
91 public: | 109 public: |
92 ContentSchemeProtocolHandler() {} | 110 ContentSchemeProtocolHandler(); |
93 | 111 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 }; | 112 }; |
105 | 113 |
106 static ScopedJavaLocalRef<jobject> GetResourceContext(JNIEnv* env) { | 114 static ScopedJavaLocalRef<jobject> GetResourceContext(JNIEnv* env) { |
107 if (g_resource_context) | 115 if (g_resource_context) |
108 return g_resource_context->get(env); | 116 return g_resource_context->get(env); |
109 ScopedJavaLocalRef<jobject> context; | 117 ScopedJavaLocalRef<jobject> context; |
110 // We have to reset as GetApplicationContext() returns a jobject with a | 118 // 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 | 119 // global ref. The constructor that takes a jobject would expect a local ref |
112 // and would assert. | 120 // and would assert. |
113 context.Reset(env, base::android::GetApplicationContext()); | 121 context.Reset(env, base::android::GetApplicationContext()); |
114 return context; | 122 return context; |
115 } | 123 } |
116 | 124 |
| 125 // AndroidStreamReaderURLRequestJobDelegateImpl ------------------------------- |
| 126 |
117 AndroidStreamReaderURLRequestJobDelegateImpl:: | 127 AndroidStreamReaderURLRequestJobDelegateImpl:: |
118 AndroidStreamReaderURLRequestJobDelegateImpl() { | 128 AndroidStreamReaderURLRequestJobDelegateImpl() {} |
119 } | |
120 | 129 |
121 AndroidStreamReaderURLRequestJobDelegateImpl:: | 130 AndroidStreamReaderURLRequestJobDelegateImpl:: |
122 ~AndroidStreamReaderURLRequestJobDelegateImpl() { | 131 ~AndroidStreamReaderURLRequestJobDelegateImpl() { |
123 } | 132 } |
124 | 133 |
125 scoped_ptr<InputStream> | 134 scoped_ptr<InputStream> |
126 AndroidStreamReaderURLRequestJobDelegateImpl::OpenInputStream( | 135 AndroidStreamReaderURLRequestJobDelegateImpl::OpenInputStream( |
127 JNIEnv* env, net::URLRequest* request) { | 136 JNIEnv* env, const GURL& url) { |
128 DCHECK(request); | 137 DCHECK(url.is_valid()); |
129 DCHECK(env); | 138 DCHECK(env); |
130 | 139 |
131 // Open the input stream. | 140 // Open the input stream. |
132 ScopedJavaLocalRef<jstring> url = | 141 ScopedJavaLocalRef<jstring> jurl = |
133 ConvertUTF8ToJavaString(env, request->url().spec()); | 142 ConvertUTF8ToJavaString(env, url.spec()); |
134 ScopedJavaLocalRef<jobject> stream = | 143 ScopedJavaLocalRef<jobject> stream = |
135 android_webview::Java_AndroidProtocolHandler_open( | 144 android_webview::Java_AndroidProtocolHandler_open( |
136 env, | 145 env, |
137 GetResourceContext(env).obj(), | 146 GetResourceContext(env).obj(), |
138 url.obj()); | 147 jurl.obj()); |
139 | 148 |
140 // Check and clear pending exceptions. | 149 // Check and clear pending exceptions. |
141 if (ClearException(env) || stream.is_null()) { | 150 if (ClearException(env) || stream.is_null()) { |
142 DLOG(ERROR) << "Unable to open input stream for Android URL"; | 151 DLOG(ERROR) << "Unable to open input stream for Android URL"; |
143 return scoped_ptr<InputStream>(); | 152 return scoped_ptr<InputStream>(); |
144 } | 153 } |
145 return make_scoped_ptr<InputStream>(new InputStreamImpl(stream)); | 154 return make_scoped_ptr<InputStream>(new InputStreamImpl(stream)); |
146 } | 155 } |
147 | 156 |
| 157 void AndroidStreamReaderURLRequestJobDelegateImpl::OnInputStreamOpenFailed( |
| 158 net::URLRequest* request, |
| 159 bool* restart) { |
| 160 DCHECK(!HasRequestPreviouslyFailed(request)); |
| 161 MarkRequestAsFailed(request); |
| 162 *restart = true; |
| 163 } |
| 164 |
148 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetMimeType( | 165 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetMimeType( |
149 JNIEnv* env, | 166 JNIEnv* env, |
150 net::URLRequest* request, | 167 net::URLRequest* request, |
151 android_webview::InputStream* stream, | 168 android_webview::InputStream* stream, |
152 std::string* mime_type) { | 169 std::string* mime_type) { |
153 DCHECK(env); | 170 DCHECK(env); |
154 DCHECK(request); | 171 DCHECK(request); |
155 DCHECK(mime_type); | 172 DCHECK(mime_type); |
156 | 173 |
157 // Query the mime type from the Java side. It is possible for the query to | 174 // Query the mime type from the Java side. It is possible for the query to |
(...skipping 16 matching lines...) Expand all Loading... |
174 | 191 |
175 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetCharset( | 192 bool AndroidStreamReaderURLRequestJobDelegateImpl::GetCharset( |
176 JNIEnv* env, | 193 JNIEnv* env, |
177 net::URLRequest* request, | 194 net::URLRequest* request, |
178 android_webview::InputStream* stream, | 195 android_webview::InputStream* stream, |
179 std::string* charset) { | 196 std::string* charset) { |
180 // TODO: We should probably be getting this from the managed side. | 197 // TODO: We should probably be getting this from the managed side. |
181 return false; | 198 return false; |
182 } | 199 } |
183 | 200 |
184 AssetFileProtocolInterceptor::AssetFileProtocolInterceptor() | 201 // AndroidProtocolHandlerBase ------------------------------------------------- |
| 202 |
| 203 net::URLRequestJob* AndroidProtocolHandlerBase::MaybeCreateJob( |
| 204 net::URLRequest* request, |
| 205 net::NetworkDelegate* network_delegate) const { |
| 206 if (!CanHandleRequest(request)) return NULL; |
| 207 |
| 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. |
| 210 // |
| 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)) return NULL; |
| 219 |
| 220 scoped_ptr<AndroidStreamReaderURLRequestJobDelegateImpl> reader_delegate( |
| 221 new AndroidStreamReaderURLRequestJobDelegateImpl()); |
| 222 |
| 223 return new AndroidStreamReaderURLRequestJob( |
| 224 request, |
| 225 network_delegate, |
| 226 reader_delegate.PassAs<AndroidStreamReaderURLRequestJob::Delegate>()); |
| 227 } |
| 228 |
| 229 // AssetFileProtocolHandler --------------------------------------------------- |
| 230 |
| 231 AssetFileProtocolHandler::AssetFileProtocolHandler() |
185 : asset_prefix_(std::string(chrome::kFileScheme) + | 232 : asset_prefix_(std::string(chrome::kFileScheme) + |
186 std::string(content::kStandardSchemeSeparator) + | 233 std::string(content::kStandardSchemeSeparator) + |
187 android_webview::kAndroidAssetPath), | 234 android_webview::kAndroidAssetPath), |
188 resource_prefix_(std::string(chrome::kFileScheme) + | 235 resource_prefix_(std::string(chrome::kFileScheme) + |
189 std::string(content::kStandardSchemeSeparator) + | 236 std::string(content::kStandardSchemeSeparator) + |
190 android_webview::kAndroidResourcePath) { | 237 android_webview::kAndroidResourcePath) { |
191 } | 238 } |
192 | 239 |
193 AssetFileProtocolInterceptor::~AssetFileProtocolInterceptor() { | 240 AssetFileProtocolHandler::~AssetFileProtocolHandler() { |
194 } | 241 } |
195 | 242 |
196 // static | 243 bool AssetFileProtocolHandler::CanHandleRequest( |
197 scoped_ptr<net::URLRequestJobFactory> | 244 const net::URLRequest* request) const { |
198 AssetFileProtocolInterceptor::CreateURLRequestJobFactory( | 245 if (!request->url().SchemeIsFile()) |
199 scoped_ptr<net::URLRequestJobFactory> base_job_factory) { | 246 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 | 247 |
212 const std::string& url = request->url().spec(); | 248 const std::string& url = request->url().spec(); |
213 if (!StartsWithASCII(url, asset_prefix_, /*case_sensitive=*/ true) && | 249 if (!StartsWithASCII(url, asset_prefix_, /*case_sensitive=*/ true) && |
214 !StartsWithASCII(url, resource_prefix_, /*case_sensitive=*/ true)) { | 250 !StartsWithASCII(url, resource_prefix_, /*case_sensitive=*/ true)) { |
215 return NULL; | 251 return false; |
216 } | 252 } |
217 | 253 |
218 return new AndroidStreamReaderURLRequestJob( | 254 return true; |
219 request, | 255 } |
220 network_delegate, | 256 |
221 scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>( | 257 // ContentSchemeProtocolHandler ----------------------------------------------- |
222 new AndroidStreamReaderURLRequestJobDelegateImpl())); | 258 |
| 259 ContentSchemeProtocolHandler::ContentSchemeProtocolHandler() { |
| 260 } |
| 261 |
| 262 bool ContentSchemeProtocolHandler::CanHandleRequest( |
| 263 const net::URLRequest* request) const { |
| 264 return request->url().SchemeIs(android_webview::kContentScheme); |
223 } | 265 } |
224 | 266 |
225 } // namespace | 267 } // namespace |
226 | 268 |
227 namespace android_webview { | 269 namespace android_webview { |
228 | 270 |
229 bool RegisterAndroidProtocolHandler(JNIEnv* env) { | 271 bool RegisterAndroidProtocolHandler(JNIEnv* env) { |
230 return RegisterNativesImpl(env); | 272 return RegisterNativesImpl(env); |
231 } | 273 } |
232 | 274 |
233 // static | 275 // static |
234 scoped_ptr<net::URLRequestJobFactory> CreateAndroidRequestJobFactory( | 276 scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> |
235 scoped_ptr<AwURLRequestJobFactory> job_factory) { | 277 CreateContentSchemeProtocolHandler() { |
236 // Register content://. Note that even though a scheme is | 278 return make_scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>( |
237 // registered here, it cannot be used by child processes until access to it is | 279 new ContentSchemeProtocolHandler()); |
238 // granted via ChildProcessSecurityPolicy::GrantScheme(). This is done in | 280 } |
239 // AwContentBrowserClient. | 281 |
240 // The job factory takes ownership of the handler. | 282 // static |
241 bool set_protocol = job_factory->SetProtocolHandler( | 283 scoped_ptr<net::URLRequestJobFactory::ProtocolHandler> |
242 android_webview::kContentScheme, new ContentSchemeProtocolHandler()); | 284 CreateAssetFileProtocolHandler() { |
243 DCHECK(set_protocol); | 285 return make_scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>( |
244 return AssetFileProtocolInterceptor::CreateURLRequestJobFactory( | 286 new AssetFileProtocolHandler()); |
245 job_factory.PassAs<net::URLRequestJobFactory>()); | |
246 } | 287 } |
247 | 288 |
248 // Set a context object to be used for resolving resource queries. This can | 289 // 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 | 290 // 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 | 291 // resource queries to a specific context object, e.g., for the purposes of |
251 // testing. | 292 // testing. |
252 // | 293 // |
253 // |context| should be a android.content.Context instance or NULL to enable | 294 // |context| should be a android.content.Context instance or NULL to enable |
254 // the use of the standard application context. | 295 // the use of the standard application context. |
255 static void SetResourceContextForTesting(JNIEnv* env, jclass /*clazz*/, | 296 static void SetResourceContextForTesting(JNIEnv* env, jclass /*clazz*/, |
(...skipping 11 matching lines...) Expand all Loading... |
267 env, android_webview::kAndroidAssetPath).Release(); | 308 env, android_webview::kAndroidAssetPath).Release(); |
268 } | 309 } |
269 | 310 |
270 static jstring GetAndroidResourcePath(JNIEnv* env, jclass /*clazz*/) { | 311 static jstring GetAndroidResourcePath(JNIEnv* env, jclass /*clazz*/) { |
271 // OK to release, JNI binding. | 312 // OK to release, JNI binding. |
272 return ConvertUTF8ToJavaString( | 313 return ConvertUTF8ToJavaString( |
273 env, android_webview::kAndroidResourcePath).Release(); | 314 env, android_webview::kAndroidResourcePath).Release(); |
274 } | 315 } |
275 | 316 |
276 } // namespace android_webview | 317 } // namespace android_webview |
OLD | NEW |