| OLD | NEW | 
 | (Empty) | 
|    1 /* |  | 
|    2  * This file is part of Adblock Plus <http://adblockplus.org/>, |  | 
|    3  * Copyright (C) 2006-2014 Eyeo GmbH |  | 
|    4  * |  | 
|    5  * Adblock Plus is free software: you can redistribute it and/or modify |  | 
|    6  * it under the terms of the GNU General Public License version 3 as |  | 
|    7  * published by the Free Software Foundation. |  | 
|    8  * |  | 
|    9  * Adblock Plus is distributed in the hope that it will be useful, |  | 
|   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of |  | 
|   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | 
|   12  * GNU General Public License for more details. |  | 
|   13  * |  | 
|   14  * You should have received a copy of the GNU General Public License |  | 
|   15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. |  | 
|   16  */ |  | 
|   17  |  | 
|   18 #include <AdblockPlus.h> |  | 
|   19 #include "AndroidWebRequest.h" |  | 
|   20 #include "Utils.h" |  | 
|   21 #include "Debug.h" |  | 
|   22  |  | 
|   23 namespace |  | 
|   24 { |  | 
|   25   std::string ExtractExceptionMessage(JNIEnv* env, jthrowable throwable) |  | 
|   26   { |  | 
|   27     jclass throwableClass = env->FindClass("java/lang/Throwable"); |  | 
|   28     jmethodID throwableToStringMethodId = env->GetMethodID(throwableClass, "toSt
     ring", "()Ljava/lang/String;"); |  | 
|   29     jstring javaMessage = static_cast<jstring>(env->CallObjectMethod(throwable, 
     throwableToStringMethodId)); |  | 
|   30     return "Java exception: " + GetString(env, javaMessage); |  | 
|   31   } |  | 
|   32  |  | 
|   33   class JavaException : public std::exception |  | 
|   34   { |  | 
|   35   public: |  | 
|   36     JavaException(JNIEnv* env) |  | 
|   37       : env(env), throwable(env->ExceptionOccurred()) |  | 
|   38     { |  | 
|   39       env->ExceptionClear(); |  | 
|   40       message = ExtractExceptionMessage(env, throwable); |  | 
|   41     } |  | 
|   42  |  | 
|   43     virtual ~JavaException() throw() |  | 
|   44     { |  | 
|   45     } |  | 
|   46  |  | 
|   47     const char* what() const throw() |  | 
|   48     { |  | 
|   49       return message.c_str(); |  | 
|   50     } |  | 
|   51  |  | 
|   52     bool IsInstanceOf(const std::string& className) const |  | 
|   53     { |  | 
|   54       jclass clazz = env->FindClass(className.c_str()); |  | 
|   55       if (!clazz) |  | 
|   56         return false; |  | 
|   57       bool isInstance = env->IsInstanceOf(throwable, clazz); |  | 
|   58       env->DeleteLocalRef(clazz); |  | 
|   59       return isInstance; |  | 
|   60     } |  | 
|   61  |  | 
|   62   private: |  | 
|   63     JNIEnv* env; |  | 
|   64     jthrowable throwable; |  | 
|   65     std::string message; |  | 
|   66   }; |  | 
|   67  |  | 
|   68   int64_t ExceptionToStatus(const JavaException& exception) |  | 
|   69   { |  | 
|   70     if (exception.IsInstanceOf("java/net/MalformedURLException")) |  | 
|   71       return AdblockPlus::WebRequest::NS_ERROR_MALFORMED_URI; |  | 
|   72     if (exception.IsInstanceOf("java/net/SocketTimeoutException")) |  | 
|   73       return AdblockPlus::WebRequest::NS_ERROR_NET_TIMEOUT; |  | 
|   74     return AdblockPlus::WebRequest::NS_ERROR_FAILURE; |  | 
|   75   } |  | 
|   76 } |  | 
|   77  |  | 
|   78 AndroidWebRequest::AndroidWebRequest(JavaVM*& gJvm) : globalJvm(gJvm) |  | 
|   79 { |  | 
|   80   JNIEnv* jniEnv = NULL; |  | 
|   81   int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6); |  | 
|   82   if (stat == JNI_EDETACHED) |  | 
|   83   { |  | 
|   84     if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0) |  | 
|   85       throw std::runtime_error("Failed to get JNI environment"); |  | 
|   86   } |  | 
|   87  |  | 
|   88   jUrlClass = reinterpret_cast<jclass>(jniEnv->NewGlobalRef(jniEnv->FindClass("j
     ava/net/URL"))); |  | 
|   89   jUrlConstructorID = jniEnv->GetMethodID(jUrlClass, "<init>", "(Ljava/lang/Stri
     ng;)V"); |  | 
|   90   jUrlOpenConnectionID = jniEnv->GetMethodID(jUrlClass, "openConnection", "()Lja
     va/net/URLConnection;"); |  | 
|   91   jConnectionClass = reinterpret_cast<jclass>(jniEnv->NewGlobalRef(jniEnv->FindC
     lass("java/net/HttpURLConnection"))); |  | 
|   92   jConnectionSetMethodID = jniEnv->GetMethodID(jConnectionClass, "setRequestMeth
     od", "(Ljava/lang/String;)V"); |  | 
|   93   jConnectionSetRequestPropertyID = jniEnv->GetMethodID(jConnectionClass, "setRe
     questProperty", "(Ljava/lang/String;Ljava/lang/String;)V"); |  | 
|   94   jConnectionConnectID = jniEnv->GetMethodID(jConnectionClass, "connect", "()V")
     ; |  | 
|   95   jConnectionGetContentLengthID = jniEnv->GetMethodID(jConnectionClass, "getCont
     entLength", "()I"); |  | 
|   96   jConnectionGetResponseCodeID = jniEnv->GetMethodID(jConnectionClass, "getRespo
     nseCode", "()I"); |  | 
|   97   jConnectionGetContentEncodingID = jniEnv->GetMethodID(jConnectionClass, "getCo
     ntentEncoding", "()Ljava/lang/String;"); |  | 
|   98   jConnectionGetInputStreamID = jniEnv->GetMethodID(jConnectionClass, "getInputS
     tream", "()Ljava/io/InputStream;"); |  | 
|   99   jInputStreamReaderClass = reinterpret_cast<jclass>(jniEnv->NewGlobalRef(jniEnv
     ->FindClass("java/io/InputStreamReader"))); |  | 
|  100   jInputStreamReaderConstructorID = jniEnv->GetMethodID(jInputStreamReaderClass,
      "<init>", "(Ljava/io/InputStream;Ljava/lang/String;)V"); |  | 
|  101   jBufferedReaderClass = reinterpret_cast<jclass>(jniEnv->NewGlobalRef(jniEnv->F
     indClass("java/io/BufferedReader"))); |  | 
|  102   jBufferedReaderConstructorID = jniEnv->GetMethodID(jBufferedReaderClass, "<ini
     t>", "(Ljava/io/Reader;)V"); |  | 
|  103   jStringBuilderClass = reinterpret_cast<jclass>(jniEnv->NewGlobalRef(jniEnv->Fi
     ndClass("java/lang/StringBuilder"))); |  | 
|  104   jStringBuilderConstructorID = jniEnv->GetMethodID(jStringBuilderClass, "<init>
     ", "()V"); |  | 
|  105   jBufferedReaderReadID = jniEnv->GetMethodID(jBufferedReaderClass, "read", "([C
     II)I"); |  | 
|  106   jStringBuilderAppendID = jniEnv->GetMethodID(jStringBuilderClass, "append", "(
     [CII)Ljava/lang/StringBuilder;"); |  | 
|  107   jStringBuilderToStringID = jniEnv->GetMethodID(jStringBuilderClass, "toString"
     , "()Ljava/lang/String;"); |  | 
|  108   jBufferedReaderCloseID = jniEnv->GetMethodID(jBufferedReaderClass, "close", "(
     )V"); |  | 
|  109   jConnectionGetHeaderFieldKeyID = jniEnv->GetMethodID(jConnectionClass, "getHea
     derField", "(I)Ljava/lang/String;"); |  | 
|  110   jConnectionGetHeaderFieldID = jniEnv->GetMethodID(jConnectionClass, "getHeader
     FieldKey", "(I)Ljava/lang/String;"); |  | 
|  111  |  | 
|  112   if (stat == JNI_EDETACHED) |  | 
|  113     globalJvm->DetachCurrentThread(); |  | 
|  114 } |  | 
|  115  |  | 
|  116 AndroidWebRequest::~AndroidWebRequest() |  | 
|  117 { |  | 
|  118   JNIEnv* jniEnv = NULL; |  | 
|  119   int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6); |  | 
|  120   if (stat == JNI_EDETACHED) |  | 
|  121   { |  | 
|  122     if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0) |  | 
|  123       throw std::runtime_error("Failed to get JNI environment"); |  | 
|  124   } |  | 
|  125  |  | 
|  126   jniEnv->DeleteGlobalRef(jUrlClass); |  | 
|  127   jniEnv->DeleteGlobalRef(jConnectionClass); |  | 
|  128   jniEnv->DeleteGlobalRef(jInputStreamReaderClass); |  | 
|  129   jniEnv->DeleteGlobalRef(jBufferedReaderClass); |  | 
|  130   jniEnv->DeleteGlobalRef(jStringBuilderClass); |  | 
|  131  |  | 
|  132   if (stat == JNI_EDETACHED) |  | 
|  133     globalJvm->DetachCurrentThread(); |  | 
|  134 } |  | 
|  135  |  | 
|  136 AdblockPlus::ServerResponse AndroidWebRequest::GET( |  | 
|  137   const std::string& url, const AdblockPlus::HeaderList& requestHeaders) const |  | 
|  138 { |  | 
|  139   JNIEnv* jniEnv = NULL; |  | 
|  140   int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6); |  | 
|  141   if (stat == JNI_EDETACHED) |  | 
|  142   { |  | 
|  143     if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0) |  | 
|  144       throw std::runtime_error("Failed to get JNI environment"); |  | 
|  145   } |  | 
|  146  |  | 
|  147   AdblockPlus::ServerResponse result; |  | 
|  148   try |  | 
|  149   { |  | 
|  150     // URL jUrl = new URL(url) |  | 
|  151     jstring jUrlStr = jniEnv->NewStringUTF(url.c_str()); |  | 
|  152  |  | 
|  153     jobject jUrl = jniEnv->NewObject(jUrlClass, jUrlConstructorID, jUrlStr); |  | 
|  154     if (jniEnv->ExceptionCheck()) |  | 
|  155       throw JavaException(jniEnv); |  | 
|  156     jniEnv->DeleteLocalRef(jUrlStr); |  | 
|  157  |  | 
|  158     // HttpURLConnection connection = (HttpURLConnection) jUrl.openConnection(); |  | 
|  159     jobject jConnection = jniEnv->CallObjectMethod(jUrl, jUrlOpenConnectionID); |  | 
|  160     if (jniEnv->ExceptionCheck()) |  | 
|  161       throw JavaException(jniEnv); |  | 
|  162  |  | 
|  163     // connection.setRequestMethod("GET"); |  | 
|  164     jstring jMethod = jniEnv->NewStringUTF("GET"); |  | 
|  165     jniEnv->CallVoidMethod(jConnection, jConnectionSetMethodID, jMethod); |  | 
|  166     if (jniEnv->ExceptionCheck()) |  | 
|  167       throw JavaException(jniEnv); |  | 
|  168     jniEnv->DeleteLocalRef(jMethod); |  | 
|  169  |  | 
|  170     for (int i = 0; i < requestHeaders.size(); i++) |  | 
|  171     { |  | 
|  172       // connection.setRequestProperty(requestHeaders[i].first, requestHeaders[i
     ].second); |  | 
|  173       jstring jHeader = jniEnv->NewStringUTF(requestHeaders[i].first.c_str()); |  | 
|  174       jstring jValue = jniEnv->NewStringUTF(requestHeaders[i].second.c_str()); |  | 
|  175       jniEnv->CallVoidMethod(jConnection, jConnectionSetRequestPropertyID, jHead
     er, jValue); |  | 
|  176       if (jniEnv->ExceptionCheck()) |  | 
|  177         throw JavaException(jniEnv); |  | 
|  178       jniEnv->DeleteLocalRef(jHeader); |  | 
|  179       jniEnv->DeleteLocalRef(jValue); |  | 
|  180     } |  | 
|  181  |  | 
|  182     // connection.connect(); |  | 
|  183     jniEnv->CallVoidMethod(jConnection, jConnectionConnectID); |  | 
|  184     if (jniEnv->ExceptionCheck()) |  | 
|  185       throw JavaException(jniEnv); |  | 
|  186  |  | 
|  187     // int lenghtOfFile = connection.getContentLength(); |  | 
|  188     jint lenghtOfFile = jniEnv->CallIntMethod(jConnection, jConnectionGetContent
     LengthID); |  | 
|  189     if (jniEnv->ExceptionCheck()) |  | 
|  190       throw JavaException(jniEnv); |  | 
|  191  |  | 
|  192     D(D_WARN, "Size: %d", lenghtOfFile); |  | 
|  193  |  | 
|  194     // result.responseStatus = connection.getResponseCode(); |  | 
|  195     result.responseStatus = jniEnv->CallIntMethod(jConnection, jConnectionGetRes
     ponseCodeID); |  | 
|  196     if (jniEnv->ExceptionCheck()) |  | 
|  197       throw JavaException(jniEnv); |  | 
|  198  |  | 
|  199     /* Read response data */ |  | 
|  200  |  | 
|  201     // String jEncoding = connection.getContentEncoding(); |  | 
|  202     jstring jEncoding = (jstring) jniEnv->CallObjectMethod(jConnection, jConnect
     ionGetContentEncodingID); |  | 
|  203     if (jniEnv->ExceptionCheck()) |  | 
|  204       throw JavaException(jniEnv); |  | 
|  205  |  | 
|  206     if (jEncoding == NULL) |  | 
|  207       jEncoding = jniEnv->NewStringUTF("utf-8"); |  | 
|  208  |  | 
|  209     // InputStream jis = connection.getInputStream(); |  | 
|  210     jobject jis = jniEnv->CallObjectMethod(jConnection, jConnectionGetInputStrea
     mID); |  | 
|  211     if (jniEnv->ExceptionCheck()) |  | 
|  212       throw JavaException(jniEnv); |  | 
|  213  |  | 
|  214     // InputStreamReader jisr = new InputStreamReader(jis, jEncoding); |  | 
|  215     jobject jisr = jniEnv->NewObject(jInputStreamReaderClass, jInputStreamReader
     ConstructorID, jis, jEncoding); |  | 
|  216     if (jniEnv->ExceptionCheck()) |  | 
|  217       throw JavaException(jniEnv); |  | 
|  218  |  | 
|  219     jniEnv->DeleteLocalRef(jEncoding); |  | 
|  220  |  | 
|  221     // BufferedReader jin = new BufferedReader(jisr); |  | 
|  222     jobject jin = jniEnv->NewObject(jBufferedReaderClass, jBufferedReaderConstru
     ctorID, jisr); |  | 
|  223     if (jniEnv->ExceptionCheck()) |  | 
|  224       throw JavaException(jniEnv); |  | 
|  225  |  | 
|  226     // char[] jBuffer = new char[0x10000]; |  | 
|  227     jcharArray jBuffer = jniEnv->NewCharArray(0x10000); |  | 
|  228  |  | 
|  229     // StringBuilder jout = new StringBuilder(); |  | 
|  230     jobject jout = jniEnv->NewObject(jStringBuilderClass, jStringBuilderConstruc
     torID); |  | 
|  231     if (jniEnv->ExceptionCheck()) |  | 
|  232       throw JavaException(jniEnv); |  | 
|  233  |  | 
|  234     jlong total = 0; |  | 
|  235     jint read; |  | 
|  236  |  | 
|  237     jint jBufferLength = (jint) jniEnv->GetArrayLength(jBuffer); |  | 
|  238  |  | 
|  239     do |  | 
|  240     { |  | 
|  241       // read = jin.read(buffer, 0, buffer.length); |  | 
|  242       read = jniEnv->CallIntMethod(jin, jBufferedReaderReadID, jBuffer, 0, jBuff
     erLength); |  | 
|  243       if (jniEnv->ExceptionCheck()) |  | 
|  244         throw JavaException(jniEnv); |  | 
|  245  |  | 
|  246       if (read > 0) |  | 
|  247       { |  | 
|  248         // jout.append(buffer, 0, read); |  | 
|  249         jniEnv->CallObjectMethod(jout, jStringBuilderAppendID, jBuffer, 0, jBuff
     erLength); |  | 
|  250         if (jniEnv->ExceptionCheck()) |  | 
|  251           throw JavaException(jniEnv); |  | 
|  252  |  | 
|  253         total += read; |  | 
|  254       } |  | 
|  255     } |  | 
|  256     while (read >= 0); |  | 
|  257  |  | 
|  258     // String jData = out.toString(); |  | 
|  259     jstring jData = (jstring) jniEnv->CallObjectMethod(jout, jStringBuilderToStr
     ingID); |  | 
|  260     if (jniEnv->ExceptionCheck()) |  | 
|  261       throw JavaException(jniEnv); |  | 
|  262  |  | 
|  263     result.responseText = GetString(jniEnv, jData); |  | 
|  264  |  | 
|  265     // jin.close(); |  | 
|  266     jniEnv->CallVoidMethod(jin, jBufferedReaderCloseID); |  | 
|  267     if (jniEnv->ExceptionCheck()) |  | 
|  268       throw JavaException(jniEnv); |  | 
|  269  |  | 
|  270     jint i = 0; |  | 
|  271     while (true) |  | 
|  272     { |  | 
|  273       // String jHeaderName = connection.getHeaderFieldKey(i) |  | 
|  274       jstring jHeaderName = (jstring) jniEnv->CallObjectMethod(jConnection, jCon
     nectionGetHeaderFieldKeyID, i); |  | 
|  275       if (jniEnv->ExceptionCheck()) |  | 
|  276         throw JavaException(jniEnv); |  | 
|  277  |  | 
|  278       // String jHeaderValue = connection.getHeaderField(i) |  | 
|  279       jstring jHeaderValue = (jstring) jniEnv->CallObjectMethod(jConnection, jCo
     nnectionGetHeaderFieldID, i); |  | 
|  280       if (jniEnv->ExceptionCheck()) |  | 
|  281         throw JavaException(jniEnv); |  | 
|  282  |  | 
|  283       if (!jHeaderValue) |  | 
|  284         break; |  | 
|  285  |  | 
|  286       std::string headerName = GetString(jniEnv, jHeaderName); |  | 
|  287       std::string headerValue = GetString(jniEnv, jHeaderValue); |  | 
|  288  |  | 
|  289       headerName = TrimString(headerName); |  | 
|  290       headerValue = TrimString(headerValue); |  | 
|  291  |  | 
|  292       std::transform(headerName.begin(), headerName.end(), headerName.begin(), :
     :tolower); |  | 
|  293  |  | 
|  294       result.responseHeaders.push_back(std::pair<std::string, std::string>(heade
     rName, headerValue)); |  | 
|  295  |  | 
|  296       i++; |  | 
|  297     } |  | 
|  298     D(D_WARN, "Finished downloading"); |  | 
|  299  |  | 
|  300     result.status = NS_OK; |  | 
|  301   } |  | 
|  302   catch(JavaException& e) |  | 
|  303   { |  | 
|  304     result.responseStatus = 0; |  | 
|  305     result.status = ExceptionToStatus(e); |  | 
|  306     D(D_ERROR, "%s", e.what()); |  | 
|  307   } |  | 
|  308   catch (const std::exception& e) |  | 
|  309   { |  | 
|  310     D(D_ERROR, "Exception: %s", e.what()); |  | 
|  311     result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE; |  | 
|  312   } |  | 
|  313   catch (...) |  | 
|  314   { |  | 
|  315     D(D_ERROR, "Unknown exception"); |  | 
|  316     result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE; |  | 
|  317   } |  | 
|  318  |  | 
|  319   if (stat == JNI_EDETACHED) |  | 
|  320     globalJvm->DetachCurrentThread(); |  | 
|  321  |  | 
|  322   return result; |  | 
|  323 } |  | 
| OLD | NEW |