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.
5 #include "components/cronet/android/chromium_url_request.h"
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"
17 using base::android::ConvertUTF8ToJavaString
;
18 using base::android::ConvertJavaStringToUTF8
;
23 net::RequestPriority
ConvertRequestPriority(jint request_priority
) {
24 switch (request_priority
) {
25 case REQUEST_PRIORITY_IDLE
:
27 case REQUEST_PRIORITY_LOWEST
:
29 case REQUEST_PRIORITY_LOW
:
31 case REQUEST_PRIORITY_MEDIUM
:
33 case REQUEST_PRIORITY_HIGHEST
:
40 void SetPostContentType(JNIEnv
* env
,
41 URLRequestAdapter
* request_adapter
,
42 jstring content_type
) {
43 std::string
method_post("POST");
44 request_adapter
->SetMethod(method_post
);
46 std::string
content_type_header("Content-Type");
47 std::string
content_type_string(ConvertJavaStringToUTF8(env
, content_type
));
49 request_adapter
->AddHeader(content_type_header
, content_type_string
);
52 // A delegate of URLRequestAdapter that delivers callbacks to the Java layer.
53 class JniURLRequestAdapterDelegate
54 : public URLRequestAdapter::URLRequestAdapterDelegate
{
56 JniURLRequestAdapterDelegate(JNIEnv
* env
, jobject owner
) {
57 owner_
= env
->NewGlobalRef(owner
);
60 void OnResponseStarted(URLRequestAdapter
* request_adapter
) override
{
61 JNIEnv
* env
= base::android::AttachCurrentThread();
62 cronet::Java_ChromiumUrlRequest_onResponseStarted(env
, owner_
);
65 void OnBytesRead(URLRequestAdapter
* request_adapter
,
66 int bytes_read
) override
{
67 if (bytes_read
!= 0) {
68 JNIEnv
* env
= base::android::AttachCurrentThread();
69 base::android::ScopedJavaLocalRef
<jobject
> java_buffer(
70 env
, env
->NewDirectByteBuffer(request_adapter
->Data(), bytes_read
));
71 cronet::Java_ChromiumUrlRequest_onBytesRead(
72 env
, owner_
, java_buffer
.obj());
76 void OnRequestFinished(URLRequestAdapter
* request_adapter
) override
{
77 JNIEnv
* env
= base::android::AttachCurrentThread();
78 cronet::Java_ChromiumUrlRequest_finish(env
, owner_
);
81 int ReadFromUploadChannel(net::IOBuffer
* buf
, int buf_length
) override
{
82 JNIEnv
* env
= base::android::AttachCurrentThread();
83 base::android::ScopedJavaLocalRef
<jobject
> java_buffer(
84 env
, env
->NewDirectByteBuffer(buf
->data(), buf_length
));
85 jint bytes_read
= cronet::Java_ChromiumUrlRequest_readFromUploadChannel(
86 env
, owner_
, java_buffer
.obj());
91 ~JniURLRequestAdapterDelegate() override
{
92 JNIEnv
* env
= base::android::AttachCurrentThread();
93 env
->DeleteGlobalRef(owner_
);
99 DISALLOW_COPY_AND_ASSIGN(JniURLRequestAdapterDelegate
);
104 // Explicitly register static JNI functions.
105 bool ChromiumUrlRequestRegisterJni(JNIEnv
* env
) {
106 return RegisterNativesImpl(env
);
109 static jlong
CreateRequestAdapter(JNIEnv
* env
,
110 const JavaParamRef
<jobject
>& jcaller
,
111 jlong jurl_request_context_adapter
,
112 const JavaParamRef
<jstring
>& jurl
,
113 jint jrequest_priority
) {
114 URLRequestContextAdapter
* context_adapter
=
115 reinterpret_cast<URLRequestContextAdapter
*>(jurl_request_context_adapter
);
116 DCHECK(context_adapter
);
118 GURL
url(ConvertJavaStringToUTF8(env
, jurl
));
120 VLOG(1) << "New chromium network request: " << url
.possibly_invalid_spec();
122 URLRequestAdapter
* adapter
= new URLRequestAdapter(
123 context_adapter
, new JniURLRequestAdapterDelegate(env
, jcaller
), url
,
124 ConvertRequestPriority(jrequest_priority
));
126 return reinterpret_cast<jlong
>(adapter
);
130 static void AddHeader(JNIEnv
* env
,
131 const JavaParamRef
<jobject
>& jcaller
,
132 jlong jurl_request_adapter
,
133 const JavaParamRef
<jstring
>& jheader_name
,
134 const JavaParamRef
<jstring
>& jheader_value
) {
135 URLRequestAdapter
* request_adapter
=
136 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
137 DCHECK(request_adapter
);
139 std::string
header_name(ConvertJavaStringToUTF8(env
, jheader_name
));
140 std::string
header_value(ConvertJavaStringToUTF8(env
, jheader_value
));
142 request_adapter
->AddHeader(header_name
, header_value
);
145 static void SetMethod(JNIEnv
* env
,
146 const JavaParamRef
<jobject
>& jcaller
,
147 jlong jurl_request_adapter
,
148 const JavaParamRef
<jstring
>& jmethod
) {
149 URLRequestAdapter
* request_adapter
=
150 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
151 DCHECK(request_adapter
);
153 std::string
method(ConvertJavaStringToUTF8(env
, jmethod
));
155 request_adapter
->SetMethod(method
);
158 static void SetUploadData(JNIEnv
* env
,
159 const JavaParamRef
<jobject
>& jcaller
,
160 jlong jurl_request_adapter
,
161 const JavaParamRef
<jstring
>& jcontent_type
,
162 const JavaParamRef
<jbyteArray
>& jcontent
) {
163 URLRequestAdapter
* request_adapter
=
164 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
165 DCHECK(request_adapter
);
166 SetPostContentType(env
, request_adapter
, jcontent_type
);
168 if (jcontent
!= NULL
) {
169 jsize size
= env
->GetArrayLength(jcontent
);
171 jbyte
* content_bytes
= env
->GetByteArrayElements(jcontent
, NULL
);
172 request_adapter
->SetUploadContent(
173 reinterpret_cast<const char*>(content_bytes
), size
);
174 env
->ReleaseByteArrayElements(jcontent
, content_bytes
, 0);
179 static void SetUploadChannel(JNIEnv
* env
,
180 const JavaParamRef
<jobject
>& jcaller
,
181 jlong jurl_request_adapter
,
182 const JavaParamRef
<jstring
>& jcontent_type
,
183 jlong jcontent_length
) {
184 URLRequestAdapter
* request_adapter
=
185 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
186 DCHECK(request_adapter
);
187 SetPostContentType(env
, request_adapter
, jcontent_type
);
189 request_adapter
->SetUploadChannel(env
, jcontent_length
);
192 static void EnableChunkedUpload(JNIEnv
* env
,
193 const JavaParamRef
<jobject
>& jcaller
,
194 jlong jurl_request_adapter
,
195 const JavaParamRef
<jstring
>& jcontent_type
) {
196 URLRequestAdapter
* request_adapter
=
197 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
198 DCHECK(request_adapter
);
199 SetPostContentType(env
, request_adapter
, jcontent_type
);
201 request_adapter
->EnableChunkedUpload();
204 static void AppendChunk(JNIEnv
* env
,
205 const JavaParamRef
<jobject
>& jcaller
,
206 jlong jurl_request_adapter
,
207 const JavaParamRef
<jobject
>& jchunk_byte_buffer
,
209 jboolean jis_last_chunk
) {
210 URLRequestAdapter
* request_adapter
=
211 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
212 DCHECK(request_adapter
);
213 DCHECK(jchunk_byte_buffer
);
215 void* chunk
= env
->GetDirectBufferAddress(jchunk_byte_buffer
);
216 request_adapter
->AppendChunk(reinterpret_cast<const char*>(chunk
),
217 jchunk_size
, jis_last_chunk
);
221 static void Start(JNIEnv
* env
,
222 const JavaParamRef
<jobject
>& jcaller
,
223 jlong jurl_request_adapter
) {
224 URLRequestAdapter
* request_adapter
=
225 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
226 if (request_adapter
!= NULL
)
227 request_adapter
->Start();
231 static void DestroyRequestAdapter(JNIEnv
* env
,
232 const JavaParamRef
<jobject
>& jcaller
,
233 jlong jurl_request_adapter
) {
234 URLRequestAdapter
* request_adapter
=
235 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
236 if (request_adapter
!= NULL
)
237 request_adapter
->Destroy();
241 static void Cancel(JNIEnv
* env
,
242 const JavaParamRef
<jobject
>& jcaller
,
243 jlong jurl_request_adapter
) {
244 URLRequestAdapter
* request_adapter
=
245 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
246 if (request_adapter
!= NULL
)
247 request_adapter
->Cancel();
250 static jint
GetErrorCode(JNIEnv
* env
,
251 const JavaParamRef
<jobject
>& jcaller
,
252 jlong jurl_request_adapter
) {
253 URLRequestAdapter
* request_adapter
=
254 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
255 DCHECK(request_adapter
);
256 int error_code
= request_adapter
->error_code();
257 switch (error_code
) {
258 // TODO(mef): Investigate returning success on positive values, too, as
259 // they technically indicate success.
261 return REQUEST_ERROR_SUCCESS
;
263 // TODO(mef): Investigate this. The fact is that Chrome does not do this,
264 // and this library is not just being used for downloads.
266 // Comment from src/content/browser/download/download_resource_handler.cc:
267 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are
268 // allowed since a number of servers in the wild close the connection too
269 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 -
270 // treat downloads as complete in both cases, so we follow their lead.
271 case net::ERR_CONTENT_LENGTH_MISMATCH
:
272 case net::ERR_INCOMPLETE_CHUNKED_ENCODING
:
273 return REQUEST_ERROR_SUCCESS
;
275 case net::ERR_INVALID_URL
:
276 case net::ERR_DISALLOWED_URL_SCHEME
:
277 case net::ERR_UNKNOWN_URL_SCHEME
:
278 return REQUEST_ERROR_MALFORMED_URL
;
280 case net::ERR_CONNECTION_TIMED_OUT
:
281 return REQUEST_ERROR_CONNECTION_TIMED_OUT
;
283 case net::ERR_NAME_NOT_RESOLVED
:
284 return REQUEST_ERROR_UNKNOWN_HOST
;
285 case net::ERR_TOO_MANY_REDIRECTS
:
286 return REQUEST_ERROR_TOO_MANY_REDIRECTS
;
288 return REQUEST_ERROR_UNKNOWN
;
291 static ScopedJavaLocalRef
<jstring
> GetErrorString(
293 const JavaParamRef
<jobject
>& jcaller
,
294 jlong jurl_request_adapter
) {
295 URLRequestAdapter
* request_adapter
=
296 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
297 DCHECK(request_adapter
);
298 int error_code
= request_adapter
->error_code();
300 std::string error_string
= net::ErrorToString(error_code
);
303 "System error: %s(%d)",
304 error_string
.c_str(),
306 return ConvertUTF8ToJavaString(env
, buffer
);
309 static jint
GetHttpStatusCode(JNIEnv
* env
,
310 const JavaParamRef
<jobject
>& jcaller
,
311 jlong jurl_request_adapter
) {
312 URLRequestAdapter
* request_adapter
=
313 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
314 DCHECK(request_adapter
);
315 return request_adapter
->http_status_code();
318 static ScopedJavaLocalRef
<jstring
> GetHttpStatusText(
320 const JavaParamRef
<jobject
>& jcaller
,
321 jlong jurl_request_adapter
) {
322 URLRequestAdapter
* request_adapter
=
323 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
324 DCHECK(request_adapter
);
325 return ConvertUTF8ToJavaString(env
, request_adapter
->http_status_text());
328 static ScopedJavaLocalRef
<jstring
> GetContentType(
330 const JavaParamRef
<jobject
>& jcaller
,
331 jlong jurl_request_adapter
) {
332 URLRequestAdapter
* request_adapter
=
333 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
334 DCHECK(request_adapter
);
335 std::string type
= request_adapter
->content_type();
337 return ConvertUTF8ToJavaString(env
, type
.c_str());
339 return ScopedJavaLocalRef
<jstring
>();
343 static jlong
GetContentLength(JNIEnv
* env
,
344 const JavaParamRef
<jobject
>& jcaller
,
345 jlong jurl_request_adapter
) {
346 URLRequestAdapter
* request_adapter
=
347 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
348 DCHECK(request_adapter
);
349 return request_adapter
->content_length();
352 static ScopedJavaLocalRef
<jstring
> GetHeader(
354 const JavaParamRef
<jobject
>& jcaller
,
355 jlong jurl_request_adapter
,
356 const JavaParamRef
<jstring
>& jheader_name
) {
357 URLRequestAdapter
* request_adapter
=
358 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
359 DCHECK(request_adapter
);
360 std::string header_name
= ConvertJavaStringToUTF8(env
, jheader_name
);
361 std::string header_value
= request_adapter
->GetHeader(header_name
);
362 if (!header_value
.empty())
363 return ConvertUTF8ToJavaString(env
, header_value
.c_str());
364 return ScopedJavaLocalRef
<jstring
>();
367 static void GetAllHeaders(JNIEnv
* env
,
368 const JavaParamRef
<jobject
>& jcaller
,
369 jlong jurl_request_adapter
,
370 const JavaParamRef
<jobject
>& jheaders_map
) {
371 URLRequestAdapter
* request_adapter
=
372 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
373 DCHECK(request_adapter
);
375 net::HttpResponseHeaders
* headers
= request_adapter
->GetResponseHeaders();
380 std::string header_name
;
381 std::string header_value
;
382 while (headers
->EnumerateHeaderLines(&iter
, &header_name
, &header_value
)) {
383 ScopedJavaLocalRef
<jstring
> name
=
384 ConvertUTF8ToJavaString(env
, header_name
);
385 ScopedJavaLocalRef
<jstring
> value
=
386 ConvertUTF8ToJavaString(env
, header_value
);
387 Java_ChromiumUrlRequest_onAppendResponseHeader(env
, jcaller
, jheaders_map
,
388 name
.obj(), value
.obj());
391 // Some implementations (notably HttpURLConnection) include a mapping for the
392 // null key; in HTTP's case, this maps to the HTTP status line.
393 ScopedJavaLocalRef
<jstring
> status_line
=
394 ConvertUTF8ToJavaString(env
, headers
->GetStatusLine());
395 Java_ChromiumUrlRequest_onAppendResponseHeader(env
, jcaller
, jheaders_map
,
396 NULL
, status_line
.obj());
399 static ScopedJavaLocalRef
<jstring
> GetNegotiatedProtocol(
401 const JavaParamRef
<jobject
>& jcaller
,
402 jlong jurl_request_adapter
) {
403 URLRequestAdapter
* request_adapter
=
404 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
405 DCHECK(request_adapter
);
407 std::string negotiated_protocol
= request_adapter
->GetNegotiatedProtocol();
408 return ConvertUTF8ToJavaString(env
, negotiated_protocol
.c_str());
411 static jboolean
GetWasCached(JNIEnv
* env
,
412 const JavaParamRef
<jobject
>& jcaller
,
413 jlong jurl_request_adapter
) {
414 URLRequestAdapter
* request_adapter
=
415 reinterpret_cast<URLRequestAdapter
*>(jurl_request_adapter
);
416 DCHECK(request_adapter
);
418 bool was_cached
= request_adapter
->GetWasCached();
419 return was_cached
? JNI_TRUE
: JNI_FALSE
;
422 static void DisableRedirects(JNIEnv
* env
,
423 const JavaParamRef
<jobject
>& jcaller
,
424 jlong jrequest_adapter
) {
425 URLRequestAdapter
* request_adapter
=
426 reinterpret_cast<URLRequestAdapter
*>(jrequest_adapter
);
427 DCHECK(request_adapter
);
428 request_adapter
->DisableRedirects();
431 } // namespace cronet