| 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 | 
|---|