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;
22 net::RequestPriority ConvertRequestPriority(jint request_priority) {
23 switch (request_priority) {
24 case REQUEST_PRIORITY_IDLE:
26 case REQUEST_PRIORITY_LOWEST:
28 case REQUEST_PRIORITY_LOW:
30 case REQUEST_PRIORITY_MEDIUM:
32 case REQUEST_PRIORITY_HIGHEST:
39 void SetPostContentType(JNIEnv* env,
40 URLRequestAdapter* request,
41 jstring content_type) {
42 DCHECK(request != NULL);
44 std::string method_post("POST");
45 request->SetMethod(method_post);
47 std::string content_type_header("Content-Type");
48 std::string content_type_string(
49 base::android::ConvertJavaStringToUTF8(env, content_type));
51 request->AddHeader(content_type_header, content_type_string);
54 // A delegate of URLRequestAdapter that delivers callbacks to the Java layer.
55 class JniURLRequestAdapterDelegate
56 : public URLRequestAdapter::URLRequestAdapterDelegate {
58 JniURLRequestAdapterDelegate(JNIEnv* env, jobject owner) {
59 owner_ = env->NewGlobalRef(owner);
62 virtual void OnResponseStarted(URLRequestAdapter* request) override {
63 JNIEnv* env = base::android::AttachCurrentThread();
64 cronet::Java_ChromiumUrlRequest_onResponseStarted(env, owner_);
67 virtual void OnBytesRead(URLRequestAdapter* request) override {
68 int bytes_read = request->bytes_read();
69 if (bytes_read != 0) {
70 JNIEnv* env = base::android::AttachCurrentThread();
71 base::android::ScopedJavaLocalRef<jobject> java_buffer(
72 env, env->NewDirectByteBuffer(request->Data(), bytes_read));
73 cronet::Java_ChromiumUrlRequest_onBytesRead(
74 env, owner_, java_buffer.obj());
78 virtual void OnRequestFinished(URLRequestAdapter* request) override {
79 JNIEnv* env = base::android::AttachCurrentThread();
80 cronet::Java_ChromiumUrlRequest_finish(env, owner_);
83 virtual int ReadFromUploadChannel(net::IOBuffer* buf,
84 int buf_length) override {
85 JNIEnv* env = base::android::AttachCurrentThread();
86 base::android::ScopedJavaLocalRef<jobject> java_buffer(
87 env, env->NewDirectByteBuffer(buf->data(), buf_length));
88 jint bytes_read = cronet::Java_ChromiumUrlRequest_readFromUploadChannel(
89 env, owner_, java_buffer.obj());
94 virtual ~JniURLRequestAdapterDelegate() {
95 JNIEnv* env = base::android::AttachCurrentThread();
96 env->DeleteGlobalRef(owner_);
102 DISALLOW_COPY_AND_ASSIGN(JniURLRequestAdapterDelegate);
107 // Explicitly register static JNI functions.
108 bool ChromiumUrlRequestRegisterJni(JNIEnv* env) {
109 return RegisterNativesImpl(env);
112 static jlong CreateRequestAdapter(JNIEnv* env,
114 jlong urlRequestContextAdapter,
117 URLRequestContextAdapter* context =
118 reinterpret_cast<URLRequestContextAdapter*>(urlRequestContextAdapter);
119 DCHECK(context != NULL);
121 GURL url(base::android::ConvertJavaStringToUTF8(env, url_string));
123 VLOG(1) << "New chromium network request: " << url.possibly_invalid_spec();
125 URLRequestAdapter* adapter =
126 new URLRequestAdapter(context,
127 new JniURLRequestAdapterDelegate(env, object),
129 ConvertRequestPriority(priority));
131 return reinterpret_cast<jlong>(adapter);
135 static void AddHeader(JNIEnv* env,
137 jlong urlRequestAdapter,
140 URLRequestAdapter* request =
141 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
144 std::string name_string(base::android::ConvertJavaStringToUTF8(env, name));
145 std::string value_string(base::android::ConvertJavaStringToUTF8(env, value));
147 request->AddHeader(name_string, value_string);
150 static void SetMethod(JNIEnv* env,
152 jlong urlRequestAdapter,
154 URLRequestAdapter* request =
155 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
158 std::string method_string(
159 base::android::ConvertJavaStringToUTF8(env, method));
161 request->SetMethod(method_string);
164 static void SetUploadData(JNIEnv* env,
166 jlong urlRequestAdapter,
167 jstring content_type,
168 jbyteArray content) {
169 URLRequestAdapter* request =
170 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
171 SetPostContentType(env, request, content_type);
173 if (content != NULL) {
174 jsize size = env->GetArrayLength(content);
176 jbyte* content_bytes = env->GetByteArrayElements(content, NULL);
177 request->SetUploadContent(reinterpret_cast<const char*>(content_bytes),
179 env->ReleaseByteArrayElements(content, content_bytes, 0);
184 static void SetUploadChannel(JNIEnv* env,
186 jlong urlRequestAdapter,
187 jstring content_type,
188 jlong content_length) {
189 URLRequestAdapter* request =
190 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
191 SetPostContentType(env, request, content_type);
193 request->SetUploadChannel(env, content_length);
196 static void EnableChunkedUpload(JNIEnv* env,
198 jlong urlRequestAdapter,
199 jstring content_type) {
200 URLRequestAdapter* request =
201 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
202 SetPostContentType(env, request, content_type);
204 request->EnableChunkedUpload();
207 static void AppendChunk(JNIEnv* env,
209 jlong urlRequestAdapter,
210 jobject chunk_byte_buffer,
212 jboolean is_last_chunk) {
213 URLRequestAdapter* request =
214 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
215 DCHECK(chunk_byte_buffer != NULL);
217 void* chunk = env->GetDirectBufferAddress(chunk_byte_buffer);
218 request->AppendChunk(
219 reinterpret_cast<const char*>(chunk), chunk_size, is_last_chunk);
223 static void Start(JNIEnv* env, jobject object, jlong urlRequestAdapter) {
224 URLRequestAdapter* request =
225 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
226 if (request != NULL) {
232 static void DestroyRequestAdapter(JNIEnv* env,
234 jlong urlRequestAdapter) {
235 URLRequestAdapter* request =
236 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
237 if (request != NULL) {
243 static void Cancel(JNIEnv* env, jobject object, jlong urlRequestAdapter) {
244 URLRequestAdapter* request =
245 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
246 if (request != NULL) {
251 static jint GetErrorCode(JNIEnv* env, jobject object, jlong urlRequestAdapter) {
252 URLRequestAdapter* request =
253 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
254 int error_code = request->error_code();
255 switch (error_code) {
256 // TODO(mef): Investigate returning success on positive values, too, as
257 // they technically indicate success.
259 return REQUEST_ERROR_SUCCESS;
261 // TODO(mef): Investigate this. The fact is that Chrome does not do this,
262 // and this library is not just being used for downloads.
264 // Comment from src/content/browser/download/download_resource_handler.cc:
265 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are
266 // allowed since a number of servers in the wild close the connection too
267 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 -
268 // treat downloads as complete in both cases, so we follow their lead.
269 case net::ERR_CONTENT_LENGTH_MISMATCH:
270 case net::ERR_INCOMPLETE_CHUNKED_ENCODING:
271 return REQUEST_ERROR_SUCCESS;
273 case net::ERR_INVALID_URL:
274 case net::ERR_DISALLOWED_URL_SCHEME:
275 case net::ERR_UNKNOWN_URL_SCHEME:
276 return REQUEST_ERROR_MALFORMED_URL;
278 case net::ERR_CONNECTION_TIMED_OUT:
279 return REQUEST_ERROR_CONNECTION_TIMED_OUT;
281 case net::ERR_NAME_NOT_RESOLVED:
282 return REQUEST_ERROR_UNKNOWN_HOST;
283 case net::ERR_TOO_MANY_REDIRECTS:
284 return REQUEST_ERROR_TOO_MANY_REDIRECTS;
286 return REQUEST_ERROR_UNKNOWN;
289 static jstring GetErrorString(JNIEnv* env,
291 jlong urlRequestAdapter) {
292 URLRequestAdapter* request =
293 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
294 int error_code = request->error_code();
296 std::string error_string = net::ErrorToString(error_code);
299 "System error: %s(%d)",
300 error_string.c_str(),
302 return ConvertUTF8ToJavaString(env, buffer).Release();
305 static jint GetHttpStatusCode(JNIEnv* env,
307 jlong urlRequestAdapter) {
308 URLRequestAdapter* request =
309 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
310 return request->http_status_code();
313 static jstring GetHttpStatusText(JNIEnv* env,
315 jlong urlRequestAdapter) {
316 URLRequestAdapter* request =
317 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
318 return ConvertUTF8ToJavaString(env, request->http_status_text()).Release();
321 static jstring GetContentType(JNIEnv* env,
323 jlong urlRequestAdapter) {
324 URLRequestAdapter* request =
325 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
326 if (request == NULL) {
329 std::string type = request->content_type();
331 return ConvertUTF8ToJavaString(env, type.c_str()).Release();
337 static jlong GetContentLength(JNIEnv* env,
339 jlong urlRequestAdapter) {
340 URLRequestAdapter* request =
341 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
342 if (request == NULL) {
345 return request->content_length();
348 static jstring GetHeader(JNIEnv* env,
350 jlong urlRequestAdapter,
352 URLRequestAdapter* request =
353 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
354 if (request == NULL) {
358 std::string name_string = base::android::ConvertJavaStringToUTF8(env, name);
359 std::string value = request->GetHeader(name_string);
360 if (!value.empty()) {
361 return ConvertUTF8ToJavaString(env, value.c_str()).Release();
367 static void GetAllHeaders(JNIEnv* env,
369 jlong urlRequestAdapter,
370 jobject headersMap) {
371 URLRequestAdapter* request =
372 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
376 net::HttpResponseHeaders* headers = request->GetResponseHeaders();
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(
389 env, object, headersMap, name.Release(), value.Release());
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(
397 env, object, headersMap, NULL, status_line.Release());
400 static jstring GetNegotiatedProtocol(JNIEnv* env,
402 jlong urlRequestAdapter) {
403 URLRequestAdapter* request =
404 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
406 return ConvertUTF8ToJavaString(env, "").Release();
408 std::string negotiated_protocol = request->GetNegotiatedProtocol();
409 return ConvertUTF8ToJavaString(env, negotiated_protocol.c_str()).Release();
412 static void DisableRedirects(JNIEnv* env, jobject jcaller,
413 jlong jrequest_adapter) {
414 URLRequestAdapter* request_adapter =
415 reinterpret_cast<URLRequestAdapter*>(jrequest_adapter);
416 if (request_adapter != NULL)
417 request_adapter->DisableRedirects();
420 } // namespace cronet