Chromium Code Reviews| 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 "net/cronet/android/org_chromium_net_UrlRequest.h" | |
| 6 | |
| 7 #include <stdio.h> | |
| 8 | |
| 9 #include "net/base/net_errors.h" | |
| 10 #include "net/base/request_priority.h" | |
| 11 #include "net/cronet/android/org_chromium_net_UrlRequestContext.h" | |
| 12 #include "net/cronet/android/url_request_context_peer.h" | |
| 13 #include "net/cronet/android/url_request_peer.h" | |
| 14 | |
| 15 // TODO(mef): Replace following definitions with generated UrlRequest_jni.h | |
| 16 //#include "jni/UrlRequest_jni.h" | |
| 17 namespace { | |
| 18 | |
| 19 jclass g_class; | |
| 20 jmethodID g_method_finish; | |
| 21 jmethodID g_method_onAppendChunkCompleted; | |
| 22 jmethodID g_method_onResponseStarted; | |
| 23 jmethodID g_method_onReadBytes; | |
| 24 jclass g_class_OutputStream; | |
| 25 jmethodID g_method_write; | |
| 26 jfieldID g_request_field; | |
| 27 | |
| 28 net::RequestPriority ConvertRequestPriority(jint request_priority) { | |
| 29 switch (request_priority) { | |
| 30 case REQUEST_PRIORITY_IDLE: | |
| 31 return net::IDLE; | |
| 32 case REQUEST_PRIORITY_LOWEST: | |
| 33 return net::LOWEST; | |
| 34 case REQUEST_PRIORITY_LOW: | |
| 35 return net::LOW; | |
| 36 case REQUEST_PRIORITY_MEDIUM: | |
| 37 return net::MEDIUM; | |
| 38 case REQUEST_PRIORITY_HIGHEST: | |
| 39 return net::HIGHEST; | |
| 40 default: | |
| 41 return net::LOWEST; | |
| 42 } | |
| 43 } | |
| 44 | |
| 45 // Stores a reference to the request in a java field. | |
| 46 void SetNativeObject(JNIEnv* env, jobject object, URLRequestPeer* request) { | |
| 47 env->SetLongField(object, g_request_field, reinterpret_cast<jlong>(request)); | |
| 48 } | |
| 49 | |
| 50 // Returns a reference to the request, which is stored in a field of the Java | |
| 51 // object. | |
| 52 static URLRequestPeer* GetNativeObject(JNIEnv* env, jobject object) { | |
|
mmenke
2014/03/04 19:36:20
nit: --static
mef
2014/03/05 20:54:13
Done.
| |
| 53 return reinterpret_cast<URLRequestPeer*>( | |
| 54 env->GetLongField(object, g_request_field)); | |
| 55 } | |
| 56 | |
| 57 void SetPostContentType(JNIEnv* env, | |
| 58 URLRequestPeer* request, | |
| 59 jstring content_type) { | |
| 60 DCHECK(request != NULL); | |
| 61 | |
| 62 std::string method_post("POST"); | |
| 63 request->SetMethod(method_post); | |
| 64 | |
| 65 std::string content_type_header("Content-Type"); | |
| 66 | |
| 67 const char* content_type_utf8 = env->GetStringUTFChars(content_type, NULL); | |
| 68 std::string content_type_string(content_type_utf8); | |
| 69 env->ReleaseStringUTFChars(content_type, content_type_utf8); | |
| 70 | |
| 71 request->AddHeader(content_type_header, content_type_string); | |
| 72 } | |
| 73 | |
| 74 } // namespace | |
| 75 | |
| 76 // Find Java classes and retain them. | |
| 77 bool UrlRequestRegisterJni(JNIEnv* env) { | |
| 78 g_class = | |
| 79 (jclass)env->NewGlobalRef(env->FindClass("org/chromium/net/UrlRequest")); | |
|
mmenke
2014/03/04 19:36:20
nit: C-style casts are forbidden.
mef
2014/03/05 20:54:13
Done.
| |
| 80 g_method_finish = env->GetMethodID(g_class, "finish", "()V"); | |
| 81 g_method_onAppendChunkCompleted = | |
| 82 env->GetMethodID(g_class, "onAppendChunkCompleted", "()V"); | |
| 83 g_method_onResponseStarted = | |
| 84 env->GetMethodID(g_class, "onResponseStarted", "()V"); | |
| 85 g_method_onReadBytes = | |
| 86 env->GetMethodID(g_class, "onBytesRead", "(Ljava/nio/ByteBuffer;)V"); | |
| 87 g_request_field = env->GetFieldID(g_class, "mRequest", "J"); | |
| 88 | |
| 89 g_class_OutputStream = | |
| 90 (jclass)env->NewGlobalRef(env->FindClass("java/io/OutputStream")); | |
|
mmenke
2014/03/04 19:36:20
nit: C-style casts are forbidden.
mef
2014/03/05 20:54:13
Done.
| |
| 91 g_method_write = env->GetMethodID(g_class_OutputStream, "write", "([BII)V"); | |
| 92 | |
| 93 if (!g_class || !g_method_finish || !g_method_onAppendChunkCompleted || | |
| 94 !g_method_onResponseStarted || !g_method_onReadBytes || | |
| 95 !g_request_field || !g_class_OutputStream || !g_method_write) { | |
| 96 return false; | |
| 97 } | |
| 98 return true; | |
| 99 } | |
| 100 | |
| 101 // A delegate of URLRequestPeer that delivers callbacks to the Java layer. | |
| 102 class JniURLRequestPeerDelegate | |
| 103 : public URLRequestPeer::URLRequestPeerDelegate { | |
| 104 public: | |
| 105 JniURLRequestPeerDelegate(JNIEnv* env, jobject owner) { | |
| 106 owner_ = env->NewGlobalRef(owner); | |
| 107 env->GetJavaVM(&vm_); | |
| 108 } | |
| 109 | |
| 110 virtual void OnAppendChunkCompleted(URLRequestPeer* request) OVERRIDE { | |
| 111 JNIEnv* env = GetEnv(vm_); | |
| 112 env->CallVoidMethod(owner_, g_method_onAppendChunkCompleted); | |
| 113 if (env->ExceptionOccurred()) { | |
| 114 env->ExceptionDescribe(); | |
| 115 env->ExceptionClear(); | |
| 116 } | |
| 117 } | |
| 118 | |
| 119 virtual void OnResponseStarted(URLRequestPeer* request) OVERRIDE { | |
| 120 JNIEnv* env = GetEnv(vm_); | |
| 121 env->CallVoidMethod(owner_, g_method_onResponseStarted); | |
| 122 if (env->ExceptionOccurred()) { | |
| 123 env->ExceptionDescribe(); | |
| 124 env->ExceptionClear(); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 virtual void OnBytesRead(URLRequestPeer* request) OVERRIDE { | |
| 129 int bytes_read = request->bytes_read(); | |
| 130 if (bytes_read != 0) { | |
| 131 JNIEnv* env = GetEnv(vm_); | |
| 132 jobject bytebuf = env->NewDirectByteBuffer(request->Data(), bytes_read); | |
| 133 env->CallVoidMethod(owner_, g_method_onReadBytes, bytebuf); | |
| 134 env->DeleteLocalRef(bytebuf); | |
| 135 if (env->ExceptionOccurred()) { | |
| 136 env->ExceptionDescribe(); | |
| 137 env->ExceptionClear(); | |
| 138 } | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 virtual void OnRequestFinished(URLRequestPeer* request) OVERRIDE { | |
| 143 JNIEnv* env = GetEnv(vm_); | |
| 144 env->CallVoidMethod(owner_, g_method_finish); | |
| 145 if (env->ExceptionOccurred()) { | |
| 146 env->ExceptionDescribe(); | |
| 147 env->ExceptionClear(); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 protected: | |
| 152 virtual ~JniURLRequestPeerDelegate() { GetEnv(vm_)->DeleteGlobalRef(owner_); } | |
| 153 | |
| 154 private: | |
| 155 jobject owner_; | |
| 156 JavaVM* vm_; | |
|
mmenke
2014/03/04 19:36:20
DISALLOW_COPY_AND_ASSIGN (+include the header for
mef
2014/03/05 20:54:13
Done.
| |
| 157 }; | |
| 158 | |
| 159 JNIEXPORT void JNICALL | |
| 160 Java_org_chromium_net_UrlRequest_nativeInit(JNIEnv* env, | |
| 161 jobject object, | |
| 162 jobject request_context, | |
| 163 jstring url_string, | |
| 164 jint priority) { | |
| 165 URLRequestContextPeer* context = | |
| 166 GetURLRequestContextPeer(env, request_context); | |
| 167 DCHECK(context != NULL); | |
| 168 | |
| 169 const char* url_utf8 = env->GetStringUTFChars(url_string, NULL); | |
| 170 | |
| 171 DVLOG(context->logging_level()) | |
| 172 << "New chromium network request. URL:" << url_utf8; | |
| 173 | |
| 174 GURL url(url_utf8); | |
| 175 | |
| 176 env->ReleaseStringUTFChars(url_string, url_utf8); | |
| 177 | |
| 178 URLRequestPeer* request = | |
| 179 new URLRequestPeer(context, | |
| 180 new JniURLRequestPeerDelegate(env, object), | |
| 181 url, | |
| 182 ConvertRequestPriority(priority)); | |
| 183 | |
| 184 SetNativeObject(env, object, request); | |
| 185 } | |
| 186 | |
| 187 // synchronized | |
| 188 JNIEXPORT void JNICALL | |
| 189 Java_org_chromium_net_UrlRequest_nativeAddHeader(JNIEnv* env, | |
| 190 jobject object, | |
| 191 jstring name, | |
| 192 jstring value) { | |
| 193 URLRequestPeer* request = GetNativeObject(env, object); | |
| 194 DCHECK(request != NULL); | |
| 195 | |
| 196 const char* name_utf8 = env->GetStringUTFChars(name, NULL); | |
| 197 std::string name_string(name_utf8); | |
| 198 env->ReleaseStringUTFChars(name, name_utf8); | |
| 199 | |
| 200 const char* value_utf8 = env->GetStringUTFChars(value, NULL); | |
| 201 std::string value_string(value_utf8); | |
| 202 env->ReleaseStringUTFChars(value, value_utf8); | |
| 203 | |
| 204 request->AddHeader(name_string, value_string); | |
| 205 } | |
| 206 | |
| 207 JNIEXPORT void JNICALL | |
| 208 Java_org_chromium_net_UrlRequest_nativeSetPostData(JNIEnv* env, | |
| 209 jobject object, | |
| 210 jstring content_type, | |
| 211 jbyteArray content) { | |
| 212 URLRequestPeer* request = GetNativeObject(env, object); | |
| 213 SetPostContentType(env, request, content_type); | |
| 214 | |
| 215 if (content != NULL) { | |
| 216 jsize size = env->GetArrayLength(content); | |
| 217 if (size > 0) { | |
| 218 jbyte* content_bytes = env->GetByteArrayElements(content, NULL); | |
| 219 request->SetPostContent(reinterpret_cast<const char*>(content_bytes), | |
| 220 size); | |
| 221 env->ReleaseByteArrayElements(content, content_bytes, 0); | |
| 222 } | |
| 223 } | |
| 224 } | |
| 225 | |
| 226 JNIEXPORT void JNICALL | |
| 227 Java_org_chromium_net_UrlRequest_nativeBeginChunkedUpload( | |
| 228 JNIEnv* env, | |
| 229 jobject object, | |
| 230 jstring content_type) { | |
| 231 URLRequestPeer* request = GetNativeObject(env, object); | |
| 232 SetPostContentType(env, request, content_type); | |
| 233 | |
| 234 request->EnableStreamingUpload(); | |
| 235 } | |
| 236 | |
| 237 JNIEXPORT void JNICALL | |
| 238 Java_org_chromium_net_UrlRequest_nativeAppendChunk(JNIEnv* env, | |
| 239 jobject object, | |
| 240 jobject chunk_byte_buffer, | |
| 241 jint chunk_size, | |
| 242 jboolean is_last_chunk) { | |
| 243 URLRequestPeer* request = GetNativeObject(env, object); | |
| 244 CHECK(request != NULL); | |
| 245 | |
| 246 if (chunk_byte_buffer != NULL) { | |
| 247 void* chunk = env->GetDirectBufferAddress(chunk_byte_buffer); | |
| 248 request->AppendChunk( | |
| 249 reinterpret_cast<const char*>(chunk), chunk_size, is_last_chunk); | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 /* synchronized */ | |
| 254 JNIEXPORT void JNICALL | |
| 255 Java_org_chromium_net_UrlRequest_nativeStart(JNIEnv* env, jobject object) { | |
| 256 URLRequestPeer* request = GetNativeObject(env, object); | |
| 257 if (request != NULL) { | |
| 258 request->Start(); | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 /* synchronized */ | |
| 263 JNIEXPORT void JNICALL | |
| 264 Java_org_chromium_net_UrlRequest_nativeRecycle(JNIEnv* env, jobject object) { | |
| 265 URLRequestPeer* request = GetNativeObject(env, object); | |
| 266 if (request != NULL) { | |
| 267 request->Destroy(); | |
| 268 } | |
| 269 | |
| 270 SetNativeObject(env, object, NULL); | |
| 271 } | |
| 272 | |
| 273 /* synchronized */ | |
| 274 JNIEXPORT void JNICALL | |
| 275 Java_org_chromium_net_UrlRequest_nativeCancel(JNIEnv* env, jobject object) { | |
| 276 URLRequestPeer* request = GetNativeObject(env, object); | |
| 277 if (request != NULL) { | |
| 278 request->Cancel(); | |
| 279 } | |
| 280 } | |
| 281 | |
| 282 JNIEXPORT jint JNICALL | |
| 283 Java_org_chromium_net_UrlRequest_nativeGetErrorCode(JNIEnv* env, | |
| 284 jobject object) { | |
| 285 URLRequestPeer* request = GetNativeObject(env, object); | |
| 286 int error_code = request->error_code(); | |
| 287 switch (error_code) { | |
| 288 // TODO(mef): Investigate returning success on positive values, too, as | |
| 289 // they technically indicate success. | |
| 290 case net::OK: | |
| 291 return ERROR_SUCCESS; | |
| 292 | |
| 293 // TODO(mef): Investigate this. The fact is that Chrome does not do this, | |
| 294 // and this library is not just being used for downloads. | |
| 295 | |
| 296 // Comment from src/content/browser/download/download_resource_handler.cc: | |
| 297 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are | |
| 298 // allowed since a number of servers in the wild close the connection too | |
| 299 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 - | |
| 300 // treat downloads as complete in both cases, so we follow their lead. | |
| 301 case net::ERR_CONTENT_LENGTH_MISMATCH: | |
| 302 case net::ERR_INCOMPLETE_CHUNKED_ENCODING: | |
| 303 return ERROR_SUCCESS; | |
| 304 | |
| 305 case net::ERR_INVALID_URL: | |
| 306 case net::ERR_DISALLOWED_URL_SCHEME: | |
| 307 case net::ERR_UNKNOWN_URL_SCHEME: | |
| 308 return ERROR_MALFORMED_URL; | |
| 309 | |
| 310 case net::ERR_CONNECTION_TIMED_OUT: | |
| 311 return ERROR_CONNECTION_TIMED_OUT; | |
| 312 | |
| 313 case net::ERR_NAME_NOT_RESOLVED: | |
| 314 return ERROR_UNKNOWN_HOST; | |
| 315 } | |
| 316 return ERROR_UNKNOWN; | |
| 317 } | |
| 318 | |
| 319 JNIEXPORT jstring JNICALL | |
| 320 Java_org_chromium_net_UrlRequest_nativeGetErrorString(JNIEnv* env, | |
| 321 jobject object) { | |
| 322 int error_code = GetNativeObject(env, object)->error_code(); | |
| 323 char buffer[200]; | |
| 324 snprintf(buffer, | |
| 325 sizeof(buffer), | |
| 326 "System error: %s(%d)", | |
| 327 net::ErrorToString(error_code), | |
| 328 error_code); | |
| 329 return env->NewStringUTF(buffer); | |
| 330 } | |
| 331 | |
| 332 JNIEXPORT jint JNICALL | |
| 333 Java_org_chromium_net_UrlRequest_getHttpStatusCode(JNIEnv* env, | |
| 334 jobject object) { | |
| 335 return GetNativeObject(env, object)->http_status_code(); | |
| 336 } | |
| 337 | |
| 338 JNIEXPORT jstring JNICALL | |
| 339 Java_org_chromium_net_UrlRequest_nativeGetContentType(JNIEnv* env, | |
| 340 jobject object) { | |
| 341 URLRequestPeer* request = GetNativeObject(env, object); | |
| 342 if (request == NULL) { | |
| 343 return NULL; | |
| 344 } | |
| 345 std::string type = request->content_type(); | |
| 346 if (!type.empty()) { | |
| 347 return env->NewStringUTF(type.c_str()); | |
| 348 } else { | |
| 349 return NULL; | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 JNIEXPORT jlong JNICALL | |
| 354 Java_org_chromium_net_UrlRequest_nativeGetContentLength(JNIEnv* env, | |
| 355 jobject object) { | |
| 356 URLRequestPeer* request = GetNativeObject(env, object); | |
| 357 if (request == NULL) { | |
| 358 return 0; | |
| 359 } | |
| 360 return request->content_length(); | |
| 361 } | |
| OLD | NEW |