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

Side by Side Diff: jni/AndroidWebRequest.cpp

Issue 5668574207148032: Handle network errors better (Closed)
Patch Set: Use GetString() and don't return a c_str() to a temporary string object Created Nov. 22, 2013, 6 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2013 Eyeo GmbH 3 * Copyright (C) 2006-2013 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 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/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 #include <AdblockPlus.h> 18 #include <AdblockPlus.h>
19 #include "AndroidWebRequest.h" 19 #include "AndroidWebRequest.h"
20 #include "Utils.h" 20 #include "Utils.h"
21 #include "debug.h" 21 #include "debug.h"
22 22
23 struct JavaException : public std::exception 23 namespace
24 { 24 {
25 jthrowable ex; 25 std::string ExtractExceptionMessage(JNIEnv* env, jthrowable throwable)
26
27 JavaException(jthrowable e) : ex(e)
28 { 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);
29 } 31 }
30 32
31 const char* what() const throw() 33 class JavaException : public std::exception
32 { 34 {
33 return "Java Exception"; 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;
34 } 75 }
35 }; 76 }
36 77
37 AndroidWebRequest::AndroidWebRequest(JavaVM*& gJvm) : globalJvm(gJvm) 78 AndroidWebRequest::AndroidWebRequest(JavaVM*& gJvm) : globalJvm(gJvm)
38 { 79 {
39 JNIEnv* jniEnv = NULL; 80 JNIEnv* jniEnv = NULL;
40 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6); 81 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6);
41 if (stat == JNI_EDETACHED) 82 if (stat == JNI_EDETACHED)
42 { 83 {
43 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0) 84 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0)
44 throw std::runtime_error("Failed to get JNI environment"); 85 throw std::runtime_error("Failed to get JNI environment");
45 } 86 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 { 138 {
98 JNIEnv* jniEnv = NULL; 139 JNIEnv* jniEnv = NULL;
99 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6); 140 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6);
100 if (stat == JNI_EDETACHED) 141 if (stat == JNI_EDETACHED)
101 { 142 {
102 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0) 143 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0)
103 throw std::runtime_error("Failed to get JNI environment"); 144 throw std::runtime_error("Failed to get JNI environment");
104 } 145 }
105 146
106 AdblockPlus::ServerResponse result; 147 AdblockPlus::ServerResponse result;
107 result.status = NS_ERROR_FAILURE;
108 result.responseStatus = 0;
109
110 try 148 try
111 { 149 {
112 // URL jUrl = new URL(url) 150 // URL jUrl = new URL(url)
113 jstring jUrlStr = jniEnv->NewStringUTF(url.c_str()); 151 jstring jUrlStr = jniEnv->NewStringUTF(url.c_str());
114 152
115 jobject jUrl = jniEnv->NewObject(jUrlClass, jUrlConstructorID, jUrlStr); 153 jobject jUrl = jniEnv->NewObject(jUrlClass, jUrlConstructorID, jUrlStr);
116 if (jniEnv->ExceptionCheck()) 154 if (jniEnv->ExceptionCheck())
117 throw JavaException(jniEnv->ExceptionOccurred()); 155 throw JavaException(jniEnv);
118 jniEnv->DeleteLocalRef(jUrlStr); 156 jniEnv->DeleteLocalRef(jUrlStr);
119 157
120 // HttpURLConnection connection = (HttpURLConnection) jUrl.openConnection(); 158 // HttpURLConnection connection = (HttpURLConnection) jUrl.openConnection();
121 jobject jConnection = jniEnv->CallObjectMethod(jUrl, jUrlOpenConnectionID); 159 jobject jConnection = jniEnv->CallObjectMethod(jUrl, jUrlOpenConnectionID);
122 if (jniEnv->ExceptionCheck()) 160 if (jniEnv->ExceptionCheck())
123 throw JavaException(jniEnv->ExceptionOccurred()); 161 throw JavaException(jniEnv);
124 162
125 // connection.setRequestMethod("GET"); 163 // connection.setRequestMethod("GET");
126 jstring jMethod = jniEnv->NewStringUTF("GET"); 164 jstring jMethod = jniEnv->NewStringUTF("GET");
127 jniEnv->CallVoidMethod(jConnection, jConnectionSetMethodID, jMethod); 165 jniEnv->CallVoidMethod(jConnection, jConnectionSetMethodID, jMethod);
128 if (jniEnv->ExceptionCheck()) 166 if (jniEnv->ExceptionCheck())
129 throw JavaException(jniEnv->ExceptionOccurred()); 167 throw JavaException(jniEnv);
130 jniEnv->DeleteLocalRef(jMethod); 168 jniEnv->DeleteLocalRef(jMethod);
131 169
132 for (int i = 0; i < requestHeaders.size(); i++) 170 for (int i = 0; i < requestHeaders.size(); i++)
133 { 171 {
134 // connection.setRequestProperty(requestHeaders[i].first, requestHeaders[i ].second); 172 // connection.setRequestProperty(requestHeaders[i].first, requestHeaders[i ].second);
135 jstring jHeader = jniEnv->NewStringUTF(requestHeaders[i].first.c_str()); 173 jstring jHeader = jniEnv->NewStringUTF(requestHeaders[i].first.c_str());
136 jstring jValue = jniEnv->NewStringUTF(requestHeaders[i].second.c_str()); 174 jstring jValue = jniEnv->NewStringUTF(requestHeaders[i].second.c_str());
137 jniEnv->CallVoidMethod(jConnection, jConnectionSetRequestPropertyID, jHead er, jValue); 175 jniEnv->CallVoidMethod(jConnection, jConnectionSetRequestPropertyID, jHead er, jValue);
138 if (jniEnv->ExceptionCheck()) 176 if (jniEnv->ExceptionCheck())
139 throw JavaException(jniEnv->ExceptionOccurred()); 177 throw JavaException(jniEnv);
140 jniEnv->DeleteLocalRef(jHeader); 178 jniEnv->DeleteLocalRef(jHeader);
141 jniEnv->DeleteLocalRef(jValue); 179 jniEnv->DeleteLocalRef(jValue);
142 } 180 }
143 181
144 // connection.connect(); 182 // connection.connect();
145 jniEnv->CallVoidMethod(jConnection, jConnectionConnectID); 183 jniEnv->CallVoidMethod(jConnection, jConnectionConnectID);
146 if (jniEnv->ExceptionCheck()) 184 if (jniEnv->ExceptionCheck())
147 throw JavaException(jniEnv->ExceptionOccurred()); 185 throw JavaException(jniEnv);
148 186
149 // int lenghtOfFile = connection.getContentLength(); 187 // int lenghtOfFile = connection.getContentLength();
150 jint lenghtOfFile = jniEnv->CallIntMethod(jConnection, jConnectionGetContent LengthID); 188 jint lenghtOfFile = jniEnv->CallIntMethod(jConnection, jConnectionGetContent LengthID);
151 if (jniEnv->ExceptionCheck()) 189 if (jniEnv->ExceptionCheck())
152 throw JavaException(jniEnv->ExceptionOccurred()); 190 throw JavaException(jniEnv);
153 191
154 D(D_WARN, "Size: %d", lenghtOfFile); 192 D(D_WARN, "Size: %d", lenghtOfFile);
155 193
156 // result.responseStatus = connection.getResponseCode(); 194 // result.responseStatus = connection.getResponseCode();
157 result.responseStatus = jniEnv->CallIntMethod(jConnection, jConnectionGetRes ponseCodeID); 195 result.responseStatus = jniEnv->CallIntMethod(jConnection, jConnectionGetRes ponseCodeID);
158 if (jniEnv->ExceptionCheck()) 196 if (jniEnv->ExceptionCheck())
159 throw JavaException(jniEnv->ExceptionOccurred()); 197 throw JavaException(jniEnv);
160 198
161 /* Read response data */ 199 /* Read response data */
162 200
163 // String jEncoding = connection.getContentEncoding(); 201 // String jEncoding = connection.getContentEncoding();
164 jstring jEncoding = (jstring) jniEnv->CallObjectMethod(jConnection, jConnect ionGetContentEncodingID); 202 jstring jEncoding = (jstring) jniEnv->CallObjectMethod(jConnection, jConnect ionGetContentEncodingID);
165 if (jniEnv->ExceptionCheck()) 203 if (jniEnv->ExceptionCheck())
166 throw JavaException(jniEnv->ExceptionOccurred()); 204 throw JavaException(jniEnv);
167 205
168 if (jEncoding == NULL) 206 if (jEncoding == NULL)
169 jEncoding = jniEnv->NewStringUTF("utf-8"); 207 jEncoding = jniEnv->NewStringUTF("utf-8");
170 208
171 // InputStream jis = connection.getInputStream(); 209 // InputStream jis = connection.getInputStream();
172 jobject jis = jniEnv->CallObjectMethod(jConnection, jConnectionGetInputStrea mID); 210 jobject jis = jniEnv->CallObjectMethod(jConnection, jConnectionGetInputStrea mID);
173 if (jniEnv->ExceptionCheck()) 211 if (jniEnv->ExceptionCheck())
174 throw JavaException(jniEnv->ExceptionOccurred()); 212 throw JavaException(jniEnv);
175 213
176 // InputStreamReader jisr = new InputStreamReader(jis, jEncoding); 214 // InputStreamReader jisr = new InputStreamReader(jis, jEncoding);
177 jobject jisr = jniEnv->NewObject(jInputStreamReaderClass, jInputStreamReader ConstructorID, jis, jEncoding); 215 jobject jisr = jniEnv->NewObject(jInputStreamReaderClass, jInputStreamReader ConstructorID, jis, jEncoding);
178 if (jniEnv->ExceptionCheck()) 216 if (jniEnv->ExceptionCheck())
179 throw JavaException(jniEnv->ExceptionOccurred()); 217 throw JavaException(jniEnv);
180 218
181 jniEnv->DeleteLocalRef(jEncoding); 219 jniEnv->DeleteLocalRef(jEncoding);
182 220
183 // BufferedReader jin = new BufferedReader(jisr); 221 // BufferedReader jin = new BufferedReader(jisr);
184 jobject jin = jniEnv->NewObject(jBufferedReaderClass, jBufferedReaderConstru ctorID, jisr); 222 jobject jin = jniEnv->NewObject(jBufferedReaderClass, jBufferedReaderConstru ctorID, jisr);
185 if (jniEnv->ExceptionCheck()) 223 if (jniEnv->ExceptionCheck())
186 throw JavaException(jniEnv->ExceptionOccurred()); 224 throw JavaException(jniEnv);
187 225
188 // char[] jBuffer = new char[0x10000]; 226 // char[] jBuffer = new char[0x10000];
189 jcharArray jBuffer = jniEnv->NewCharArray(0x10000); 227 jcharArray jBuffer = jniEnv->NewCharArray(0x10000);
190 228
191 // StringBuilder jout = new StringBuilder(); 229 // StringBuilder jout = new StringBuilder();
192 jobject jout = jniEnv->NewObject(jStringBuilderClass, jStringBuilderConstruc torID); 230 jobject jout = jniEnv->NewObject(jStringBuilderClass, jStringBuilderConstruc torID);
193 if (jniEnv->ExceptionCheck()) 231 if (jniEnv->ExceptionCheck())
194 throw JavaException(jniEnv->ExceptionOccurred()); 232 throw JavaException(jniEnv);
195 233
196 jlong total = 0; 234 jlong total = 0;
197 jint read; 235 jint read;
198 236
199 jint jBufferLength = (jint) jniEnv->GetArrayLength(jBuffer); 237 jint jBufferLength = (jint) jniEnv->GetArrayLength(jBuffer);
200 238
201 do 239 do
202 { 240 {
203 // read = jin.read(buffer, 0, buffer.length); 241 // read = jin.read(buffer, 0, buffer.length);
204 read = jniEnv->CallIntMethod(jin, jBufferedReaderReadID, jBuffer, 0, jBuff erLength); 242 read = jniEnv->CallIntMethod(jin, jBufferedReaderReadID, jBuffer, 0, jBuff erLength);
205 if (jniEnv->ExceptionCheck()) 243 if (jniEnv->ExceptionCheck())
206 throw JavaException(jniEnv->ExceptionOccurred()); 244 throw JavaException(jniEnv);
207 245
208 if (read > 0) 246 if (read > 0)
209 { 247 {
210 // jout.append(buffer, 0, read); 248 // jout.append(buffer, 0, read);
211 jniEnv->CallObjectMethod(jout, jStringBuilderAppendID, jBuffer, 0, jBuff erLength); 249 jniEnv->CallObjectMethod(jout, jStringBuilderAppendID, jBuffer, 0, jBuff erLength);
212 if (jniEnv->ExceptionCheck()) 250 if (jniEnv->ExceptionCheck())
213 throw JavaException(jniEnv->ExceptionOccurred()); 251 throw JavaException(jniEnv);
214 252
215 total += read; 253 total += read;
216 } 254 }
217 } 255 }
218 while (read >= 0); 256 while (read >= 0);
219 257
220 // String jData = out.toString(); 258 // String jData = out.toString();
221 jstring jData = (jstring) jniEnv->CallObjectMethod(jout, jStringBuilderToStr ingID); 259 jstring jData = (jstring) jniEnv->CallObjectMethod(jout, jStringBuilderToStr ingID);
222 if (jniEnv->ExceptionCheck()) 260 if (jniEnv->ExceptionCheck())
223 throw JavaException(jniEnv->ExceptionOccurred()); 261 throw JavaException(jniEnv);
224 262
225 result.responseText = GetString(jniEnv, jData); 263 result.responseText = GetString(jniEnv, jData);
226 264
227 // jin.close(); 265 // jin.close();
228 jniEnv->CallVoidMethod(jin, jBufferedReaderCloseID); 266 jniEnv->CallVoidMethod(jin, jBufferedReaderCloseID);
229 if (jniEnv->ExceptionCheck()) 267 if (jniEnv->ExceptionCheck())
230 throw JavaException(jniEnv->ExceptionOccurred()); 268 throw JavaException(jniEnv);
231 269
232 jint i = 0; 270 jint i = 0;
233 while (true) 271 while (true)
234 { 272 {
235 // String jHeaderName = connection.getHeaderFieldKey(i) 273 // String jHeaderName = connection.getHeaderFieldKey(i)
236 jstring jHeaderName = (jstring) jniEnv->CallObjectMethod(jConnection, jCon nectionGetHeaderFieldKeyID, i); 274 jstring jHeaderName = (jstring) jniEnv->CallObjectMethod(jConnection, jCon nectionGetHeaderFieldKeyID, i);
237 if (jniEnv->ExceptionCheck()) 275 if (jniEnv->ExceptionCheck())
238 throw JavaException(jniEnv->ExceptionOccurred()); 276 throw JavaException(jniEnv);
239 277
240 // String jHeaderValue = connection.getHeaderField(i) 278 // String jHeaderValue = connection.getHeaderField(i)
241 jstring jHeaderValue = (jstring) jniEnv->CallObjectMethod(jConnection, jCo nnectionGetHeaderFieldID, i); 279 jstring jHeaderValue = (jstring) jniEnv->CallObjectMethod(jConnection, jCo nnectionGetHeaderFieldID, i);
242 if (jniEnv->ExceptionCheck()) 280 if (jniEnv->ExceptionCheck())
243 throw JavaException(jniEnv->ExceptionOccurred()); 281 throw JavaException(jniEnv);
244 282
245 if (!jHeaderValue) 283 if (!jHeaderValue)
246 break; 284 break;
247 285
248 std::string headerName = GetString(jniEnv, jHeaderName); 286 std::string headerName = GetString(jniEnv, jHeaderName);
249 std::string headerValue = GetString(jniEnv, jHeaderValue); 287 std::string headerValue = GetString(jniEnv, jHeaderValue);
250 288
251 headerName = TrimString(headerName); 289 headerName = TrimString(headerName);
252 headerValue = TrimString(headerValue); 290 headerValue = TrimString(headerValue);
253 291
254 std::transform(headerName.begin(), headerName.end(), headerName.begin(), : :tolower); 292 std::transform(headerName.begin(), headerName.end(), headerName.begin(), : :tolower);
255 293
256 result.responseHeaders.push_back(std::pair<std::string, std::string>(heade rName, headerValue)); 294 result.responseHeaders.push_back(std::pair<std::string, std::string>(heade rName, headerValue));
257 295
258 i++; 296 i++;
259 } 297 }
260 D(D_WARN, "Finished downloading"); 298 D(D_WARN, "Finished downloading");
261 299
262 result.status = AdblockPlus::DefaultWebRequest::NS_OK; 300 result.status = NS_OK;
263 } 301 }
264 catch(JavaException& e) 302 catch(JavaException& e)
265 { 303 {
266 jniEnv->ExceptionClear(); 304 result.responseStatus = 0;
267 jclass jThrowableClass = jniEnv->FindClass("java/lang/Throwable"); 305 result.status = ExceptionToStatus(e);
268 jmethodID jThrowableToStringID = jniEnv->GetMethodID(jThrowableClass, "toStr ing", "()Ljava/lang/String;"); 306 D(D_ERROR, "%s", e.what());
269 jstring jMsg = (jstring) jniEnv->CallObjectMethod(e.ex, jThrowableToStringID );
270 const char* msg = jniEnv->GetStringUTFChars(jMsg, 0);
271 D(D_ERROR, "Java Exception: %s", msg);
272 jniEnv->ReleaseStringUTFChars(jMsg, msg);
273 jniEnv->DeleteLocalRef(jMsg);
274 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE;
275 } 307 }
276 catch (const std::exception& e) 308 catch (const std::exception& e)
277 { 309 {
278 D(D_ERROR, "Exception: %s", e.what()); 310 D(D_ERROR, "Exception: %s", e.what());
279 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE; 311 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE;
280 } 312 }
281 catch (...) 313 catch (...)
282 { 314 {
283 D(D_ERROR, "Unknown exception"); 315 D(D_ERROR, "Unknown exception");
284 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE; 316 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE;
285 } 317 }
286 318
287 if (stat == JNI_EDETACHED) 319 if (stat == JNI_EDETACHED)
288 globalJvm->DetachCurrentThread(); 320 globalJvm->DetachCurrentThread();
289 321
290 return result; 322 return result;
291 } 323 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld