Skip to content

Commit a49bcac

Browse files
author
Sefa Ilkimen
committed
Android: support guessing charset when header value is not set
1 parent 2f01d48 commit a49bcac

File tree

2 files changed

+68
-9
lines changed

2 files changed

+68
-9
lines changed

src/android/com/github/kevinsawicki/http/HttpRequest.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1945,16 +1945,24 @@ public String body() throws HttpRequestException {
19451945
}
19461946

19471947
/**
1948-
* Get the response body as a {@link String} and set it as the value of the
1948+
* Get the response body as ByteBuffer and set it as the value of the
19491949
* given reference.
19501950
*
19511951
* @param output
19521952
* @return this request
19531953
* @throws HttpRequestException
19541954
*/
1955-
public HttpRequest body(final AtomicReference<String> output) throws HttpRequestException {
1956-
output.set(body());
1957-
return this;
1955+
public HttpRequest body(final AtomicReference<ByteBuffer> output) throws HttpRequestException {
1956+
final ByteArrayOutputStream outputStream = byteStream();
1957+
1958+
try {
1959+
copy(buffer(), outputStream);
1960+
output.set(ByteBuffer.wrap(outputStream.toByteArray()));
1961+
1962+
return this;
1963+
} catch (IOException e) {
1964+
throw new HttpRequestException(e);
1965+
}
19581966
}
19591967

19601968
/**
@@ -1971,7 +1979,6 @@ public HttpRequest body(final AtomicReference<String> output, final String chars
19711979
return this;
19721980
}
19731981

1974-
19751982
/**
19761983
* Is the response body empty?
19771984
*

src/android/com/synconset/cordovahttp/CordovaHttp.java

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,22 @@
1212
import java.net.SocketTimeoutException;
1313
import java.net.UnknownHostException;
1414

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+
1523
import javax.net.ssl.SSLHandshakeException;
1624

1725
import java.util.ArrayList;
1826
import java.util.HashMap;
1927
import java.util.List;
2028
import java.util.Map;
2129
import java.util.concurrent.atomic.AtomicBoolean;
30+
import java.util.concurrent.atomic.AtomicReference;
2231
import java.util.Iterator;
2332

2433
import android.text.TextUtils;
@@ -28,7 +37,7 @@
2837

2938
abstract class CordovaHttp {
3039
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 };
3241

3342
private static AtomicBoolean sslPinning = new AtomicBoolean(false);
3443
private static AtomicBoolean acceptAllCerts = new AtomicBoolean(false);
@@ -231,25 +240,68 @@ protected void prepareRequest(HttpRequest request) throws HttpRequestException,
231240
request.uncompress(true);
232241
}
233242

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+
234281
protected void returnResponseObject(HttpRequest request) throws HttpRequestException {
235282
try {
236283
JSONObject response = new JSONObject();
237284
int code = request.code();
238-
String body = request.body(request.charset());
285+
AtomicReference<ByteBuffer> rawOutputReference = new AtomicReference<ByteBuffer>();
239286

287+
request.body(rawOutputReference);
240288
response.put("status", code);
241289
response.put("url", request.url().toString());
242290
this.addResponseHeaders(request, response);
243291

244292
if (code >= 200 && code < 300) {
245-
response.put("data", body);
293+
response.put("data", decodeBody(rawOutputReference, request.charset()));
246294
this.getCallbackContext().success(response);
247295
} else {
248-
response.put("error", body);
296+
response.put("error", decodeBody(rawOutputReference, request.charset()));
249297
this.getCallbackContext().error(response);
250298
}
251299
} catch(JSONException e) {
252300
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");
253305
}
254306
}
255307

0 commit comments

Comments
 (0)