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