| OLD | NEW |
| (Empty) |
| 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 using base::android::ConvertJavaStringToUTF8; | |
| 19 using base::android::JavaParamRef; | |
| 20 using base::android::ScopedJavaLocalRef; | |
| 21 | |
| 22 namespace cronet { | |
| 23 namespace { | |
| 24 | |
| 25 net::RequestPriority ConvertRequestPriority(jint request_priority) { | |
| 26 switch (request_priority) { | |
| 27 case REQUEST_PRIORITY_IDLE: | |
| 28 return net::IDLE; | |
| 29 case REQUEST_PRIORITY_LOWEST: | |
| 30 return net::LOWEST; | |
| 31 case REQUEST_PRIORITY_LOW: | |
| 32 return net::LOW; | |
| 33 case REQUEST_PRIORITY_MEDIUM: | |
| 34 return net::MEDIUM; | |
| 35 case REQUEST_PRIORITY_HIGHEST: | |
| 36 return net::HIGHEST; | |
| 37 default: | |
| 38 return net::LOWEST; | |
| 39 } | |
| 40 } | |
| 41 | |
| 42 void SetPostContentType(JNIEnv* env, | |
| 43 URLRequestAdapter* request_adapter, | |
| 44 jstring content_type) { | |
| 45 std::string method_post("POST"); | |
| 46 request_adapter->SetMethod(method_post); | |
| 47 | |
| 48 std::string content_type_header("Content-Type"); | |
| 49 std::string content_type_string(ConvertJavaStringToUTF8(env, content_type)); | |
| 50 | |
| 51 request_adapter->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 void OnResponseStarted(URLRequestAdapter* request_adapter) override { | |
| 63 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 64 cronet::Java_ChromiumUrlRequest_onResponseStarted(env, owner_); | |
| 65 } | |
| 66 | |
| 67 void OnBytesRead(URLRequestAdapter* request_adapter, | |
| 68 int bytes_read) override { | |
| 69 if (bytes_read != 0) { | |
| 70 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 71 base::android::ScopedJavaLocalRef<jobject> java_buffer( | |
| 72 env, env->NewDirectByteBuffer(request_adapter->Data(), bytes_read)); | |
| 73 cronet::Java_ChromiumUrlRequest_onBytesRead(env, owner_, java_buffer); | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 void OnRequestFinished(URLRequestAdapter* request_adapter) override { | |
| 78 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 79 cronet::Java_ChromiumUrlRequest_finish(env, owner_); | |
| 80 } | |
| 81 | |
| 82 int ReadFromUploadChannel(net::IOBuffer* buf, int buf_length) override { | |
| 83 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 84 base::android::ScopedJavaLocalRef<jobject> java_buffer( | |
| 85 env, env->NewDirectByteBuffer(buf->data(), buf_length)); | |
| 86 jint bytes_read = cronet::Java_ChromiumUrlRequest_readFromUploadChannel( | |
| 87 env, owner_, java_buffer); | |
| 88 return bytes_read; | |
| 89 } | |
| 90 | |
| 91 protected: | |
| 92 ~JniURLRequestAdapterDelegate() override { | |
| 93 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 94 env->DeleteGlobalRef(owner_); | |
| 95 } | |
| 96 | |
| 97 private: | |
| 98 jobject owner_; | |
| 99 | |
| 100 DISALLOW_COPY_AND_ASSIGN(JniURLRequestAdapterDelegate); | |
| 101 }; | |
| 102 | |
| 103 } // namespace | |
| 104 | |
| 105 // Explicitly register static JNI functions. | |
| 106 bool ChromiumUrlRequestRegisterJni(JNIEnv* env) { | |
| 107 return RegisterNativesImpl(env); | |
| 108 } | |
| 109 | |
| 110 static jlong CreateRequestAdapter(JNIEnv* env, | |
| 111 const JavaParamRef<jobject>& jcaller, | |
| 112 jlong jurl_request_context_adapter, | |
| 113 const JavaParamRef<jstring>& jurl, | |
| 114 jint jrequest_priority) { | |
| 115 URLRequestContextAdapter* context_adapter = | |
| 116 reinterpret_cast<URLRequestContextAdapter*>(jurl_request_context_adapter); | |
| 117 DCHECK(context_adapter); | |
| 118 | |
| 119 GURL url(ConvertJavaStringToUTF8(env, jurl)); | |
| 120 | |
| 121 VLOG(1) << "New chromium network request: " << url.possibly_invalid_spec(); | |
| 122 | |
| 123 URLRequestAdapter* adapter = new URLRequestAdapter( | |
| 124 context_adapter, new JniURLRequestAdapterDelegate(env, jcaller), url, | |
| 125 ConvertRequestPriority(jrequest_priority)); | |
| 126 | |
| 127 return reinterpret_cast<jlong>(adapter); | |
| 128 } | |
| 129 | |
| 130 // synchronized | |
| 131 static void AddHeader(JNIEnv* env, | |
| 132 const JavaParamRef<jobject>& jcaller, | |
| 133 jlong jurl_request_adapter, | |
| 134 const JavaParamRef<jstring>& jheader_name, | |
| 135 const JavaParamRef<jstring>& jheader_value) { | |
| 136 URLRequestAdapter* request_adapter = | |
| 137 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 138 DCHECK(request_adapter); | |
| 139 | |
| 140 std::string header_name(ConvertJavaStringToUTF8(env, jheader_name)); | |
| 141 std::string header_value(ConvertJavaStringToUTF8(env, jheader_value)); | |
| 142 | |
| 143 request_adapter->AddHeader(header_name, header_value); | |
| 144 } | |
| 145 | |
| 146 static void SetMethod(JNIEnv* env, | |
| 147 const JavaParamRef<jobject>& jcaller, | |
| 148 jlong jurl_request_adapter, | |
| 149 const JavaParamRef<jstring>& jmethod) { | |
| 150 URLRequestAdapter* request_adapter = | |
| 151 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 152 DCHECK(request_adapter); | |
| 153 | |
| 154 std::string method(ConvertJavaStringToUTF8(env, jmethod)); | |
| 155 | |
| 156 request_adapter->SetMethod(method); | |
| 157 } | |
| 158 | |
| 159 static void SetUploadData(JNIEnv* env, | |
| 160 const JavaParamRef<jobject>& jcaller, | |
| 161 jlong jurl_request_adapter, | |
| 162 const JavaParamRef<jstring>& jcontent_type, | |
| 163 const JavaParamRef<jbyteArray>& jcontent) { | |
| 164 URLRequestAdapter* request_adapter = | |
| 165 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 166 DCHECK(request_adapter); | |
| 167 SetPostContentType(env, request_adapter, jcontent_type); | |
| 168 | |
| 169 if (jcontent != nullptr) { | |
| 170 jsize size = env->GetArrayLength(jcontent); | |
| 171 if (size > 0) { | |
| 172 jbyte* content_bytes = env->GetByteArrayElements(jcontent, nullptr); | |
| 173 request_adapter->SetUploadContent( | |
| 174 reinterpret_cast<const char*>(content_bytes), size); | |
| 175 env->ReleaseByteArrayElements(jcontent, content_bytes, 0); | |
| 176 } | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 static void SetUploadChannel(JNIEnv* env, | |
| 181 const JavaParamRef<jobject>& jcaller, | |
| 182 jlong jurl_request_adapter, | |
| 183 const JavaParamRef<jstring>& jcontent_type, | |
| 184 jlong jcontent_length) { | |
| 185 URLRequestAdapter* request_adapter = | |
| 186 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 187 DCHECK(request_adapter); | |
| 188 SetPostContentType(env, request_adapter, jcontent_type); | |
| 189 | |
| 190 request_adapter->SetUploadChannel(env, jcontent_length); | |
| 191 } | |
| 192 | |
| 193 static void EnableChunkedUpload(JNIEnv* env, | |
| 194 const JavaParamRef<jobject>& jcaller, | |
| 195 jlong jurl_request_adapter, | |
| 196 const JavaParamRef<jstring>& jcontent_type) { | |
| 197 URLRequestAdapter* request_adapter = | |
| 198 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 199 DCHECK(request_adapter); | |
| 200 SetPostContentType(env, request_adapter, jcontent_type); | |
| 201 | |
| 202 request_adapter->EnableChunkedUpload(); | |
| 203 } | |
| 204 | |
| 205 static void AppendChunk(JNIEnv* env, | |
| 206 const JavaParamRef<jobject>& jcaller, | |
| 207 jlong jurl_request_adapter, | |
| 208 const JavaParamRef<jobject>& jchunk_byte_buffer, | |
| 209 jint jchunk_size, | |
| 210 jboolean jis_last_chunk) { | |
| 211 URLRequestAdapter* request_adapter = | |
| 212 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 213 DCHECK(request_adapter); | |
| 214 DCHECK(jchunk_byte_buffer); | |
| 215 | |
| 216 void* chunk = env->GetDirectBufferAddress(jchunk_byte_buffer); | |
| 217 request_adapter->AppendChunk(reinterpret_cast<const char*>(chunk), | |
| 218 jchunk_size, jis_last_chunk); | |
| 219 } | |
| 220 | |
| 221 /* synchronized */ | |
| 222 static void Start(JNIEnv* env, | |
| 223 const JavaParamRef<jobject>& jcaller, | |
| 224 jlong jurl_request_adapter) { | |
| 225 URLRequestAdapter* request_adapter = | |
| 226 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 227 if (request_adapter != nullptr) | |
| 228 request_adapter->Start(); | |
| 229 } | |
| 230 | |
| 231 /* synchronized */ | |
| 232 static void DestroyRequestAdapter(JNIEnv* env, | |
| 233 const JavaParamRef<jobject>& jcaller, | |
| 234 jlong jurl_request_adapter) { | |
| 235 URLRequestAdapter* request_adapter = | |
| 236 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 237 if (request_adapter != nullptr) | |
| 238 request_adapter->Destroy(); | |
| 239 } | |
| 240 | |
| 241 /* synchronized */ | |
| 242 static void Cancel(JNIEnv* env, | |
| 243 const JavaParamRef<jobject>& jcaller, | |
| 244 jlong jurl_request_adapter) { | |
| 245 URLRequestAdapter* request_adapter = | |
| 246 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 247 if (request_adapter != nullptr) | |
| 248 request_adapter->Cancel(); | |
| 249 } | |
| 250 | |
| 251 static jint GetErrorCode(JNIEnv* env, | |
| 252 const JavaParamRef<jobject>& jcaller, | |
| 253 jlong jurl_request_adapter) { | |
| 254 URLRequestAdapter* request_adapter = | |
| 255 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 256 DCHECK(request_adapter); | |
| 257 int error_code = request_adapter->error_code(); | |
| 258 switch (error_code) { | |
| 259 // TODO(mef): Investigate returning success on positive values, too, as | |
| 260 // they technically indicate success. | |
| 261 case net::OK: | |
| 262 return REQUEST_ERROR_SUCCESS; | |
| 263 | |
| 264 // TODO(mef): Investigate this. The fact is that Chrome does not do this, | |
| 265 // and this library is not just being used for downloads. | |
| 266 | |
| 267 // Comment from src/content/browser/download/download_resource_handler.cc: | |
| 268 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are | |
| 269 // allowed since a number of servers in the wild close the connection too | |
| 270 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 - | |
| 271 // treat downloads as complete in both cases, so we follow their lead. | |
| 272 case net::ERR_CONTENT_LENGTH_MISMATCH: | |
| 273 case net::ERR_INCOMPLETE_CHUNKED_ENCODING: | |
| 274 return REQUEST_ERROR_SUCCESS; | |
| 275 | |
| 276 case net::ERR_INVALID_URL: | |
| 277 case net::ERR_DISALLOWED_URL_SCHEME: | |
| 278 case net::ERR_UNKNOWN_URL_SCHEME: | |
| 279 return REQUEST_ERROR_MALFORMED_URL; | |
| 280 | |
| 281 case net::ERR_CONNECTION_TIMED_OUT: | |
| 282 return REQUEST_ERROR_CONNECTION_TIMED_OUT; | |
| 283 | |
| 284 case net::ERR_NAME_NOT_RESOLVED: | |
| 285 return REQUEST_ERROR_UNKNOWN_HOST; | |
| 286 case net::ERR_TOO_MANY_REDIRECTS: | |
| 287 return REQUEST_ERROR_TOO_MANY_REDIRECTS; | |
| 288 } | |
| 289 return REQUEST_ERROR_UNKNOWN; | |
| 290 } | |
| 291 | |
| 292 static ScopedJavaLocalRef<jstring> GetErrorString( | |
| 293 JNIEnv* env, | |
| 294 const JavaParamRef<jobject>& jcaller, | |
| 295 jlong jurl_request_adapter) { | |
| 296 URLRequestAdapter* request_adapter = | |
| 297 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 298 DCHECK(request_adapter); | |
| 299 int error_code = request_adapter->error_code(); | |
| 300 char buffer[200]; | |
| 301 std::string error_string = net::ErrorToString(error_code); | |
| 302 snprintf(buffer, | |
| 303 sizeof(buffer), | |
| 304 "System error: %s(%d)", | |
| 305 error_string.c_str(), | |
| 306 error_code); | |
| 307 return ConvertUTF8ToJavaString(env, buffer); | |
| 308 } | |
| 309 | |
| 310 static jint GetHttpStatusCode(JNIEnv* env, | |
| 311 const JavaParamRef<jobject>& jcaller, | |
| 312 jlong jurl_request_adapter) { | |
| 313 URLRequestAdapter* request_adapter = | |
| 314 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 315 DCHECK(request_adapter); | |
| 316 return request_adapter->http_status_code(); | |
| 317 } | |
| 318 | |
| 319 static ScopedJavaLocalRef<jstring> GetHttpStatusText( | |
| 320 JNIEnv* env, | |
| 321 const JavaParamRef<jobject>& jcaller, | |
| 322 jlong jurl_request_adapter) { | |
| 323 URLRequestAdapter* request_adapter = | |
| 324 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 325 DCHECK(request_adapter); | |
| 326 return ConvertUTF8ToJavaString(env, request_adapter->http_status_text()); | |
| 327 } | |
| 328 | |
| 329 static ScopedJavaLocalRef<jstring> GetContentType( | |
| 330 JNIEnv* env, | |
| 331 const JavaParamRef<jobject>& jcaller, | |
| 332 jlong jurl_request_adapter) { | |
| 333 URLRequestAdapter* request_adapter = | |
| 334 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 335 DCHECK(request_adapter); | |
| 336 std::string type = request_adapter->content_type(); | |
| 337 if (!type.empty()) { | |
| 338 return ConvertUTF8ToJavaString(env, type.c_str()); | |
| 339 } else { | |
| 340 return ScopedJavaLocalRef<jstring>(); | |
| 341 } | |
| 342 } | |
| 343 | |
| 344 static jlong GetContentLength(JNIEnv* env, | |
| 345 const JavaParamRef<jobject>& jcaller, | |
| 346 jlong jurl_request_adapter) { | |
| 347 URLRequestAdapter* request_adapter = | |
| 348 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 349 DCHECK(request_adapter); | |
| 350 return request_adapter->content_length(); | |
| 351 } | |
| 352 | |
| 353 static ScopedJavaLocalRef<jstring> GetHeader( | |
| 354 JNIEnv* env, | |
| 355 const JavaParamRef<jobject>& jcaller, | |
| 356 jlong jurl_request_adapter, | |
| 357 const JavaParamRef<jstring>& jheader_name) { | |
| 358 URLRequestAdapter* request_adapter = | |
| 359 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 360 DCHECK(request_adapter); | |
| 361 std::string header_name = ConvertJavaStringToUTF8(env, jheader_name); | |
| 362 std::string header_value = request_adapter->GetHeader(header_name); | |
| 363 if (!header_value.empty()) | |
| 364 return ConvertUTF8ToJavaString(env, header_value.c_str()); | |
| 365 return ScopedJavaLocalRef<jstring>(); | |
| 366 } | |
| 367 | |
| 368 static void GetAllHeaders(JNIEnv* env, | |
| 369 const JavaParamRef<jobject>& jcaller, | |
| 370 jlong jurl_request_adapter, | |
| 371 const JavaParamRef<jobject>& jheaders_map) { | |
| 372 URLRequestAdapter* request_adapter = | |
| 373 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 374 DCHECK(request_adapter); | |
| 375 | |
| 376 net::HttpResponseHeaders* headers = request_adapter->GetResponseHeaders(); | |
| 377 if (headers == nullptr) | |
| 378 return; | |
| 379 | |
| 380 size_t iter = 0; | |
| 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(env, jcaller, jheaders_map, | |
| 389 name, value); | |
| 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(env, jcaller, jheaders_map, | |
| 397 nullptr, status_line); | |
| 398 } | |
| 399 | |
| 400 static ScopedJavaLocalRef<jstring> GetNegotiatedProtocol( | |
| 401 JNIEnv* env, | |
| 402 const JavaParamRef<jobject>& jcaller, | |
| 403 jlong jurl_request_adapter) { | |
| 404 URLRequestAdapter* request_adapter = | |
| 405 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 406 DCHECK(request_adapter); | |
| 407 | |
| 408 std::string negotiated_protocol = request_adapter->GetNegotiatedProtocol(); | |
| 409 return ConvertUTF8ToJavaString(env, negotiated_protocol.c_str()); | |
| 410 } | |
| 411 | |
| 412 static jboolean GetWasCached(JNIEnv* env, | |
| 413 const JavaParamRef<jobject>& jcaller, | |
| 414 jlong jurl_request_adapter) { | |
| 415 URLRequestAdapter* request_adapter = | |
| 416 reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter); | |
| 417 DCHECK(request_adapter); | |
| 418 | |
| 419 bool was_cached = request_adapter->GetWasCached(); | |
| 420 return was_cached ? JNI_TRUE : JNI_FALSE; | |
| 421 } | |
| 422 | |
| 423 static void DisableRedirects(JNIEnv* env, | |
| 424 const JavaParamRef<jobject>& jcaller, | |
| 425 jlong jrequest_adapter) { | |
| 426 URLRequestAdapter* request_adapter = | |
| 427 reinterpret_cast<URLRequestAdapter*>(jrequest_adapter); | |
| 428 DCHECK(request_adapter); | |
| 429 request_adapter->DisableRedirects(); | |
| 430 } | |
| 431 | |
| 432 } // namespace cronet | |
| OLD | NEW |