Search code examples
javaandroidencryptionaesretrofit2

Retrofit2 interceptor converts special character to Question mark in Android


Special characters such as (“ ”,') gets converted into ? while applying interceptor in retrofit2.While getting response from retrofit2 , i am getting special characters but the interceptor changes the special character to ? and displays ? instead of special characters

Adding retrofit in Interceptor:

 CustomRequestInterceptor requestInterceptor = newCustomRequestInterceptor();
 HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
 logging.setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY : 
 HttpLoggingInterceptor.Level.NONE);
 OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
 httpClient.addInterceptor(requestInterceptor);
 httpClient.addInterceptor(logging);

Interceptor class(CustomRequestInterceptor.java) for retrofit2:

public class CustomRequestInterceptor implements Interceptor {

    private static String newToken;
    private String bodyString;

    private final String TAG = getClass().getSimpleName();


    @Override
    public Response intercept(Chain chain) throws IOException {


        String token = "";
        Request request = chain.request();
        RequestBody oldBody = request.body();

        Buffer buffer = new Buffer();
        oldBody.writeTo(buffer);

        String strOldBody = buffer.readUtf8();
        Log.i(TAG, "original req " + strOldBody);
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        JSONObject jsonObject = new JSONObject();
        String decodedStr = decoder(strOldBody.replace("data=", ""));
        try {

            if (decodedStr != null && decodedStr.equalsIgnoreCase("")) {
                token = getRandomNumber();
                jsonObject.put("auth_token", token);
            } else {
                jsonObject = new JSONObject(decodedStr);
                token = getRandomNumber();
                jsonObject.put("auth_token", token);
            }

        } catch (Exception e) {
            Log.e(AppConstants.TAG, "Exception", e);
        }

        Log.i(AppConstants.TAG, "Request JSONObject " + jsonObject.toString());
        String strNewBody = "data=" + URLEncoder.encode(Encryption.encryptString(jsonObject.toString()));


        Log.i(TAG, "strNewBody " + strNewBody);
        RequestBody body = RequestBody.create(mediaType, strNewBody);

        Log.i(TAG, "content type is " + body.contentType().toString());
        Log.i(TAG, "content length is " + String.valueOf(body.contentLength()));
        Log.i(TAG, "method is " + request.method());

        request = request.newBuilder().header("Content-Type", body.contentType().toString())
                .header("Content-Length", String.valueOf(body.contentLength()))
                .method(request.method(), body).build();


        Response response = chain.proceed(request);
        String responseString = new String(response.body().bytes());
        Log.i(TAG, "Response: " + responseString);
        String newResponseString = Encryption.decryptString(responseString);
        Log.i(TAG, "Response edited: " + URLDecoder.decode(newResponseString));
        JSONObject res_JsonObject = new JSONObject();
        if (newResponseString.startsWith("{")) {
            try {
                res_JsonObject = new JSONObject(newResponseString);
                String response_token = res_JsonObject.getString("auth_token");
                if (response_token.equalsIgnoreCase("" + token)) {

                } else {
                    res_JsonObject.put("status", false);
                    res_JsonObject.put("message", "Authentication Failed");
                    Toast.makeText(new AppController().getApplicationContext(), "Authentication Failed", Toast.LENGTH_LONG).show();
                }

            } catch (Exception e) {
                Log.e(AppConstants.TAG, "Exception", e);
            }
        }

        byte[] ptext = res_JsonObject.toString().getBytes(ISO_8859_1);
        String value = new String(ptext, UTF_16);

        return response.newBuilder()
                .body(ResponseBody.create(response.body().contentType(), value))
                .build();
    }

    public String decoder(String encodedStr) {
        try {
            return URLDecoder.decode(encodedStr);

        } catch (Exception e) {

            Log.e(AppConstants.TAG, "Exception", e);
            return encodedStr;
        }
    }
}

Expected output:

{
  "comment": "“hello”"
}

Actual output:

{
  "comment": "?hello?"
}

Solution

  • The problem is in the return statement of intercept method, when we call ResponseBody.create(), the responsebody class converts data to UTF-8 format and UTF-8 does not support characters like (“,”) so it gives us "?" sign because we have given response.body().contentType(), so it converts to UTF-8 which is default. The solution is to not to pass response.body().contentType() to create() and give our own contentType. Here is the updated class.

    public class CustomRequestInterceptor implements Interceptor {
    
        private static String newToken;
        private String bodyString;
    
        private final String TAG = getClass().getSimpleName();
    
    
        @Override
        public Response intercept(Chain chain) throws IOException {
    
    
            String token = "";
            Request request = chain.request();
            RequestBody oldBody = request.body();
    
            Buffer buffer = new Buffer();
            oldBody.writeTo(buffer);
    
            String strOldBody = buffer.readUtf8();
            Log.i(TAG, "original req " + strOldBody);
            MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
            JSONObject jsonObject = new JSONObject();
            String decodedStr = decoder(strOldBody.replace("data=", ""));
            try {
    
                if (decodedStr != null && decodedStr.equalsIgnoreCase("")) {
                    token = getRandomNumber();
                    jsonObject.put("auth_token", token);
                } else {
                    jsonObject = new JSONObject(decodedStr);
                    token = getRandomNumber();
                    jsonObject.put("auth_token", token);
                }
    
            } catch (Exception e) {
                Log.e(AppConstants.TAG, "Exception", e);
            }
    
            Log.i(AppConstants.TAG, "Request JSONObject " + jsonObject.toString());
            String strNewBody = "data=" + URLEncoder.encode(Encryption.encryptString(jsonObject.toString()));
    
    
            Log.i(TAG, "strNewBody " + strNewBody);
            RequestBody body = RequestBody.create(mediaType, strNewBody);
    
            Log.i(TAG, "content type is " + body.contentType().toString());
            Log.i(TAG, "content length is " + String.valueOf(body.contentLength()));
            Log.i(TAG, "method is " + request.method());
    
            request = request.newBuilder().header("Content-Type", body.contentType().toString())
                    .header("Content-Length", String.valueOf(body.contentLength()))
                    .method(request.method(), body).build();
    
    
            Response response = chain.proceed(request);
            String responseString = new String(response.body().bytes());
            Log.i(TAG, "Response: " + responseString);
            String newResponseString = Encryption.decryptString(responseString);
            JSONObject res_JsonObject = new JSONObject();
            if (newResponseString.startsWith("{")) {
                try {
                    res_JsonObject = new JSONObject(newResponseString);
                    String response_token = res_JsonObject.getString("auth_token");
                    if (response_token.equalsIgnoreCase("" + token)) {
    
                    } else {
                        res_JsonObject.put("status", false);
                        res_JsonObject.put("message", "Authentication Failed");
                        Toast.makeText(new AppController().getApplicationContext(), "Authentication Failed", Toast.LENGTH_LONG).show();
                    }
    
                } catch (Exception e) {
                    Log.e(AppConstants.TAG, "Exception", e);
                }
            }
    
            MediaType contentType = MediaType.parse(response.body().contentType() + "; charset=utf-32");
    
            return response.newBuilder()
                    .body(ResponseBody.create(contentType, newResponseString.getBytes()))
                    .build();
        }
    
        public String decoder(String encodedStr) {
            try {
                return URLDecoder.decode(encodedStr);
    
            } catch (Exception e) {
    
                Log.e(AppConstants.TAG, "Exception", e);
                return encodedStr;
            }
        }
    
    }