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 |