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: Created Nov. 22, 2013, 4:15 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 const char* nativeMessage = env->GetStringUTFChars(javaMessage, 0);
31 const std::string message = nativeMessage;
32 env->ReleaseStringUTFChars(javaMessage, nativeMessage);
33 return message;
29 } 34 }
30 35
31 const char* what() const throw() 36 class JavaException : public std::exception
32 { 37 {
33 return "Java Exception"; 38 public:
39 JavaException(JNIEnv* env)
40 : env(env), throwable(env->ExceptionOccurred())
41 {
42 env->ExceptionClear();
43 message = ExtractExceptionMessage(env, throwable);
44 }
45
46 virtual ~JavaException() throw()
47 {
48 }
49
50 const char* what() const throw()
51 {
52 return ("Java Exception: " + message).c_str();
Wladimir Palant 2013/11/22 17:51:03 You are creating a temporary std::string instance
Felix Dahlke 2013/11/22 18:01:12 Done.
53 }
54
55 bool IsInstanceOf(const std::string& className) const
56 {
57 jclass clazz = env->FindClass(className.c_str());
58 if (!clazz)
59 return false;
60 bool isInstance = env->IsInstanceOf(throwable, clazz);
61 env->DeleteLocalRef(clazz);
62 return isInstance;
63 }
64
65 private:
66 JNIEnv* env;
67 jthrowable throwable;
68 std::string message;
69 };
70
71 int64_t ExceptionToStatus(const JavaException& exception)
72 {
73 if (exception.IsInstanceOf("java/net/MalformedURLException"))
74 return AdblockPlus::WebRequest::NS_ERROR_MALFORMED_URI;
75 if (exception.IsInstanceOf("java/net/SocketTimeoutException"))
76 return AdblockPlus::WebRequest::NS_ERROR_NET_TIMEOUT;
77 return AdblockPlus::WebRequest::NS_ERROR_FAILURE;
34 } 78 }
35 }; 79 }
36 80
37 AndroidWebRequest::AndroidWebRequest(JavaVM*& gJvm) : globalJvm(gJvm) 81 AndroidWebRequest::AndroidWebRequest(JavaVM*& gJvm) : globalJvm(gJvm)
38 { 82 {
39 JNIEnv* jniEnv = NULL; 83 JNIEnv* jniEnv = NULL;
40 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6); 84 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6);
41 if (stat == JNI_EDETACHED) 85 if (stat == JNI_EDETACHED)
42 { 86 {
43 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0) 87 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0)
44 throw std::runtime_error("Failed to get JNI environment"); 88 throw std::runtime_error("Failed to get JNI environment");
45 } 89 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 { 141 {
98 JNIEnv* jniEnv = NULL; 142 JNIEnv* jniEnv = NULL;
99 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6); 143 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6);
100 if (stat == JNI_EDETACHED) 144 if (stat == JNI_EDETACHED)
101 { 145 {
102 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0) 146 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0)
103 throw std::runtime_error("Failed to get JNI environment"); 147 throw std::runtime_error("Failed to get JNI environment");
104 } 148 }
105 149
106 AdblockPlus::ServerResponse result; 150 AdblockPlus::ServerResponse result;
107 result.status = NS_ERROR_FAILURE;
108 result.responseStatus = 0;
109
110 try 151 try
111 { 152 {
112 // URL jUrl = new URL(url) 153 // URL jUrl = new URL(url)
113 jstring jUrlStr = jniEnv->NewStringUTF(url.c_str()); 154 jstring jUrlStr = jniEnv->NewStringUTF(url.c_str());
114 155
115 jobject jUrl = jniEnv->NewObject(jUrlClass, jUrlConstructorID, jUrlStr); 156 jobject jUrl = jniEnv->NewObject(jUrlClass, jUrlConstructorID, jUrlStr);
116 if (jniEnv->ExceptionCheck()) 157 if (jniEnv->ExceptionCheck())
117 throw JavaException(jniEnv->ExceptionOccurred()); 158 throw JavaException(jniEnv);
118 jniEnv->DeleteLocalRef(jUrlStr); 159 jniEnv->DeleteLocalRef(jUrlStr);
119 160
120 // HttpURLConnection connection = (HttpURLConnection) jUrl.openConnection(); 161 // HttpURLConnection connection = (HttpURLConnection) jUrl.openConnection();
121 jobject jConnection = jniEnv->CallObjectMethod(jUrl, jUrlOpenConnectionID); 162 jobject jConnection = jniEnv->CallObjectMethod(jUrl, jUrlOpenConnectionID);
122 if (jniEnv->ExceptionCheck()) 163 if (jniEnv->ExceptionCheck())
123 throw JavaException(jniEnv->ExceptionOccurred()); 164 throw JavaException(jniEnv);
124 165
125 // connection.setRequestMethod("GET"); 166 // connection.setRequestMethod("GET");
126 jstring jMethod = jniEnv->NewStringUTF("GET"); 167 jstring jMethod = jniEnv->NewStringUTF("GET");
127 jniEnv->CallVoidMethod(jConnection, jConnectionSetMethodID, jMethod); 168 jniEnv->CallVoidMethod(jConnection, jConnectionSetMethodID, jMethod);
128 if (jniEnv->ExceptionCheck()) 169 if (jniEnv->ExceptionCheck())
129 throw JavaException(jniEnv->ExceptionOccurred()); 170 throw JavaException(jniEnv);
130 jniEnv->DeleteLocalRef(jMethod); 171 jniEnv->DeleteLocalRef(jMethod);
131 172
132 for (int i = 0; i < requestHeaders.size(); i++) 173 for (int i = 0; i < requestHeaders.size(); i++)
133 { 174 {
134 // connection.setRequestProperty(requestHeaders[i].first, requestHeaders[i ].second); 175 // connection.setRequestProperty(requestHeaders[i].first, requestHeaders[i ].second);
135 jstring jHeader = jniEnv->NewStringUTF(requestHeaders[i].first.c_str()); 176 jstring jHeader = jniEnv->NewStringUTF(requestHeaders[i].first.c_str());
136 jstring jValue = jniEnv->NewStringUTF(requestHeaders[i].second.c_str()); 177 jstring jValue = jniEnv->NewStringUTF(requestHeaders[i].second.c_str());
137 jniEnv->CallVoidMethod(jConnection, jConnectionSetRequestPropertyID, jHead er, jValue); 178 jniEnv->CallVoidMethod(jConnection, jConnectionSetRequestPropertyID, jHead er, jValue);
138 if (jniEnv->ExceptionCheck()) 179 if (jniEnv->ExceptionCheck())
139 throw JavaException(jniEnv->ExceptionOccurred()); 180 throw JavaException(jniEnv);
140 jniEnv->DeleteLocalRef(jHeader); 181 jniEnv->DeleteLocalRef(jHeader);
141 jniEnv->DeleteLocalRef(jValue); 182 jniEnv->DeleteLocalRef(jValue);
142 } 183 }
143 184
144 // connection.connect(); 185 // connection.connect();
145 jniEnv->CallVoidMethod(jConnection, jConnectionConnectID); 186 jniEnv->CallVoidMethod(jConnection, jConnectionConnectID);
146 if (jniEnv->ExceptionCheck()) 187 if (jniEnv->ExceptionCheck())
147 throw JavaException(jniEnv->ExceptionOccurred()); 188 throw JavaException(jniEnv);
148 189
149 // int lenghtOfFile = connection.getContentLength(); 190 // int lenghtOfFile = connection.getContentLength();
150 jint lenghtOfFile = jniEnv->CallIntMethod(jConnection, jConnectionGetContent LengthID); 191 jint lenghtOfFile = jniEnv->CallIntMethod(jConnection, jConnectionGetContent LengthID);
151 if (jniEnv->ExceptionCheck()) 192 if (jniEnv->ExceptionCheck())
152 throw JavaException(jniEnv->ExceptionOccurred()); 193 throw JavaException(jniEnv);
153 194
154 D(D_WARN, "Size: %d", lenghtOfFile); 195 D(D_WARN, "Size: %d", lenghtOfFile);
155 196
156 // result.responseStatus = connection.getResponseCode(); 197 // result.responseStatus = connection.getResponseCode();
157 result.responseStatus = jniEnv->CallIntMethod(jConnection, jConnectionGetRes ponseCodeID); 198 result.responseStatus = jniEnv->CallIntMethod(jConnection, jConnectionGetRes ponseCodeID);
158 if (jniEnv->ExceptionCheck()) 199 if (jniEnv->ExceptionCheck())
159 throw JavaException(jniEnv->ExceptionOccurred()); 200 throw JavaException(jniEnv);
160 201
161 /* Read response data */ 202 /* Read response data */
162 203
163 // String jEncoding = connection.getContentEncoding(); 204 // String jEncoding = connection.getContentEncoding();
164 jstring jEncoding = (jstring) jniEnv->CallObjectMethod(jConnection, jConnect ionGetContentEncodingID); 205 jstring jEncoding = (jstring) jniEnv->CallObjectMethod(jConnection, jConnect ionGetContentEncodingID);
165 if (jniEnv->ExceptionCheck()) 206 if (jniEnv->ExceptionCheck())
166 throw JavaException(jniEnv->ExceptionOccurred()); 207 throw JavaException(jniEnv);
167 208
168 if (jEncoding == NULL) 209 if (jEncoding == NULL)
169 jEncoding = jniEnv->NewStringUTF("utf-8"); 210 jEncoding = jniEnv->NewStringUTF("utf-8");
170 211
171 // InputStream jis = connection.getInputStream(); 212 // InputStream jis = connection.getInputStream();
172 jobject jis = jniEnv->CallObjectMethod(jConnection, jConnectionGetInputStrea mID); 213 jobject jis = jniEnv->CallObjectMethod(jConnection, jConnectionGetInputStrea mID);
173 if (jniEnv->ExceptionCheck()) 214 if (jniEnv->ExceptionCheck())
174 throw JavaException(jniEnv->ExceptionOccurred()); 215 throw JavaException(jniEnv);
175 216
176 // InputStreamReader jisr = new InputStreamReader(jis, jEncoding); 217 // InputStreamReader jisr = new InputStreamReader(jis, jEncoding);
177 jobject jisr = jniEnv->NewObject(jInputStreamReaderClass, jInputStreamReader ConstructorID, jis, jEncoding); 218 jobject jisr = jniEnv->NewObject(jInputStreamReaderClass, jInputStreamReader ConstructorID, jis, jEncoding);
178 if (jniEnv->ExceptionCheck()) 219 if (jniEnv->ExceptionCheck())
179 throw JavaException(jniEnv->ExceptionOccurred()); 220 throw JavaException(jniEnv);
180 221
181 jniEnv->DeleteLocalRef(jEncoding); 222 jniEnv->DeleteLocalRef(jEncoding);
182 223
183 // BufferedReader jin = new BufferedReader(jisr); 224 // BufferedReader jin = new BufferedReader(jisr);
184 jobject jin = jniEnv->NewObject(jBufferedReaderClass, jBufferedReaderConstru ctorID, jisr); 225 jobject jin = jniEnv->NewObject(jBufferedReaderClass, jBufferedReaderConstru ctorID, jisr);
185 if (jniEnv->ExceptionCheck()) 226 if (jniEnv->ExceptionCheck())
186 throw JavaException(jniEnv->ExceptionOccurred()); 227 throw JavaException(jniEnv);
187 228
188 // char[] jBuffer = new char[0x10000]; 229 // char[] jBuffer = new char[0x10000];
189 jcharArray jBuffer = jniEnv->NewCharArray(0x10000); 230 jcharArray jBuffer = jniEnv->NewCharArray(0x10000);
190 231
191 // StringBuilder jout = new StringBuilder(); 232 // StringBuilder jout = new StringBuilder();
192 jobject jout = jniEnv->NewObject(jStringBuilderClass, jStringBuilderConstruc torID); 233 jobject jout = jniEnv->NewObject(jStringBuilderClass, jStringBuilderConstruc torID);
193 if (jniEnv->ExceptionCheck()) 234 if (jniEnv->ExceptionCheck())
194 throw JavaException(jniEnv->ExceptionOccurred()); 235 throw JavaException(jniEnv);
195 236
196 jlong total = 0; 237 jlong total = 0;
197 jint read; 238 jint read;
198 239
199 jint jBufferLength = (jint) jniEnv->GetArrayLength(jBuffer); 240 jint jBufferLength = (jint) jniEnv->GetArrayLength(jBuffer);
200 241
201 do 242 do
202 { 243 {
203 // read = jin.read(buffer, 0, buffer.length); 244 // read = jin.read(buffer, 0, buffer.length);
204 read = jniEnv->CallIntMethod(jin, jBufferedReaderReadID, jBuffer, 0, jBuff erLength); 245 read = jniEnv->CallIntMethod(jin, jBufferedReaderReadID, jBuffer, 0, jBuff erLength);
205 if (jniEnv->ExceptionCheck()) 246 if (jniEnv->ExceptionCheck())
206 throw JavaException(jniEnv->ExceptionOccurred()); 247 throw JavaException(jniEnv);
207 248
208 if (read > 0) 249 if (read > 0)
209 { 250 {
210 // jout.append(buffer, 0, read); 251 // jout.append(buffer, 0, read);
211 jniEnv->CallObjectMethod(jout, jStringBuilderAppendID, jBuffer, 0, jBuff erLength); 252 jniEnv->CallObjectMethod(jout, jStringBuilderAppendID, jBuffer, 0, jBuff erLength);
212 if (jniEnv->ExceptionCheck()) 253 if (jniEnv->ExceptionCheck())
213 throw JavaException(jniEnv->ExceptionOccurred()); 254 throw JavaException(jniEnv);
214 255
215 total += read; 256 total += read;
216 } 257 }
217 } 258 }
218 while (read >= 0); 259 while (read >= 0);
219 260
220 // String jData = out.toString(); 261 // String jData = out.toString();
221 jstring jData = (jstring) jniEnv->CallObjectMethod(jout, jStringBuilderToStr ingID); 262 jstring jData = (jstring) jniEnv->CallObjectMethod(jout, jStringBuilderToStr ingID);
222 if (jniEnv->ExceptionCheck()) 263 if (jniEnv->ExceptionCheck())
223 throw JavaException(jniEnv->ExceptionOccurred()); 264 throw JavaException(jniEnv);
224 265
225 result.responseText = GetString(jniEnv, jData); 266 result.responseText = GetString(jniEnv, jData);
226 267
227 // jin.close(); 268 // jin.close();
228 jniEnv->CallVoidMethod(jin, jBufferedReaderCloseID); 269 jniEnv->CallVoidMethod(jin, jBufferedReaderCloseID);
229 if (jniEnv->ExceptionCheck()) 270 if (jniEnv->ExceptionCheck())
230 throw JavaException(jniEnv->ExceptionOccurred()); 271 throw JavaException(jniEnv);
231 272
232 jint i = 0; 273 jint i = 0;
233 while (true) 274 while (true)
234 { 275 {
235 // String jHeaderName = connection.getHeaderFieldKey(i) 276 // String jHeaderName = connection.getHeaderFieldKey(i)
236 jstring jHeaderName = (jstring) jniEnv->CallObjectMethod(jConnection, jCon nectionGetHeaderFieldKeyID, i); 277 jstring jHeaderName = (jstring) jniEnv->CallObjectMethod(jConnection, jCon nectionGetHeaderFieldKeyID, i);
237 if (jniEnv->ExceptionCheck()) 278 if (jniEnv->ExceptionCheck())
238 throw JavaException(jniEnv->ExceptionOccurred()); 279 throw JavaException(jniEnv);
239 280
240 // String jHeaderValue = connection.getHeaderField(i) 281 // String jHeaderValue = connection.getHeaderField(i)
241 jstring jHeaderValue = (jstring) jniEnv->CallObjectMethod(jConnection, jCo nnectionGetHeaderFieldID, i); 282 jstring jHeaderValue = (jstring) jniEnv->CallObjectMethod(jConnection, jCo nnectionGetHeaderFieldID, i);
242 if (jniEnv->ExceptionCheck()) 283 if (jniEnv->ExceptionCheck())
243 throw JavaException(jniEnv->ExceptionOccurred()); 284 throw JavaException(jniEnv);
244 285
245 if (!jHeaderValue) 286 if (!jHeaderValue)
246 break; 287 break;
247 288
248 std::string headerName = GetString(jniEnv, jHeaderName); 289 std::string headerName = GetString(jniEnv, jHeaderName);
249 std::string headerValue = GetString(jniEnv, jHeaderValue); 290 std::string headerValue = GetString(jniEnv, jHeaderValue);
250 291
251 headerName = TrimString(headerName); 292 headerName = TrimString(headerName);
252 headerValue = TrimString(headerValue); 293 headerValue = TrimString(headerValue);
253 294
254 std::transform(headerName.begin(), headerName.end(), headerName.begin(), : :tolower); 295 std::transform(headerName.begin(), headerName.end(), headerName.begin(), : :tolower);
255 296
256 result.responseHeaders.push_back(std::pair<std::string, std::string>(heade rName, headerValue)); 297 result.responseHeaders.push_back(std::pair<std::string, std::string>(heade rName, headerValue));
257 298
258 i++; 299 i++;
259 } 300 }
260 D(D_WARN, "Finished downloading"); 301 D(D_WARN, "Finished downloading");
261 302
262 result.status = AdblockPlus::DefaultWebRequest::NS_OK; 303 result.status = NS_OK;
263 } 304 }
264 catch(JavaException& e) 305 catch(JavaException& e)
265 { 306 {
266 jniEnv->ExceptionClear(); 307 result.responseStatus = 0;
267 jclass jThrowableClass = jniEnv->FindClass("java/lang/Throwable"); 308 result.status = ExceptionToStatus(e);
268 jmethodID jThrowableToStringID = jniEnv->GetMethodID(jThrowableClass, "toStr ing", "()Ljava/lang/String;"); 309 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 } 310 }
276 catch (const std::exception& e) 311 catch (const std::exception& e)
277 { 312 {
278 D(D_ERROR, "Exception: %s", e.what()); 313 D(D_ERROR, "Exception: %s", e.what());
279 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE; 314 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE;
280 } 315 }
281 catch (...) 316 catch (...)
282 { 317 {
283 D(D_ERROR, "Unknown exception"); 318 D(D_ERROR, "Unknown exception");
284 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE; 319 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE;
285 } 320 }
286 321
287 if (stat == JNI_EDETACHED) 322 if (stat == JNI_EDETACHED)
288 globalJvm->DetachCurrentThread(); 323 globalJvm->DetachCurrentThread();
289 324
290 return result; 325 return result;
291 } 326 }
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