|
12 | 12 | import java.net.SocketTimeoutException;
|
13 | 13 | import java.net.UnknownHostException;
|
14 | 14 |
|
| 15 | +import java.nio.ByteBuffer; |
| 16 | + |
| 17 | +import java.nio.charset.CharacterCodingException; |
| 18 | +import java.nio.charset.Charset; |
| 19 | +import java.nio.charset.CharsetDecoder; |
| 20 | +import java.nio.charset.CodingErrorAction; |
| 21 | +import java.nio.charset.MalformedInputException; |
| 22 | + |
15 | 23 | import javax.net.ssl.SSLHandshakeException;
|
16 | 24 |
|
17 | 25 | import java.util.ArrayList;
|
18 | 26 | import java.util.HashMap;
|
19 | 27 | import java.util.List;
|
20 | 28 | import java.util.Map;
|
21 | 29 | import java.util.concurrent.atomic.AtomicBoolean;
|
| 30 | +import java.util.concurrent.atomic.AtomicReference; |
22 | 31 | import java.util.Iterator;
|
23 | 32 |
|
24 | 33 | import android.text.TextUtils;
|
|
28 | 37 |
|
29 | 38 | abstract class CordovaHttp {
|
30 | 39 | protected static final String TAG = "CordovaHTTP";
|
31 |
| - protected static final String[] ACCEPTED_CHARSETS = new String[] {HttpRequest.CHARSET_UTF8, HttpRequest.CHARSET_LATIN1}; |
| 40 | + protected static final String[] ACCEPTED_CHARSETS = new String[] { HttpRequest.CHARSET_UTF8, HttpRequest.CHARSET_LATIN1 }; |
32 | 41 |
|
33 | 42 | private static AtomicBoolean sslPinning = new AtomicBoolean(false);
|
34 | 43 | private static AtomicBoolean acceptAllCerts = new AtomicBoolean(false);
|
@@ -231,25 +240,68 @@ protected void prepareRequest(HttpRequest request) throws HttpRequestException,
|
231 | 240 | request.uncompress(true);
|
232 | 241 | }
|
233 | 242 |
|
| 243 | + private CharsetDecoder createCharsetDecoder(final String charsetName) { |
| 244 | + return Charset.forName(charsetName).newDecoder() |
| 245 | + .onMalformedInput(CodingErrorAction.REPORT) |
| 246 | + .onUnmappableCharacter(CodingErrorAction.REPORT); |
| 247 | + } |
| 248 | + |
| 249 | + private String decodeBody(AtomicReference<ByteBuffer> rawOutput, String charsetName) |
| 250 | + throws CharacterCodingException, MalformedInputException { |
| 251 | + |
| 252 | + if (charsetName == null) { |
| 253 | + return tryDecodeByteBuffer(rawOutput); |
| 254 | + } |
| 255 | + |
| 256 | + return decodeByteBuffer(rawOutput, charsetName); |
| 257 | + } |
| 258 | + |
| 259 | + private String tryDecodeByteBuffer(AtomicReference<ByteBuffer> rawOutput) |
| 260 | + throws CharacterCodingException, MalformedInputException { |
| 261 | + |
| 262 | + for (int i = 0; i < ACCEPTED_CHARSETS.length - 1; i++) { |
| 263 | + try { |
| 264 | + return decodeByteBuffer(rawOutput, ACCEPTED_CHARSETS[i]); |
| 265 | + } catch (MalformedInputException e) { |
| 266 | + continue; |
| 267 | + } catch (CharacterCodingException e) { |
| 268 | + continue; |
| 269 | + } |
| 270 | + } |
| 271 | + |
| 272 | + return decodeBody(rawOutput, ACCEPTED_CHARSETS[ACCEPTED_CHARSETS.length - 1]); |
| 273 | + } |
| 274 | + |
| 275 | + private String decodeByteBuffer(AtomicReference<ByteBuffer> rawOutput, String charsetName) |
| 276 | + throws CharacterCodingException, MalformedInputException { |
| 277 | + |
| 278 | + return createCharsetDecoder(charsetName).decode(rawOutput.get()).toString(); |
| 279 | + } |
| 280 | + |
234 | 281 | protected void returnResponseObject(HttpRequest request) throws HttpRequestException {
|
235 | 282 | try {
|
236 | 283 | JSONObject response = new JSONObject();
|
237 | 284 | int code = request.code();
|
238 |
| - String body = request.body(request.charset()); |
| 285 | + AtomicReference<ByteBuffer> rawOutputReference = new AtomicReference<ByteBuffer>(); |
239 | 286 |
|
| 287 | + request.body(rawOutputReference); |
240 | 288 | response.put("status", code);
|
241 | 289 | response.put("url", request.url().toString());
|
242 | 290 | this.addResponseHeaders(request, response);
|
243 | 291 |
|
244 | 292 | if (code >= 200 && code < 300) {
|
245 |
| - response.put("data", body); |
| 293 | + response.put("data", decodeBody(rawOutputReference, request.charset())); |
246 | 294 | this.getCallbackContext().success(response);
|
247 | 295 | } else {
|
248 |
| - response.put("error", body); |
| 296 | + response.put("error", decodeBody(rawOutputReference, request.charset())); |
249 | 297 | this.getCallbackContext().error(response);
|
250 | 298 | }
|
251 | 299 | } catch(JSONException e) {
|
252 | 300 | this.respondWithError("There was an error generating the response");
|
| 301 | + } catch(MalformedInputException e) { |
| 302 | + this.respondWithError("Could not decode response data due to malformed data"); |
| 303 | + } catch(CharacterCodingException e) { |
| 304 | + this.respondWithError("Could not decode response data due to invalid or unknown charset encoding"); |
253 | 305 | }
|
254 | 306 | }
|
255 | 307 |
|
|
0 commit comments