Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / components / cronet / android / chromium_url_request.cc
blob48db19721e75c04bd5e2181a096214ed2b5394d1
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;
19 namespace cronet {
20 namespace {
22 net::RequestPriority ConvertRequestPriority(jint request_priority) {
23 switch (request_priority) {
24 case REQUEST_PRIORITY_IDLE:
25 return net::IDLE;
26 case REQUEST_PRIORITY_LOWEST:
27 return net::LOWEST;
28 case REQUEST_PRIORITY_LOW:
29 return net::LOW;
30 case REQUEST_PRIORITY_MEDIUM:
31 return net::MEDIUM;
32 case REQUEST_PRIORITY_HIGHEST:
33 return net::HIGHEST;
34 default:
35 return net::LOWEST;
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");
49 const char* content_type_utf8 = env->GetStringUTFChars(content_type, NULL);
50 std::string content_type_string(content_type_utf8);
51 env->ReleaseStringUTFChars(content_type, content_type_utf8);
53 request->AddHeader(content_type_header, content_type_string);
56 // A delegate of URLRequestAdapter that delivers callbacks to the Java layer.
57 class JniURLRequestAdapterDelegate
58 : public URLRequestAdapter::URLRequestAdapterDelegate {
59 public:
60 JniURLRequestAdapterDelegate(JNIEnv* env, jobject owner) {
61 owner_ = env->NewGlobalRef(owner);
64 virtual void OnResponseStarted(URLRequestAdapter* request) OVERRIDE {
65 JNIEnv* env = base::android::AttachCurrentThread();
66 cronet::Java_ChromiumUrlRequest_onResponseStarted(env, owner_);
69 virtual void OnBytesRead(URLRequestAdapter* request) OVERRIDE {
70 int bytes_read = request->bytes_read();
71 if (bytes_read != 0) {
72 JNIEnv* env = base::android::AttachCurrentThread();
73 base::android::ScopedJavaLocalRef<jobject> java_buffer(
74 env, env->NewDirectByteBuffer(request->Data(), bytes_read));
75 cronet::Java_ChromiumUrlRequest_onBytesRead(
76 env, owner_, java_buffer.obj());
80 virtual void OnRequestFinished(URLRequestAdapter* request) OVERRIDE {
81 JNIEnv* env = base::android::AttachCurrentThread();
82 cronet::Java_ChromiumUrlRequest_finish(env, owner_);
85 virtual int ReadFromUploadChannel(net::IOBuffer* buf,
86 int buf_length) OVERRIDE {
87 JNIEnv* env = base::android::AttachCurrentThread();
88 base::android::ScopedJavaLocalRef<jobject> java_buffer(
89 env, env->NewDirectByteBuffer(buf->data(), buf_length));
90 jint bytes_read = cronet::Java_ChromiumUrlRequest_readFromUploadChannel(
91 env, owner_, java_buffer.obj());
92 return bytes_read;
95 protected:
96 virtual ~JniURLRequestAdapterDelegate() {
97 JNIEnv* env = base::android::AttachCurrentThread();
98 env->DeleteGlobalRef(owner_);
101 private:
102 jobject owner_;
104 DISALLOW_COPY_AND_ASSIGN(JniURLRequestAdapterDelegate);
107 } // namespace
109 // Explicitly register static JNI functions.
110 bool ChromiumUrlRequestRegisterJni(JNIEnv* env) {
111 return RegisterNativesImpl(env);
114 static jlong CreateRequestAdapter(JNIEnv* env,
115 jobject object,
116 jlong urlRequestContextAdapter,
117 jstring url_string,
118 jint priority) {
119 URLRequestContextAdapter* context =
120 reinterpret_cast<URLRequestContextAdapter*>(urlRequestContextAdapter);
121 DCHECK(context != NULL);
123 const char* url_utf8 = env->GetStringUTFChars(url_string, NULL);
125 VLOG(1) << "New chromium network request. URL:" << url_utf8;
127 GURL url(url_utf8);
129 env->ReleaseStringUTFChars(url_string, url_utf8);
131 URLRequestAdapter* adapter =
132 new URLRequestAdapter(context,
133 new JniURLRequestAdapterDelegate(env, object),
134 url,
135 ConvertRequestPriority(priority));
137 return reinterpret_cast<jlong>(adapter);
140 // synchronized
141 static void AddHeader(JNIEnv* env,
142 jobject object,
143 jlong urlRequestAdapter,
144 jstring name,
145 jstring value) {
146 URLRequestAdapter* request =
147 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
148 DCHECK(request);
150 std::string name_string(base::android::ConvertJavaStringToUTF8(env, name));
151 std::string value_string(base::android::ConvertJavaStringToUTF8(env, value));
153 request->AddHeader(name_string, value_string);
156 static void SetMethod(JNIEnv* env,
157 jobject object,
158 jlong urlRequestAdapter,
159 jstring method) {
160 URLRequestAdapter* request =
161 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
162 DCHECK(request);
164 std::string method_string(
165 base::android::ConvertJavaStringToUTF8(env, method));
167 request->SetMethod(method_string);
170 static void SetUploadData(JNIEnv* env,
171 jobject object,
172 jlong urlRequestAdapter,
173 jstring content_type,
174 jbyteArray content) {
175 URLRequestAdapter* request =
176 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
177 SetPostContentType(env, request, content_type);
179 if (content != NULL) {
180 jsize size = env->GetArrayLength(content);
181 if (size > 0) {
182 jbyte* content_bytes = env->GetByteArrayElements(content, NULL);
183 request->SetUploadContent(reinterpret_cast<const char*>(content_bytes),
184 size);
185 env->ReleaseByteArrayElements(content, content_bytes, 0);
190 static void SetUploadChannel(JNIEnv* env,
191 jobject object,
192 jlong urlRequestAdapter,
193 jstring content_type,
194 jlong content_length) {
195 URLRequestAdapter* request =
196 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
197 SetPostContentType(env, request, content_type);
199 request->SetUploadChannel(env, content_length);
202 static void EnableChunkedUpload(JNIEnv* env,
203 jobject object,
204 jlong urlRequestAdapter,
205 jstring content_type) {
206 URLRequestAdapter* request =
207 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
208 SetPostContentType(env, request, content_type);
210 request->EnableChunkedUpload();
213 static void AppendChunk(JNIEnv* env,
214 jobject object,
215 jlong urlRequestAdapter,
216 jobject chunk_byte_buffer,
217 jint chunk_size,
218 jboolean is_last_chunk) {
219 URLRequestAdapter* request =
220 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
221 DCHECK(chunk_byte_buffer != NULL);
223 void* chunk = env->GetDirectBufferAddress(chunk_byte_buffer);
224 request->AppendChunk(
225 reinterpret_cast<const char*>(chunk), chunk_size, is_last_chunk);
228 /* synchronized */
229 static void Start(JNIEnv* env, jobject object, jlong urlRequestAdapter) {
230 URLRequestAdapter* request =
231 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
232 if (request != NULL) {
233 request->Start();
237 /* synchronized */
238 static void DestroyRequestAdapter(JNIEnv* env,
239 jobject object,
240 jlong urlRequestAdapter) {
241 URLRequestAdapter* request =
242 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
243 if (request != NULL) {
244 request->Destroy();
248 /* synchronized */
249 static void Cancel(JNIEnv* env, jobject object, jlong urlRequestAdapter) {
250 URLRequestAdapter* request =
251 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
252 if (request != NULL) {
253 request->Cancel();
257 static jint GetErrorCode(JNIEnv* env, jobject object, jlong urlRequestAdapter) {
258 URLRequestAdapter* request =
259 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
260 int error_code = request->error_code();
261 switch (error_code) {
262 // TODO(mef): Investigate returning success on positive values, too, as
263 // they technically indicate success.
264 case net::OK:
265 return REQUEST_ERROR_SUCCESS;
267 // TODO(mef): Investigate this. The fact is that Chrome does not do this,
268 // and this library is not just being used for downloads.
270 // Comment from src/content/browser/download/download_resource_handler.cc:
271 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are
272 // allowed since a number of servers in the wild close the connection too
273 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 -
274 // treat downloads as complete in both cases, so we follow their lead.
275 case net::ERR_CONTENT_LENGTH_MISMATCH:
276 case net::ERR_INCOMPLETE_CHUNKED_ENCODING:
277 return REQUEST_ERROR_SUCCESS;
279 case net::ERR_INVALID_URL:
280 case net::ERR_DISALLOWED_URL_SCHEME:
281 case net::ERR_UNKNOWN_URL_SCHEME:
282 return REQUEST_ERROR_MALFORMED_URL;
284 case net::ERR_CONNECTION_TIMED_OUT:
285 return REQUEST_ERROR_CONNECTION_TIMED_OUT;
287 case net::ERR_NAME_NOT_RESOLVED:
288 return REQUEST_ERROR_UNKNOWN_HOST;
290 return REQUEST_ERROR_UNKNOWN;
293 static jstring GetErrorString(JNIEnv* env,
294 jobject object,
295 jlong urlRequestAdapter) {
296 URLRequestAdapter* request =
297 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
298 int error_code = request->error_code();
299 char buffer[200];
300 std::string error_string = net::ErrorToString(error_code);
301 snprintf(buffer,
302 sizeof(buffer),
303 "System error: %s(%d)",
304 error_string.c_str(),
305 error_code);
306 return ConvertUTF8ToJavaString(env, buffer).Release();
309 static jint GetHttpStatusCode(JNIEnv* env,
310 jobject object,
311 jlong urlRequestAdapter) {
312 URLRequestAdapter* request =
313 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
314 return request->http_status_code();
317 static jstring GetContentType(JNIEnv* env,
318 jobject object,
319 jlong urlRequestAdapter) {
320 URLRequestAdapter* request =
321 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
322 if (request == NULL) {
323 return NULL;
325 std::string type = request->content_type();
326 if (!type.empty()) {
327 return ConvertUTF8ToJavaString(env, type.c_str()).Release();
328 } else {
329 return NULL;
333 static jlong GetContentLength(JNIEnv* env,
334 jobject object,
335 jlong urlRequestAdapter) {
336 URLRequestAdapter* request =
337 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
338 if (request == NULL) {
339 return 0;
341 return request->content_length();
344 static jstring GetHeader(JNIEnv* env,
345 jobject object,
346 jlong urlRequestAdapter,
347 jstring name) {
348 URLRequestAdapter* request =
349 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
350 if (request == NULL) {
351 return NULL;
354 std::string name_string = base::android::ConvertJavaStringToUTF8(env, name);
355 std::string value = request->GetHeader(name_string);
356 if (!value.empty()) {
357 return ConvertUTF8ToJavaString(env, value.c_str()).Release();
358 } else {
359 return NULL;
363 static void GetAllHeaders(JNIEnv* env,
364 jobject object,
365 jlong urlRequestAdapter,
366 jobject headersMap) {
367 URLRequestAdapter* request =
368 reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
369 if (request == NULL)
370 return;
372 net::HttpResponseHeaders* headers = request->GetResponseHeaders();
373 if (headers == NULL)
374 return;
376 void* iter = NULL;
377 std::string header_name;
378 std::string header_value;
379 while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) {
380 ScopedJavaLocalRef<jstring> name =
381 ConvertUTF8ToJavaString(env, header_name);
382 ScopedJavaLocalRef<jstring> value =
383 ConvertUTF8ToJavaString(env, header_value);
384 Java_ChromiumUrlRequest_onAppendResponseHeader(
385 env, object, headersMap, name.Release(), value.Release());
388 // Some implementations (notably HttpURLConnection) include a mapping for the
389 // null key; in HTTP's case, this maps to the HTTP status line.
390 ScopedJavaLocalRef<jstring> status_line =
391 ConvertUTF8ToJavaString(env, headers->GetStatusLine());
392 Java_ChromiumUrlRequest_onAppendResponseHeader(
393 env, object, headersMap, NULL, status_line.Release());
396 } // namespace cronet