Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: jni/AndroidWebRequest.cpp

Issue 11172036: ABP/Android libadblockplus integration (Closed)
Patch Set: Created July 22, 2013, 8:52 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2013 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 struct JavaException : public std::exception
24 {
25 jthrowable ex;
26
27 JavaException(jthrowable e) : ex(e)
28 {
29 }
30
31 const char* what() const throw()
32 {
33 return "Java Exception";
Wladimir Palant 2013/09/12 11:31:14 I think that this should return the actual excepti
34 }
35 };
36
37 AndroidWebRequest::AndroidWebRequest(JavaVM*& gJvm) : globalJvm(gJvm)
Felix Dahlke 2013/09/13 14:40:39 You can actually call the parameter globalJvm as w
38 {
39 JNIEnv* jniEnv = NULL;
40 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6);
41 if (stat == JNI_EDETACHED)
42 {
43 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0)
44 throw std::runtime_error("Failed to get JNI environment");
45 }
Wladimir Palant 2013/09/12 11:31:14 Seeing that this block of code is a recurring patt
46
47 jUrlClass = reinterpret_cast<jclass>(jniEnv->NewGlobalRef(jniEnv->FindClass("j ava/net/URL")));
48 jUrlConstructorID = jniEnv->GetMethodID(jUrlClass, "<init>", "(Ljava/lang/Stri ng;)V");
49 jUrlOpenConnectionID = jniEnv->GetMethodID(jUrlClass, "openConnection", "()Lja va/net/URLConnection;");
50 jConnectionClass = reinterpret_cast<jclass>(jniEnv->NewGlobalRef(jniEnv->FindC lass("java/net/HttpURLConnection")));
51 jConnectionSetMethodID = jniEnv->GetMethodID(jConnectionClass, "setRequestMeth od", "(Ljava/lang/String;)V");
52 jConnectionSetRequestPropertyID = jniEnv->GetMethodID(jConnectionClass, "setRe questProperty", "(Ljava/lang/String;Ljava/lang/String;)V");
53 jConnectionConnectID = jniEnv->GetMethodID(jConnectionClass, "connect", "()V") ;
54 jConnectionGetContentLengthID = jniEnv->GetMethodID(jConnectionClass, "getCont entLength", "()I");
55 jConnectionGetResponseCodeID = jniEnv->GetMethodID(jConnectionClass, "getRespo nseCode", "()I");
56 jConnectionGetContentEncodingID = jniEnv->GetMethodID(jConnectionClass, "getCo ntentEncoding", "()Ljava/lang/String;");
57 jConnectionGetInputStreamID = jniEnv->GetMethodID(jConnectionClass, "getInputS tream", "()Ljava/io/InputStream;");
58 jInputStreamReaderClass = reinterpret_cast<jclass>(jniEnv->NewGlobalRef(jniEnv ->FindClass("java/io/InputStreamReader")));
59 jInputStreamReaderConstructorID = jniEnv->GetMethodID(jInputStreamReaderClass, "<init>", "(Ljava/io/InputStream;Ljava/lang/String;)V");
60 jBufferedReaderClass = reinterpret_cast<jclass>(jniEnv->NewGlobalRef(jniEnv->F indClass("java/io/BufferedReader")));
61 jBufferedReaderConstructorID = jniEnv->GetMethodID(jBufferedReaderClass, "<ini t>", "(Ljava/io/Reader;)V");
62 jStringBuilderClass = reinterpret_cast<jclass>(jniEnv->NewGlobalRef(jniEnv->Fi ndClass("java/lang/StringBuilder")));
63 jStringBuilderConstructorID = jniEnv->GetMethodID(jStringBuilderClass, "<init> ", "()V");
64 jBufferedReaderReadID = jniEnv->GetMethodID(jBufferedReaderClass, "read", "([C II)I");
65 jStringBuilderAppendID = jniEnv->GetMethodID(jStringBuilderClass, "append", "( [CII)Ljava/lang/StringBuilder;");
66 jStringBuilderToStringID = jniEnv->GetMethodID(jStringBuilderClass, "toString" , "()Ljava/lang/String;");
67 jBufferedReaderCloseID = jniEnv->GetMethodID(jBufferedReaderClass, "close", "( )V");
68 jConnectionGetHeaderFieldKeyID = jniEnv->GetMethodID(jConnectionClass, "getHea derField", "(I)Ljava/lang/String;");
69 jConnectionGetHeaderFieldID = jniEnv->GetMethodID(jConnectionClass, "getHeader FieldKey", "(I)Ljava/lang/String;");
70
71 if (stat == JNI_EDETACHED)
72 globalJvm->DetachCurrentThread();
73 }
74
75 AndroidWebRequest::~AndroidWebRequest()
76 {
77 JNIEnv* jniEnv = NULL;
78 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6);
79 if (stat == JNI_EDETACHED)
80 {
81 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0)
82 throw std::runtime_error("Failed to get JNI environment");
83 }
84
85 jniEnv->DeleteGlobalRef(jUrlClass);
86 jniEnv->DeleteGlobalRef(jConnectionClass);
87 jniEnv->DeleteGlobalRef(jInputStreamReaderClass);
88 jniEnv->DeleteGlobalRef(jBufferedReaderClass);
89 jniEnv->DeleteGlobalRef(jStringBuilderClass);
90
91 if (stat == JNI_EDETACHED)
92 globalJvm->DetachCurrentThread();
93 }
94
95 AdblockPlus::ServerResponse AndroidWebRequest::GET(
96 const std::string& url, const AdblockPlus::HeaderList& requestHeaders) const
97 {
98 JNIEnv* jniEnv = NULL;
99 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6);
100 if (stat == JNI_EDETACHED)
101 {
102 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0)
103 throw std::runtime_error("Failed to get JNI environment");
104 }
105
106 AdblockPlus::ServerResponse result;
107 result.status = NS_ERROR_FAILURE;
108 result.responseStatus = 0;
109
110 try
111 {
112 // URL jUrl = new URL(url)
Felix Dahlke 2013/09/13 14:40:39 Using JNI for all this is a bit cumbersome, I thin
113 jstring jUrlStr = jniEnv->NewStringUTF(url.c_str());
114
115 jobject jUrl = jniEnv->NewObject(jUrlClass, jUrlConstructorID, jUrlStr);
116 if (jniEnv->ExceptionCheck())
117 throw JavaException(jniEnv->ExceptionOccurred());
Wladimir Palant 2013/09/12 11:31:14 Seeing this block of code repeated all over the pl
Felix Dahlke 2013/09/13 14:40:39 I'd vote for HandleExceptions(); I also think we
118 jniEnv->DeleteLocalRef(jUrlStr);
Felix Dahlke 2013/09/13 14:40:39 DeleteLocalRef shouldn't be necessary here. It'll
119
120 // HttpURLConnection connection = (HttpURLConnection) jUrl.openConnection();
121 jobject jConnection = jniEnv->CallObjectMethod(jUrl, jUrlOpenConnectionID);
122 if (jniEnv->ExceptionCheck())
123 throw JavaException(jniEnv->ExceptionOccurred());
124
125 // connection.setRequestMethod("GET");
126 jstring jMethod = jniEnv->NewStringUTF("GET");
127 jniEnv->CallVoidMethod(jConnection, jConnectionSetMethodID, jMethod);
128 if (jniEnv->ExceptionCheck())
129 throw JavaException(jniEnv->ExceptionOccurred());
130 jniEnv->DeleteLocalRef(jMethod);
131
132 for (int i = 0; i < requestHeaders.size(); i++)
133 {
134 // connection.setRequestProperty(requestHeaders[i].first, requestHeaders[i ].second);
135 jstring jHeader = jniEnv->NewStringUTF(requestHeaders[i].first.c_str());
136 jstring jValue = jniEnv->NewStringUTF(requestHeaders[i].second.c_str());
137 jniEnv->CallVoidMethod(jConnection, jConnectionSetRequestPropertyID, jHead er, jValue);
138 if (jniEnv->ExceptionCheck())
139 throw JavaException(jniEnv->ExceptionOccurred());
140 jniEnv->DeleteLocalRef(jHeader);
141 jniEnv->DeleteLocalRef(jValue);
142 }
143
144 // connection.connect();
145 jniEnv->CallVoidMethod(jConnection, jConnectionConnectID);
146 if (jniEnv->ExceptionCheck())
147 throw JavaException(jniEnv->ExceptionOccurred());
148
149 // int lenghtOfFile = connection.getContentLength();
150 jint lenghtOfFile = jniEnv->CallIntMethod(jConnection, jConnectionGetContent LengthID);
Wladimir Palant 2013/09/12 11:31:14 This variable's name is misspelled, and it isn't a
151 if (jniEnv->ExceptionCheck())
152 throw JavaException(jniEnv->ExceptionOccurred());
153
154 D(D_WARN, "Size: %d", lenghtOfFile);
155
156 // result.responseStatus = connection.getResponseCode();
157 result.responseStatus = jniEnv->CallIntMethod(jConnection, jConnectionGetRes ponseCodeID);
158 if (jniEnv->ExceptionCheck())
159 throw JavaException(jniEnv->ExceptionOccurred());
160
161 /* Read response data */
162
163 // String jEncoding = connection.getContentEncoding();
164 jstring jEncoding = (jstring) jniEnv->CallObjectMethod(jConnection, jConnect ionGetContentEncodingID);
165 if (jniEnv->ExceptionCheck())
166 throw JavaException(jniEnv->ExceptionOccurred());
167
168 if (jEncoding == NULL)
169 jEncoding = jniEnv->NewStringUTF("utf-8");
170
171 // InputStream jis = connection.getInputStream();
172 jobject jis = jniEnv->CallObjectMethod(jConnection, jConnectionGetInputStrea mID);
173 if (jniEnv->ExceptionCheck())
174 throw JavaException(jniEnv->ExceptionOccurred());
175
176 // InputStreamReader jisr = new InputStreamReader(jis, jEncoding);
177 jobject jisr = jniEnv->NewObject(jInputStreamReaderClass, jInputStreamReader ConstructorID, jis, jEncoding);
178 if (jniEnv->ExceptionCheck())
179 throw JavaException(jniEnv->ExceptionOccurred());
180
181 jniEnv->DeleteLocalRef(jEncoding);
182
183 // BufferedReader jin = new BufferedReader(jisr);
184 jobject jin = jniEnv->NewObject(jBufferedReaderClass, jBufferedReaderConstru ctorID, jisr);
185 if (jniEnv->ExceptionCheck())
186 throw JavaException(jniEnv->ExceptionOccurred());
187
188 // char[] jBuffer = new char[0x10000];
189 jcharArray jBuffer = jniEnv->NewCharArray(0x10000);
190
191 // StringBuilder jout = new StringBuilder();
192 jobject jout = jniEnv->NewObject(jStringBuilderClass, jStringBuilderConstruc torID);
193 if (jniEnv->ExceptionCheck())
194 throw JavaException(jniEnv->ExceptionOccurred());
195
196 jlong total = 0;
197 jint read;
198
199 jint jBufferLength = (jint) jniEnv->GetArrayLength(jBuffer);
200
201 do
202 {
203 // read = jin.read(buffer, 0, buffer.length);
204 read = jniEnv->CallIntMethod(jin, jBufferedReaderReadID, jBuffer, 0, jBuff erLength);
205 if (jniEnv->ExceptionCheck())
206 throw JavaException(jniEnv->ExceptionOccurred());
207
208 if (read > 0)
209 {
210 // jout.append(buffer, 0, read);
211 jniEnv->CallObjectMethod(jout, jStringBuilderAppendID, jBuffer, 0, jBuff erLength);
212 if (jniEnv->ExceptionCheck())
213 throw JavaException(jniEnv->ExceptionOccurred());
214
215 total += read;
216 }
217 }
218 while (read >= 0);
219
220 // String jData = out.toString();
221 jstring jData = (jstring) jniEnv->CallObjectMethod(jout, jStringBuilderToStr ingID);
222 if (jniEnv->ExceptionCheck())
223 throw JavaException(jniEnv->ExceptionOccurred());
224
225 result.responseText = GetString(jniEnv, jData);
226
227 // jin.close();
228 jniEnv->CallVoidMethod(jin, jBufferedReaderCloseID);
229 if (jniEnv->ExceptionCheck())
230 throw JavaException(jniEnv->ExceptionOccurred());
231
232 jint i = 0;
233 while (true)
Felix Dahlke 2013/09/13 14:40:39 How about |for (jint i = 0; ; i++)| instead?
234 {
235 // String jHeaderName = connection.getHeaderFieldKey(i)
236 jstring jHeaderName = (jstring) jniEnv->CallObjectMethod(jConnection, jCon nectionGetHeaderFieldKeyID, i);
237 if (jniEnv->ExceptionCheck())
238 throw JavaException(jniEnv->ExceptionOccurred());
239
240 // String jHeaderValue = connection.getHeaderField(i)
241 jstring jHeaderValue = (jstring) jniEnv->CallObjectMethod(jConnection, jCo nnectionGetHeaderFieldID, i);
242 if (jniEnv->ExceptionCheck())
243 throw JavaException(jniEnv->ExceptionOccurred());
244
245 if (jHeaderValue == NULL)
Wladimir Palant 2013/09/12 11:31:14 From all I know, NULL is a Windows-specific consta
Felix Dahlke 2013/09/13 14:40:39 NULL is not Windows-specific, it's in ANSI C. But
246 break;
247
248 std::string headerName = GetString(jniEnv, jHeaderName);
249 std::string headerValue = GetString(jniEnv, jHeaderValue);
250
251 headerName = TrimString(headerName);
252 headerValue = TrimString(headerValue);
253
254 std::transform(headerName.begin(), headerName.end(), headerName.begin(), : :tolower);
255 std::transform(headerValue.begin(), headerValue.end(), headerValue.begin() , ::tolower);
Wladimir Palant 2013/09/12 11:31:14 Please do not lower-case the value, only the heade
256
257 result.responseHeaders.push_back(std::pair<std::string, std::string>(heade rName, headerValue));
258
259 i++;
260 }
261 D(D_WARN, "Finished downloading");
262
263 result.status = AdblockPlus::DefaultWebRequest::NS_OK;
264 }
265 catch(JavaException& e)
266 {
267 jniEnv->ExceptionClear();
268 jclass jThrowableClass = jniEnv->FindClass("java/lang/Throwable");
269 jmethodID jThrowableToStringID = jniEnv->GetMethodID(jThrowableClass, "toStr ing", "()Ljava/lang/String;");
270 jstring jMsg = (jstring) jniEnv->CallObjectMethod(e.ex, jThrowableToStringID );
271 const char* msg = jniEnv->GetStringUTFChars(jMsg, 0);
272 D(D_ERROR, "Java Exception: %s", msg);
273 jniEnv->ReleaseStringUTFChars(jMsg, msg);
274 jniEnv->DeleteLocalRef(jMsg);
275 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE;
Wladimir Palant 2013/09/12 11:31:14 I think that we should try to do better than that.
276 }
277 catch (const std::exception& e)
278 {
279 D(D_ERROR, "Exception: %s", e.what());
280 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE;
281 }
282 catch (...)
283 {
284 D(D_ERROR, "Unknown exception");
285 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE;
286 }
287
288 if (stat == JNI_EDETACHED)
289 globalJvm->DetachCurrentThread();
290
291 return result;
292 }
OLDNEW

Powered by Google App Engine
This is Rietveld