| 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 "base/android/jni_android.h" | |
| 8 #include "base/macros.h" | |
| 9 #include "jni/UrlRequest_jni.h" | |
| 10 #include "net/base/net_errors.h" | |
| 11 #include "net/base/request_priority.h" | |
| 12 #include "net/cronet/android/url_request_context_peer.h" | |
| 13 #include "net/cronet/android/url_request_peer.h" | |
| 14 | |
| 15 namespace net { | |
| 16 namespace { | |
| 17 | |
| 18 net::RequestPriority ConvertRequestPriority(jint request_priority) { | |
| 19 switch (request_priority) { | |
| 20 case REQUEST_PRIORITY_IDLE: | |
| 21 return net::IDLE; | |
| 22 case REQUEST_PRIORITY_LOWEST: | |
| 23 return net::LOWEST; | |
| 24 case REQUEST_PRIORITY_LOW: | |
| 25 return net::LOW; | |
| 26 case REQUEST_PRIORITY_MEDIUM: | |
| 27 return net::MEDIUM; | |
| 28 case REQUEST_PRIORITY_HIGHEST: | |
| 29 return net::HIGHEST; | |
| 30 default: | |
| 31 return net::LOWEST; | |
| 32 } | |
| 33 } | |
| 34 | |
| 35 void SetPostContentType(JNIEnv* env, | |
| 36 URLRequestPeer* request, | |
| 37 jstring content_type) { | |
| 38 DCHECK(request != NULL); | |
| 39 | |
| 40 std::string method_post("POST"); | |
| 41 request->SetMethod(method_post); | |
| 42 | |
| 43 std::string content_type_header("Content-Type"); | |
| 44 | |
| 45 const char* content_type_utf8 = env->GetStringUTFChars(content_type, NULL); | |
| 46 std::string content_type_string(content_type_utf8); | |
| 47 env->ReleaseStringUTFChars(content_type, content_type_utf8); | |
| 48 | |
| 49 request->AddHeader(content_type_header, content_type_string); | |
| 50 } | |
| 51 | |
| 52 // A delegate of URLRequestPeer that delivers callbacks to the Java layer. | |
| 53 class JniURLRequestPeerDelegate | |
| 54 : public URLRequestPeer::URLRequestPeerDelegate { | |
| 55 public: | |
| 56 JniURLRequestPeerDelegate(JNIEnv* env, jobject owner) { | |
| 57 owner_ = env->NewGlobalRef(owner); | |
| 58 } | |
| 59 | |
| 60 virtual void OnAppendChunkCompleted(URLRequestPeer* request) OVERRIDE { | |
| 61 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 62 net::Java_UrlRequest_onAppendChunkCompleted(env, owner_); | |
| 63 } | |
| 64 | |
| 65 virtual void OnResponseStarted(URLRequestPeer* request) OVERRIDE { | |
| 66 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 67 net::Java_UrlRequest_onResponseStarted(env, owner_); | |
| 68 } | |
| 69 | |
| 70 virtual void OnBytesRead(URLRequestPeer* request) OVERRIDE { | |
| 71 int bytes_read = request->bytes_read(); | |
| 72 if (bytes_read != 0) { | |
| 73 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 74 jobject bytebuf = env->NewDirectByteBuffer(request->Data(), bytes_read); | |
| 75 net::Java_UrlRequest_onBytesRead(env, owner_, bytebuf); | |
| 76 env->DeleteLocalRef(bytebuf); | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 virtual void OnRequestFinished(URLRequestPeer* request) OVERRIDE { | |
| 81 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 82 net::Java_UrlRequest_finish(env, owner_); | |
| 83 } | |
| 84 | |
| 85 protected: | |
| 86 virtual ~JniURLRequestPeerDelegate() { | |
| 87 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 88 env->DeleteGlobalRef(owner_); | |
| 89 } | |
| 90 | |
| 91 private: | |
| 92 jobject owner_; | |
| 93 | |
| 94 DISALLOW_COPY_AND_ASSIGN(JniURLRequestPeerDelegate); | |
| 95 }; | |
| 96 | |
| 97 } // namespace | |
| 98 | |
| 99 // Explicitly register static JNI functions. | |
| 100 bool UrlRequestRegisterJni(JNIEnv* env) { return RegisterNativesImpl(env); } | |
| 101 | |
| 102 static jlong CreateRequestPeer(JNIEnv* env, | |
| 103 jobject object, | |
| 104 jlong urlRequestContextPeer, | |
| 105 jstring url_string, | |
| 106 jint priority) { | |
| 107 URLRequestContextPeer* context = | |
| 108 reinterpret_cast<URLRequestContextPeer*>(urlRequestContextPeer); | |
| 109 DCHECK(context != NULL); | |
| 110 | |
| 111 const char* url_utf8 = env->GetStringUTFChars(url_string, NULL); | |
| 112 | |
| 113 DVLOG(context->logging_level()) | |
| 114 << "New chromium network request. URL:" << url_utf8; | |
| 115 | |
| 116 GURL url(url_utf8); | |
| 117 | |
| 118 env->ReleaseStringUTFChars(url_string, url_utf8); | |
| 119 | |
| 120 URLRequestPeer* peer = | |
| 121 new URLRequestPeer(context, | |
| 122 new JniURLRequestPeerDelegate(env, object), | |
| 123 url, | |
| 124 ConvertRequestPriority(priority)); | |
| 125 | |
| 126 return reinterpret_cast<jlong>(peer); | |
| 127 } | |
| 128 | |
| 129 // synchronized | |
| 130 static void AddHeader(JNIEnv* env, | |
| 131 jobject object, | |
| 132 jlong urlRequestPeer, | |
| 133 jstring name, | |
| 134 jstring value) { | |
| 135 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 136 DCHECK(request != NULL); | |
| 137 | |
| 138 const char* name_utf8 = env->GetStringUTFChars(name, NULL); | |
| 139 std::string name_string(name_utf8); | |
| 140 env->ReleaseStringUTFChars(name, name_utf8); | |
| 141 | |
| 142 const char* value_utf8 = env->GetStringUTFChars(value, NULL); | |
| 143 std::string value_string(value_utf8); | |
| 144 env->ReleaseStringUTFChars(value, value_utf8); | |
| 145 | |
| 146 request->AddHeader(name_string, value_string); | |
| 147 } | |
| 148 | |
| 149 static void SetPostData(JNIEnv* env, | |
| 150 jobject object, | |
| 151 jlong urlRequestPeer, | |
| 152 jstring content_type, | |
| 153 jbyteArray content) { | |
| 154 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 155 SetPostContentType(env, request, content_type); | |
| 156 | |
| 157 if (content != NULL) { | |
| 158 jsize size = env->GetArrayLength(content); | |
| 159 if (size > 0) { | |
| 160 jbyte* content_bytes = env->GetByteArrayElements(content, NULL); | |
| 161 request->SetPostContent(reinterpret_cast<const char*>(content_bytes), | |
| 162 size); | |
| 163 env->ReleaseByteArrayElements(content, content_bytes, 0); | |
| 164 } | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 static void BeginChunkedUpload(JNIEnv* env, | |
| 169 jobject object, | |
| 170 jlong urlRequestPeer, | |
| 171 jstring content_type) { | |
| 172 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 173 SetPostContentType(env, request, content_type); | |
| 174 | |
| 175 request->EnableStreamingUpload(); | |
| 176 } | |
| 177 | |
| 178 static void AppendChunk(JNIEnv* env, | |
| 179 jobject object, | |
| 180 jlong urlRequestPeer, | |
| 181 jobject chunk_byte_buffer, | |
| 182 jint chunk_size, | |
| 183 jboolean is_last_chunk) { | |
| 184 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 185 CHECK(request != NULL); | |
| 186 | |
| 187 if (chunk_byte_buffer != NULL) { | |
| 188 void* chunk = env->GetDirectBufferAddress(chunk_byte_buffer); | |
| 189 request->AppendChunk( | |
| 190 reinterpret_cast<const char*>(chunk), chunk_size, is_last_chunk); | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 /* synchronized */ | |
| 195 static void Start(JNIEnv* env, jobject object, jlong urlRequestPeer) { | |
| 196 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 197 if (request != NULL) { | |
| 198 request->Start(); | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 /* synchronized */ | |
| 203 static void DestroyRequestPeer(JNIEnv* env, | |
| 204 jobject object, | |
| 205 jlong urlRequestPeer) { | |
| 206 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 207 if (request != NULL) { | |
| 208 request->Destroy(); | |
| 209 } | |
| 210 } | |
| 211 | |
| 212 /* synchronized */ | |
| 213 static void Cancel(JNIEnv* env, jobject object, jlong urlRequestPeer) { | |
| 214 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 215 if (request != NULL) { | |
| 216 request->Cancel(); | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 static jint GetErrorCode(JNIEnv* env, jobject object, jlong urlRequestPeer) { | |
| 221 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 222 int error_code = request->error_code(); | |
| 223 switch (error_code) { | |
| 224 // TODO(mef): Investigate returning success on positive values, too, as | |
| 225 // they technically indicate success. | |
| 226 case net::OK: | |
| 227 return REQUEST_ERROR_SUCCESS; | |
| 228 | |
| 229 // TODO(mef): Investigate this. The fact is that Chrome does not do this, | |
| 230 // and this library is not just being used for downloads. | |
| 231 | |
| 232 // Comment from src/content/browser/download/download_resource_handler.cc: | |
| 233 // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are | |
| 234 // allowed since a number of servers in the wild close the connection too | |
| 235 // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 - | |
| 236 // treat downloads as complete in both cases, so we follow their lead. | |
| 237 case net::ERR_CONTENT_LENGTH_MISMATCH: | |
| 238 case net::ERR_INCOMPLETE_CHUNKED_ENCODING: | |
| 239 return REQUEST_ERROR_SUCCESS; | |
| 240 | |
| 241 case net::ERR_INVALID_URL: | |
| 242 case net::ERR_DISALLOWED_URL_SCHEME: | |
| 243 case net::ERR_UNKNOWN_URL_SCHEME: | |
| 244 return REQUEST_ERROR_MALFORMED_URL; | |
| 245 | |
| 246 case net::ERR_CONNECTION_TIMED_OUT: | |
| 247 return REQUEST_ERROR_CONNECTION_TIMED_OUT; | |
| 248 | |
| 249 case net::ERR_NAME_NOT_RESOLVED: | |
| 250 return REQUEST_ERROR_UNKNOWN_HOST; | |
| 251 } | |
| 252 return REQUEST_ERROR_UNKNOWN; | |
| 253 } | |
| 254 | |
| 255 static jstring GetErrorString(JNIEnv* env, | |
| 256 jobject object, | |
| 257 jlong urlRequestPeer) { | |
| 258 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 259 int error_code = request->error_code(); | |
| 260 char buffer[200]; | |
| 261 snprintf(buffer, | |
| 262 sizeof(buffer), | |
| 263 "System error: %s(%d)", | |
| 264 net::ErrorToString(error_code), | |
| 265 error_code); | |
| 266 return env->NewStringUTF(buffer); | |
| 267 } | |
| 268 | |
| 269 static jint GetHttpStatusCode(JNIEnv* env, | |
| 270 jobject object, | |
| 271 jlong urlRequestPeer) { | |
| 272 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 273 return request->http_status_code(); | |
| 274 } | |
| 275 | |
| 276 static jstring GetContentType(JNIEnv* env, | |
| 277 jobject object, | |
| 278 jlong urlRequestPeer) { | |
| 279 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 280 if (request == NULL) { | |
| 281 return NULL; | |
| 282 } | |
| 283 std::string type = request->content_type(); | |
| 284 if (!type.empty()) { | |
| 285 return env->NewStringUTF(type.c_str()); | |
| 286 } else { | |
| 287 return NULL; | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 static jlong GetContentLength(JNIEnv* env, | |
| 292 jobject object, | |
| 293 jlong urlRequestPeer) { | |
| 294 URLRequestPeer* request = reinterpret_cast<URLRequestPeer*>(urlRequestPeer); | |
| 295 if (request == NULL) { | |
| 296 return 0; | |
| 297 } | |
| 298 return request->content_length(); | |
| 299 } | |
| 300 | |
| 301 } // namespace net | |
| OLD | NEW |