Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / components / cronet / android / chromium_url_request.cc
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
19 namespace cronet {
20 namespace {
21
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;
36   }
37 }
38
39 void SetPostContentType(JNIEnv* env,
40                         URLRequestAdapter* request,
41                         jstring content_type) {
42   DCHECK(request != NULL);
43
44   std::string method_post("POST");
45   request->SetMethod(method_post);
46
47   std::string content_type_header("Content-Type");
48   std::string content_type_string(
49       base::android::ConvertJavaStringToUTF8(env, content_type));
50
51   request->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   virtual void OnResponseStarted(URLRequestAdapter* request) override {
63     JNIEnv* env = base::android::AttachCurrentThread();
64     cronet::Java_ChromiumUrlRequest_onResponseStarted(env, owner_);
65   }
66
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());
75     }
76   }
77
78   virtual void OnRequestFinished(URLRequestAdapter* request) override {
79     JNIEnv* env = base::android::AttachCurrentThread();
80     cronet::Java_ChromiumUrlRequest_finish(env, owner_);
81   }
82
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());
90     return bytes_read;
91   }
92
93  protected:
94   virtual ~JniURLRequestAdapterDelegate() {
95     JNIEnv* env = base::android::AttachCurrentThread();
96     env->DeleteGlobalRef(owner_);
97   }
98
99  private:
100   jobject owner_;
101
102   DISALLOW_COPY_AND_ASSIGN(JniURLRequestAdapterDelegate);
103 };
104
105 }  // namespace
106
107 // Explicitly register static JNI functions.
108 bool ChromiumUrlRequestRegisterJni(JNIEnv* env) {
109   return RegisterNativesImpl(env);
110 }
111
112 static jlong CreateRequestAdapter(JNIEnv* env,
113                                   jobject object,
114                                   jlong urlRequestContextAdapter,
115                                   jstring url_string,
116                                   jint priority) {
117   URLRequestContextAdapter* context =
118       reinterpret_cast<URLRequestContextAdapter*>(urlRequestContextAdapter);
119   DCHECK(context != NULL);
120
121   GURL url(base::android::ConvertJavaStringToUTF8(env, url_string));
122
123   VLOG(1) << "New chromium network request: " << url.possibly_invalid_spec();
124
125   URLRequestAdapter* adapter =
126       new URLRequestAdapter(context,
127                             new JniURLRequestAdapterDelegate(env, object),
128                             url,
129                             ConvertRequestPriority(priority));
130
131   return reinterpret_cast<jlong>(adapter);
132 }
133
134 // synchronized
135 static void AddHeader(JNIEnv* env,
136                       jobject object,
137                       jlong urlRequestAdapter,
138                       jstring name,
139                       jstring value) {
140   URLRequestAdapter* request =
141       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
142   DCHECK(request);
143
144   std::string name_string(base::android::ConvertJavaStringToUTF8(env, name));
145   std::string value_string(base::android::ConvertJavaStringToUTF8(env, value));
146
147   request->AddHeader(name_string, value_string);
148 }
149
150 static void SetMethod(JNIEnv* env,
151                       jobject object,
152                       jlong urlRequestAdapter,
153                       jstring method) {
154   URLRequestAdapter* request =
155       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
156   DCHECK(request);
157
158   std::string method_string(
159       base::android::ConvertJavaStringToUTF8(env, method));
160
161   request->SetMethod(method_string);
162 }
163
164 static void SetUploadData(JNIEnv* env,
165                           jobject object,
166                           jlong urlRequestAdapter,
167                           jstring content_type,
168                           jbyteArray content) {
169   URLRequestAdapter* request =
170       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
171   SetPostContentType(env, request, content_type);
172
173   if (content != NULL) {
174     jsize size = env->GetArrayLength(content);
175     if (size > 0) {
176       jbyte* content_bytes = env->GetByteArrayElements(content, NULL);
177       request->SetUploadContent(reinterpret_cast<const char*>(content_bytes),
178                                 size);
179       env->ReleaseByteArrayElements(content, content_bytes, 0);
180     }
181   }
182 }
183
184 static void SetUploadChannel(JNIEnv* env,
185                              jobject object,
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);
192
193   request->SetUploadChannel(env, content_length);
194 }
195
196 static void EnableChunkedUpload(JNIEnv* env,
197                                jobject object,
198                                jlong urlRequestAdapter,
199                                jstring content_type) {
200   URLRequestAdapter* request =
201       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
202   SetPostContentType(env, request, content_type);
203
204   request->EnableChunkedUpload();
205 }
206
207 static void AppendChunk(JNIEnv* env,
208                         jobject object,
209                         jlong urlRequestAdapter,
210                         jobject chunk_byte_buffer,
211                         jint chunk_size,
212                         jboolean is_last_chunk) {
213   URLRequestAdapter* request =
214       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
215   DCHECK(chunk_byte_buffer != NULL);
216
217   void* chunk = env->GetDirectBufferAddress(chunk_byte_buffer);
218   request->AppendChunk(
219       reinterpret_cast<const char*>(chunk), chunk_size, is_last_chunk);
220 }
221
222 /* synchronized */
223 static void Start(JNIEnv* env, jobject object, jlong urlRequestAdapter) {
224   URLRequestAdapter* request =
225       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
226   if (request != NULL) {
227     request->Start();
228   }
229 }
230
231 /* synchronized */
232 static void DestroyRequestAdapter(JNIEnv* env,
233                                   jobject object,
234                                   jlong urlRequestAdapter) {
235   URLRequestAdapter* request =
236       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
237   if (request != NULL) {
238     request->Destroy();
239   }
240 }
241
242 /* synchronized */
243 static void Cancel(JNIEnv* env, jobject object, jlong urlRequestAdapter) {
244   URLRequestAdapter* request =
245       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
246   if (request != NULL) {
247     request->Cancel();
248   }
249 }
250
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.
258     case net::OK:
259       return REQUEST_ERROR_SUCCESS;
260
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.
263
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;
272
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;
277
278     case net::ERR_CONNECTION_TIMED_OUT:
279       return REQUEST_ERROR_CONNECTION_TIMED_OUT;
280
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;
285   }
286   return REQUEST_ERROR_UNKNOWN;
287 }
288
289 static jstring GetErrorString(JNIEnv* env,
290                               jobject object,
291                               jlong urlRequestAdapter) {
292   URLRequestAdapter* request =
293       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
294   int error_code = request->error_code();
295   char buffer[200];
296   std::string error_string = net::ErrorToString(error_code);
297   snprintf(buffer,
298            sizeof(buffer),
299            "System error: %s(%d)",
300            error_string.c_str(),
301            error_code);
302   return ConvertUTF8ToJavaString(env, buffer).Release();
303 }
304
305 static jint GetHttpStatusCode(JNIEnv* env,
306                               jobject object,
307                               jlong urlRequestAdapter) {
308   URLRequestAdapter* request =
309       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
310   return request->http_status_code();
311 }
312
313 static jstring GetHttpStatusText(JNIEnv* env,
314                                  jobject object,
315                                  jlong urlRequestAdapter) {
316   URLRequestAdapter* request =
317       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
318   return ConvertUTF8ToJavaString(env, request->http_status_text()).Release();
319 }
320
321 static jstring GetContentType(JNIEnv* env,
322                               jobject object,
323                               jlong urlRequestAdapter) {
324   URLRequestAdapter* request =
325       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
326   if (request == NULL) {
327     return NULL;
328   }
329   std::string type = request->content_type();
330   if (!type.empty()) {
331     return ConvertUTF8ToJavaString(env, type.c_str()).Release();
332   } else {
333     return NULL;
334   }
335 }
336
337 static jlong GetContentLength(JNIEnv* env,
338                               jobject object,
339                               jlong urlRequestAdapter) {
340   URLRequestAdapter* request =
341       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
342   if (request == NULL) {
343     return 0;
344   }
345   return request->content_length();
346 }
347
348 static jstring GetHeader(JNIEnv* env,
349                          jobject object,
350                          jlong urlRequestAdapter,
351                          jstring name) {
352   URLRequestAdapter* request =
353       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
354   if (request == NULL) {
355     return NULL;
356   }
357
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();
362   } else {
363     return NULL;
364   }
365 }
366
367 static void GetAllHeaders(JNIEnv* env,
368                           jobject object,
369                           jlong urlRequestAdapter,
370                           jobject headersMap) {
371   URLRequestAdapter* request =
372       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
373   if (request == NULL)
374     return;
375
376   net::HttpResponseHeaders* headers = request->GetResponseHeaders();
377   if (headers == NULL)
378     return;
379
380   void* iter = NULL;
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());
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(
397       env, object, headersMap, NULL, status_line.Release());
398 }
399
400 static jstring GetNegotiatedProtocol(JNIEnv* env,
401                                      jobject object,
402                                      jlong urlRequestAdapter) {
403   URLRequestAdapter* request =
404       reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
405   if (request == NULL)
406     return ConvertUTF8ToJavaString(env, "").Release();
407
408   std::string negotiated_protocol = request->GetNegotiatedProtocol();
409   return ConvertUTF8ToJavaString(env, negotiated_protocol.c_str()).Release();
410 }
411
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();
418 }
419
420 }  // namespace cronet