OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 #include "components/cronet/android/chromium_url_request.h" | |
6 | |
7 #include "base/android/jni_android.h" | |
8 #include "base/android/jni_string.h" | |
9 #include "base/macros.h" | |
10 #include "components/cronet/android/url_request_adapter.h" | |
11 #include "components/cronet/android/url_request_context_adapter.h" | |
12 #include "jni/ChromiumUrlRequest_jni.h" | |
13 #include "net/base/net_errors.h" | |
14 #include "net/base/request_priority.h" | |
15 #include "net/http/http_response_headers.h" | |
16 | |
17 using base::android::ConvertUTF8ToJavaString; | |
18 using base::android::ConvertJavaStringToUTF8; | |
19 using base::android::JavaParamRef; | |
20 using base::android::ScopedJavaLocalRef; | |
21 | |
22 namespace cronet { | |
23 namespace { | |
24 | |
25 net::RequestPriority ConvertRequestPriority(jint request_priority) { | |
26 switch (request_priority) { | |
27 case REQUEST_PRIORITY_IDLE: | |
28 return net::IDLE; | |
29 case REQUEST_PRIORITY_LOWEST: | |
30 return net::LOWEST; | |
31 case REQUEST_PRIORITY_LOW: | |
32 return net::LOW; | |
33 case REQUEST_PRIORITY_MEDIUM: | |
34 return net::MEDIUM; | |
35 case REQUEST_PRIORITY_HIGHEST: | |
36 return net::HIGHEST; | |
37 default: | |
38 return net::LOWEST; | |
39 } | |
40 } | |
41 | |
42 void SetPostContentType(JNIEnv* env, | |
43 URLRequestAdapter* request_adapter, | |
44 jstring content_type) { | |
45 std::string method_post("POST"); | |
46 request_adapter->SetMethod(method_post); | |
47 | |
48 std::string content_type_header("Content-Type"); | |
49 std::string content_type_string(ConvertJavaStringToUTF8(env, content_type)); | |
50 | |
51 request_adapter->AddHeader(content_type_header, content_type_string); | |
52 } | |
53 | |
54 // A delegate of URLRequestAdapter that delivers callbacks to the Java layer. | |
55 class JniURLRequestAdapterDelegate | |
56 : public URLRequestAdapter::URLRequestAdapterDelegate { | |
57 public: | |
58 JniURLRequestAdapterDelegate(JNIEnv* env, jobject owner) { | |
59 owner_ = env->NewGlobalRef(owner); | |
60 } | |
61 | |
62 void OnResponseStarted(URLRequestAdapter* request_adapter) override { | |
63 JNIEnv* env = base::android::AttachCurrentThread(); | |
64 cronet::Java_ChromiumUrlRequest_onResponseStarted(env, owner_); | |
65 } | |
66 | |
67 void OnBytesRead(URLRequestAdapter* request_adapter, | |
68 int bytes_read) override { | |
69 if (bytes_read != 0) { | |
70 JNIEnv* env = base::android::AttachCurrentThread(); | |
71 base::android::ScopedJavaLocalRef<jobject> java_buffer( | |
72 env, env->NewDirectByteBuffer(request_adapter->Data(), bytes_read)); | |
73 cronet::Java_ChromiumUrlRequest_onBytesRead(env, owner_, java_buffer); | |
74 } | |
75 } | |
76 | |
77 void OnRequestFinished(URLRequestAdapter* request_adapter) override { | |
78 JNIEnv* env = base::android::AttachCurrentThread(); | |
79 cronet::Java_ChromiumUrlRequest_finish(env, owner_); | |
80 } | |
81 | |
82 int ReadFromUploadChannel(net::IOBuffer* buf, int buf_length) override { | |
83 JNIEnv* env = base::android::AttachCurrentThread(); | |
84 base::android::ScopedJavaLocalRef<jobject> java_buffer( | |
85 env, env->NewDirectByteBuffer(buf->data(), buf_length)); | |
86 jint bytes_read = cronet::Java_ChromiumUrlRequest_readFromUploadChannel( | |
87 env, owner_, java_buffer); | |
88 return bytes_read; | |
89 } | |
90 | |
91 protected: | |
92 ~JniURLRequestAdapterDelegate() override { | |
93 JNIEnv* env = base::android::AttachCurrentThread(); | |
94 env->DeleteGlobalRef(owner_); | |
95 } | |
96 | |
97 private: | |
98 jobject owner_; | |
99 | |
100 DISALLOW_COPY_AND_ASSIGN(JniURLRequestAdapterDelegate); | |
101 }; | |
102 | |
103 } // namespace | |
104 | |
105 // Explicitly register static JNI functions. | |
106 bool ChromiumUrlRequestRegisterJni(JNIEnv* env) { | |
107 return RegisterNativesImpl(env); | |
108 } | |
109 | |
110 static jlong CreateRequestAdapter(JNIEnv* env, | |
111 const JavaParamRef<jobject>& jcaller, | |
112 jlong jurl_request_context_adapter, | |
113 const JavaParamRef<jstring>& jurl, | |
114 jint jrequest_priority) { | |
115 URLRequestContextAdapter* context_adapter = | |
116 reinterpret_cast<URLRequestContextAdapter*>(jurl_request_context_adapter); | |
117 DCHECK(context_adapter); | |
118 | |
119 GURL url(ConvertJavaStringToUTF8(env, jurl)); | |
120 | |
121 VLOG(1) << "New chromium network request: " << url.possibly_invalid_spec(); | |
122 | |
123 URLRequestAdapter* adapter = new URLRequestAdapter( | |
124 context_adapter, new JniURLRequestAdapterDelegate(env, jcaller), url, | |
125 ConvertRequestPriority(jrequest_priority)); | |
126 | |
127 return reinterpret_cast<jlong>(adapter); | |
128 } | |
129 | |
130 // synchronized | |
131 static void AddHeader(JNIEnv* env, | |
132 const JavaParamRef<jobject>& jcaller, | |
133 jlong jurl_request_adapter, | |
134 const JavaParamRef<jstring>& jheader_name, | |
135 const JavaParamRef<jstring>& jheader_value) { | |
136 URLRequestAdapter* request_adapter = | |
137 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
138 DCHECK(request_adapter); | |
139 | |
140 std::string header_name(ConvertJavaStringToUTF8(env, jheader_name)); | |
141 std::string header_value(ConvertJavaStringToUTF8(env, jheader_value)); | |
142 | |
143 request_adapter->AddHeader(header_name, header_value); | |
144 } | |
145 | |
146 static void SetMethod(JNIEnv* env, | |
147 const JavaParamRef<jobject>& jcaller, | |
148 jlong jurl_request_adapter, | |
149 const JavaParamRef<jstring>& jmethod) { | |
150 URLRequestAdapter* request_adapter = | |
151 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
152 DCHECK(request_adapter); | |
153 | |
154 std::string method(ConvertJavaStringToUTF8(env, jmethod)); | |
155 | |
156 request_adapter->SetMethod(method); | |
157 } | |
158 | |
159 static void SetUploadData(JNIEnv* env, | |
160 const JavaParamRef<jobject>& jcaller, | |
161 jlong jurl_request_adapter, | |
162 const JavaParamRef<jstring>& jcontent_type, | |
163 const JavaParamRef<jbyteArray>& jcontent) { | |
164 URLRequestAdapter* request_adapter = | |
165 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
166 DCHECK(request_adapter); | |
167 SetPostContentType(env, request_adapter, jcontent_type); | |
168 | |
169 if (jcontent != nullptr) { | |
170 jsize size = env->GetArrayLength(jcontent); | |
171 if (size > 0) { | |
172 jbyte* content_bytes = env->GetByteArrayElements(jcontent, nullptr); | |
173 request_adapter->SetUploadContent( | |
174 reinterpret_cast<const char*>(content_bytes), size); | |
175 env->ReleaseByteArrayElements(jcontent, content_bytes, 0); | |
176 } | |
177 } | |
178 } | |
179 | |
180 static void SetUploadChannel(JNIEnv* env, | |
181 const JavaParamRef<jobject>& jcaller, | |
182 jlong jurl_request_adapter, | |
183 const JavaParamRef<jstring>& jcontent_type, | |
184 jlong jcontent_length) { | |
185 URLRequestAdapter* request_adapter = | |
186 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
187 DCHECK(request_adapter); | |
188 SetPostContentType(env, request_adapter, jcontent_type); | |
189 | |
190 request_adapter->SetUploadChannel(env, jcontent_length); | |
191 } | |
192 | |
193 static void EnableChunkedUpload(JNIEnv* env, | |
194 const JavaParamRef<jobject>& jcaller, | |
195 jlong jurl_request_adapter, | |
196 const JavaParamRef<jstring>& jcontent_type) { | |
197 URLRequestAdapter* request_adapter = | |
198 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
199 DCHECK(request_adapter); | |
200 SetPostContentType(env, request_adapter, jcontent_type); | |
201 | |
202 request_adapter->EnableChunkedUpload(); | |
203 } | |
204 | |
205 static void AppendChunk(JNIEnv* env, | |
206 const JavaParamRef<jobject>& jcaller, | |
207 jlong jurl_request_adapter, | |
208 const JavaParamRef<jobject>& jchunk_byte_buffer, | |
209 jint jchunk_size, | |
210 jboolean jis_last_chunk) { | |
211 URLRequestAdapter* request_adapter = | |
212 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
213 DCHECK(request_adapter); | |
214 DCHECK(jchunk_byte_buffer); | |
215 | |
216 void* chunk = env->GetDirectBufferAddress(jchunk_byte_buffer); | |
217 request_adapter->AppendChunk(reinterpret_cast<const char*>(chunk), | |
218 jchunk_size, jis_last_chunk); | |
219 } | |
220 | |
221 /* synchronized */ | |
222 static void Start(JNIEnv* env, | |
223 const JavaParamRef<jobject>& jcaller, | |
224 jlong jurl_request_adapter) { | |
225 URLRequestAdapter* request_adapter = | |
226 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
227 if (request_adapter != nullptr) | |
228 request_adapter->Start(); | |
229 } | |
230 | |
231 /* synchronized */ | |
232 static void DestroyRequestAdapter(JNIEnv* env, | |
233 const JavaParamRef<jobject>& jcaller, | |
234 jlong jurl_request_adapter) { | |
235 URLRequestAdapter* request_adapter = | |
236 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
237 if (request_adapter != nullptr) | |
238 request_adapter->Destroy(); | |
239 } | |
240 | |
241 /* synchronized */ | |
242 static void Cancel(JNIEnv* env, | |
243 const JavaParamRef<jobject>& jcaller, | |
244 jlong jurl_request_adapter) { | |
245 URLRequestAdapter* request_adapter = | |
246 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
247 if (request_adapter != nullptr) | |
248 request_adapter->Cancel(); | |
249 } | |
250 | |
251 static jint GetErrorCode(JNIEnv* env, | |
252 const JavaParamRef<jobject>& jcaller, | |
253 jlong jurl_request_adapter) { | |
254 URLRequestAdapter* request_adapter = | |
255 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
256 DCHECK(request_adapter); | |
257 int error_code = request_adapter->error_code(); | |
258 switch (error_code) { | |
259 // TODO(mef): Investigate returning success on positive values, too, as | |
260 // they technically indicate success. | |
261 case net::OK: | |
262 return REQUEST_ERROR_SUCCESS; | |
263 | |
264 // TODO(mef): Investigate this. The fact is that Chrome does not do this, | |
265 // and this library is not just being used for downloads. | |
266 | |
267 // Comment from src/content/browser/download/download_resource_handler.cc: | |
268 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are | |
269 // allowed since a number of servers in the wild close the connection too | |
270 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 - | |
271 // treat downloads as complete in both cases, so we follow their lead. | |
272 case net::ERR_CONTENT_LENGTH_MISMATCH: | |
273 case net::ERR_INCOMPLETE_CHUNKED_ENCODING: | |
274 return REQUEST_ERROR_SUCCESS; | |
275 | |
276 case net::ERR_INVALID_URL: | |
277 case net::ERR_DISALLOWED_URL_SCHEME: | |
278 case net::ERR_UNKNOWN_URL_SCHEME: | |
279 return REQUEST_ERROR_MALFORMED_URL; | |
280 | |
281 case net::ERR_CONNECTION_TIMED_OUT: | |
282 return REQUEST_ERROR_CONNECTION_TIMED_OUT; | |
283 | |
284 case net::ERR_NAME_NOT_RESOLVED: | |
285 return REQUEST_ERROR_UNKNOWN_HOST; | |
286 case net::ERR_TOO_MANY_REDIRECTS: | |
287 return REQUEST_ERROR_TOO_MANY_REDIRECTS; | |
288 } | |
289 return REQUEST_ERROR_UNKNOWN; | |
290 } | |
291 | |
292 static ScopedJavaLocalRef<jstring> GetErrorString( | |
293 JNIEnv* env, | |
294 const JavaParamRef<jobject>& jcaller, | |
295 jlong jurl_request_adapter) { | |
296 URLRequestAdapter* request_adapter = | |
297 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
298 DCHECK(request_adapter); | |
299 int error_code = request_adapter->error_code(); | |
300 char buffer[200]; | |
301 std::string error_string = net::ErrorToString(error_code); | |
302 snprintf(buffer, | |
303 sizeof(buffer), | |
304 "System error: %s(%d)", | |
305 error_string.c_str(), | |
306 error_code); | |
307 return ConvertUTF8ToJavaString(env, buffer); | |
308 } | |
309 | |
310 static jint GetHttpStatusCode(JNIEnv* env, | |
311 const JavaParamRef<jobject>& jcaller, | |
312 jlong jurl_request_adapter) { | |
313 URLRequestAdapter* request_adapter = | |
314 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
315 DCHECK(request_adapter); | |
316 return request_adapter->http_status_code(); | |
317 } | |
318 | |
319 static ScopedJavaLocalRef<jstring> GetHttpStatusText( | |
320 JNIEnv* env, | |
321 const JavaParamRef<jobject>& jcaller, | |
322 jlong jurl_request_adapter) { | |
323 URLRequestAdapter* request_adapter = | |
324 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
325 DCHECK(request_adapter); | |
326 return ConvertUTF8ToJavaString(env, request_adapter->http_status_text()); | |
327 } | |
328 | |
329 static ScopedJavaLocalRef<jstring> GetContentType( | |
330 JNIEnv* env, | |
331 const JavaParamRef<jobject>& jcaller, | |
332 jlong jurl_request_adapter) { | |
333 URLRequestAdapter* request_adapter = | |
334 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
335 DCHECK(request_adapter); | |
336 std::string type = request_adapter->content_type(); | |
337 if (!type.empty()) { | |
338 return ConvertUTF8ToJavaString(env, type.c_str()); | |
339 } else { | |
340 return ScopedJavaLocalRef<jstring>(); | |
341 } | |
342 } | |
343 | |
344 static jlong GetContentLength(JNIEnv* env, | |
345 const JavaParamRef<jobject>& jcaller, | |
346 jlong jurl_request_adapter) { | |
347 URLRequestAdapter* request_adapter = | |
348 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
349 DCHECK(request_adapter); | |
350 return request_adapter->content_length(); | |
351 } | |
352 | |
353 static ScopedJavaLocalRef<jstring> GetHeader( | |
354 JNIEnv* env, | |
355 const JavaParamRef<jobject>& jcaller, | |
356 jlong jurl_request_adapter, | |
357 const JavaParamRef<jstring>& jheader_name) { | |
358 URLRequestAdapter* request_adapter = | |
359 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
360 DCHECK(request_adapter); | |
361 std::string header_name = ConvertJavaStringToUTF8(env, jheader_name); | |
362 std::string header_value = request_adapter->GetHeader(header_name); | |
363 if (!header_value.empty()) | |
364 return ConvertUTF8ToJavaString(env, header_value.c_str()); | |
365 return ScopedJavaLocalRef<jstring>(); | |
366 } | |
367 | |
368 static void GetAllHeaders(JNIEnv* env, | |
369 const JavaParamRef<jobject>& jcaller, | |
370 jlong jurl_request_adapter, | |
371 const JavaParamRef<jobject>& jheaders_map) { | |
372 URLRequestAdapter* request_adapter = | |
373 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
374 DCHECK(request_adapter); | |
375 | |
376 net::HttpResponseHeaders* headers = request_adapter->GetResponseHeaders(); | |
377 if (headers == nullptr) | |
378 return; | |
379 | |
380 size_t iter = 0; | |
381 std::string header_name; | |
382 std::string header_value; | |
383 while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) { | |
384 ScopedJavaLocalRef<jstring> name = | |
385 ConvertUTF8ToJavaString(env, header_name); | |
386 ScopedJavaLocalRef<jstring> value = | |
387 ConvertUTF8ToJavaString(env, header_value); | |
388 Java_ChromiumUrlRequest_onAppendResponseHeader(env, jcaller, jheaders_map, | |
389 name, value); | |
390 } | |
391 | |
392 // Some implementations (notably HttpURLConnection) include a mapping for the | |
393 // null key; in HTTP's case, this maps to the HTTP status line. | |
394 ScopedJavaLocalRef<jstring> status_line = | |
395 ConvertUTF8ToJavaString(env, headers->GetStatusLine()); | |
396 Java_ChromiumUrlRequest_onAppendResponseHeader(env, jcaller, jheaders_map, | |
397 nullptr, status_line); | |
398 } | |
399 | |
400 static ScopedJavaLocalRef<jstring> GetNegotiatedProtocol( | |
401 JNIEnv* env, | |
402 const JavaParamRef<jobject>& jcaller, | |
403 jlong jurl_request_adapter) { | |
404 URLRequestAdapter* request_adapter = | |
405 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
406 DCHECK(request_adapter); | |
407 | |
408 std::string negotiated_protocol = request_adapter->GetNegotiatedProtocol(); | |
409 return ConvertUTF8ToJavaString(env, negotiated_protocol.c_str()); | |
410 } | |
411 | |
412 static jboolean GetWasCached(JNIEnv* env, | |
413 const JavaParamRef<jobject>& jcaller, | |
414 jlong jurl_request_adapter) { | |
415 URLRequestAdapter* request_adapter = | |
416 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
417 DCHECK(request_adapter); | |
418 | |
419 bool was_cached = request_adapter->GetWasCached(); | |
420 return was_cached ? JNI_TRUE : JNI_FALSE; | |
421 } | |
422 | |
423 static void DisableRedirects(JNIEnv* env, | |
424 const JavaParamRef<jobject>& jcaller, | |
425 jlong jrequest_adapter) { | |
426 URLRequestAdapter* request_adapter = | |
427 reinterpret_cast<URLRequestAdapter*>(jrequest_adapter); | |
428 DCHECK(request_adapter); | |
429 request_adapter->DisableRedirects(); | |
430 } | |
431 | |
432 } // namespace cronet | |
OLD | NEW |