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/org_chromium_net_UrlRequest.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_context_peer.h"
11 #include "components/cronet/android/url_request_peer.h"
12 #include "jni/UrlRequest_jni.h"
13 #include "net/base/net_errors.h"
14 #include "net/base/request_priority.h"
16 using base::android::ConvertUTF8ToJavaString
;
21 net::RequestPriority
ConvertRequestPriority(jint request_priority
) {
22 switch (request_priority
) {
23 case REQUEST_PRIORITY_IDLE
:
25 case REQUEST_PRIORITY_LOWEST
:
27 case REQUEST_PRIORITY_LOW
:
29 case REQUEST_PRIORITY_MEDIUM
:
31 case REQUEST_PRIORITY_HIGHEST
:
38 void SetPostContentType(JNIEnv
* env
,
39 URLRequestPeer
* request
,
40 jstring content_type
) {
41 DCHECK(request
!= NULL
);
43 std::string
method_post("POST");
44 request
->SetMethod(method_post
);
46 std::string
content_type_header("Content-Type");
48 const char* content_type_utf8
= env
->GetStringUTFChars(content_type
, NULL
);
49 std::string
content_type_string(content_type_utf8
);
50 env
->ReleaseStringUTFChars(content_type
, content_type_utf8
);
52 request
->AddHeader(content_type_header
, content_type_string
);
55 // A delegate of URLRequestPeer that delivers callbacks to the Java layer.
56 class JniURLRequestPeerDelegate
57 : public URLRequestPeer::URLRequestPeerDelegate
{
59 JniURLRequestPeerDelegate(JNIEnv
* env
, jobject owner
) {
60 owner_
= env
->NewGlobalRef(owner
);
63 virtual void OnAppendChunkCompleted(URLRequestPeer
* request
) OVERRIDE
{
64 JNIEnv
* env
= base::android::AttachCurrentThread();
65 cronet::Java_UrlRequest_onAppendChunkCompleted(env
, owner_
);
68 virtual void OnResponseStarted(URLRequestPeer
* request
) OVERRIDE
{
69 JNIEnv
* env
= base::android::AttachCurrentThread();
70 cronet::Java_UrlRequest_onResponseStarted(env
, owner_
);
73 virtual void OnBytesRead(URLRequestPeer
* request
) OVERRIDE
{
74 int bytes_read
= request
->bytes_read();
75 if (bytes_read
!= 0) {
76 JNIEnv
* env
= base::android::AttachCurrentThread();
77 jobject bytebuf
= env
->NewDirectByteBuffer(request
->Data(), bytes_read
);
78 cronet::Java_UrlRequest_onBytesRead(env
, owner_
, bytebuf
);
79 env
->DeleteLocalRef(bytebuf
);
83 virtual void OnRequestFinished(URLRequestPeer
* request
) OVERRIDE
{
84 JNIEnv
* env
= base::android::AttachCurrentThread();
85 cronet::Java_UrlRequest_finish(env
, owner_
);
89 virtual ~JniURLRequestPeerDelegate() {
90 JNIEnv
* env
= base::android::AttachCurrentThread();
91 env
->DeleteGlobalRef(owner_
);
97 DISALLOW_COPY_AND_ASSIGN(JniURLRequestPeerDelegate
);
102 // Explicitly register static JNI functions.
103 bool UrlRequestRegisterJni(JNIEnv
* env
) { return RegisterNativesImpl(env
); }
105 static jlong
CreateRequestPeer(JNIEnv
* env
,
107 jlong urlRequestContextPeer
,
110 URLRequestContextPeer
* context
=
111 reinterpret_cast<URLRequestContextPeer
*>(urlRequestContextPeer
);
112 DCHECK(context
!= NULL
);
114 const char* url_utf8
= env
->GetStringUTFChars(url_string
, NULL
);
116 DVLOG(context
->logging_level())
117 << "New chromium network request. URL:" << url_utf8
;
121 env
->ReleaseStringUTFChars(url_string
, url_utf8
);
123 URLRequestPeer
* peer
=
124 new URLRequestPeer(context
,
125 new JniURLRequestPeerDelegate(env
, object
),
127 ConvertRequestPriority(priority
));
129 return reinterpret_cast<jlong
>(peer
);
133 static void AddHeader(JNIEnv
* env
,
135 jlong urlRequestPeer
,
138 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
139 DCHECK(request
!= NULL
);
141 const char* name_utf8
= env
->GetStringUTFChars(name
, NULL
);
142 std::string
name_string(name_utf8
);
143 env
->ReleaseStringUTFChars(name
, name_utf8
);
145 const char* value_utf8
= env
->GetStringUTFChars(value
, NULL
);
146 std::string
value_string(value_utf8
);
147 env
->ReleaseStringUTFChars(value
, value_utf8
);
149 request
->AddHeader(name_string
, value_string
);
152 static void SetPostData(JNIEnv
* env
,
154 jlong urlRequestPeer
,
155 jstring content_type
,
156 jbyteArray content
) {
157 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
158 SetPostContentType(env
, request
, content_type
);
160 if (content
!= NULL
) {
161 jsize size
= env
->GetArrayLength(content
);
163 jbyte
* content_bytes
= env
->GetByteArrayElements(content
, NULL
);
164 request
->SetPostContent(reinterpret_cast<const char*>(content_bytes
),
166 env
->ReleaseByteArrayElements(content
, content_bytes
, 0);
171 static void BeginChunkedUpload(JNIEnv
* env
,
173 jlong urlRequestPeer
,
174 jstring content_type
) {
175 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
176 SetPostContentType(env
, request
, content_type
);
178 request
->EnableStreamingUpload();
181 static void AppendChunk(JNIEnv
* env
,
183 jlong urlRequestPeer
,
184 jobject chunk_byte_buffer
,
186 jboolean is_last_chunk
) {
187 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
188 CHECK(request
!= NULL
);
190 if (chunk_byte_buffer
!= NULL
) {
191 void* chunk
= env
->GetDirectBufferAddress(chunk_byte_buffer
);
192 request
->AppendChunk(
193 reinterpret_cast<const char*>(chunk
), chunk_size
, is_last_chunk
);
198 static void Start(JNIEnv
* env
, jobject object
, jlong urlRequestPeer
) {
199 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
200 if (request
!= NULL
) {
206 static void DestroyRequestPeer(JNIEnv
* env
,
208 jlong urlRequestPeer
) {
209 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
210 if (request
!= NULL
) {
216 static void Cancel(JNIEnv
* env
, jobject object
, jlong urlRequestPeer
) {
217 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
218 if (request
!= NULL
) {
223 static jint
GetErrorCode(JNIEnv
* env
, jobject object
, jlong urlRequestPeer
) {
224 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
225 int error_code
= request
->error_code();
226 switch (error_code
) {
227 // TODO(mef): Investigate returning success on positive values, too, as
228 // they technically indicate success.
230 return REQUEST_ERROR_SUCCESS
;
232 // TODO(mef): Investigate this. The fact is that Chrome does not do this,
233 // and this library is not just being used for downloads.
235 // Comment from src/content/browser/download/download_resource_handler.cc:
236 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are
237 // allowed since a number of servers in the wild close the connection too
238 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 -
239 // treat downloads as complete in both cases, so we follow their lead.
240 case net::ERR_CONTENT_LENGTH_MISMATCH
:
241 case net::ERR_INCOMPLETE_CHUNKED_ENCODING
:
242 return REQUEST_ERROR_SUCCESS
;
244 case net::ERR_INVALID_URL
:
245 case net::ERR_DISALLOWED_URL_SCHEME
:
246 case net::ERR_UNKNOWN_URL_SCHEME
:
247 return REQUEST_ERROR_MALFORMED_URL
;
249 case net::ERR_CONNECTION_TIMED_OUT
:
250 return REQUEST_ERROR_CONNECTION_TIMED_OUT
;
252 case net::ERR_NAME_NOT_RESOLVED
:
253 return REQUEST_ERROR_UNKNOWN_HOST
;
255 return REQUEST_ERROR_UNKNOWN
;
258 static jstring
GetErrorString(JNIEnv
* env
,
260 jlong urlRequestPeer
) {
261 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
262 int error_code
= request
->error_code();
266 "System error: %s(%d)",
267 net::ErrorToString(error_code
),
269 return ConvertUTF8ToJavaString(env
, buffer
).Release();
272 static jint
GetHttpStatusCode(JNIEnv
* env
,
274 jlong urlRequestPeer
) {
275 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
276 return request
->http_status_code();
279 static jstring
GetContentType(JNIEnv
* env
,
281 jlong urlRequestPeer
) {
282 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
283 if (request
== NULL
) {
286 std::string type
= request
->content_type();
288 return ConvertUTF8ToJavaString(env
, type
.c_str()).Release();
294 static jlong
GetContentLength(JNIEnv
* env
,
296 jlong urlRequestPeer
) {
297 URLRequestPeer
* request
= reinterpret_cast<URLRequestPeer
*>(urlRequestPeer
);
298 if (request
== NULL
) {
301 return request
->content_length();
304 } // namespace cronet