4

I cannot figure out why my code is giving me garbage data when I read the Http Response entity. This is only happening when I issue a request to one specific URL with data that causes a 400 response. My code attempts to read the response entity, but as you can see below it is garbage.

Here is a simplified test case:

import org.junit.Test;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Map;

public class Sandbox {
    @Test
    public void jaguarTestCase() {
        Client client = ClientBuilder.newClient();

        WebTarget target = client.target("http://www.jaguarusa.com/owners/vin-recall.html?view=vinRecallQuery&vin=xxxxxxxxxxxxxxxxx");
        Invocation.Builder builder = target.request();
        Response response = builder.get(Response.class);

        System.out.println("Response Code:");
        System.out.println("\t" + response.getStatus() + " - " + response.getStatusInfo().getReasonPhrase());

        System.out.println("\nResponse Headers:");
        for (Map.Entry<String, List<String>> entry : response.getStringHeaders().entrySet()) {
            System.out.print("\t" + entry.getKey() + ": ");
            for (String value : entry.getValue()) {
                System.out.println(value);
            }
        }

        String responseEntity = response.readEntity(String.class);
        System.out.println("\nResponse Entity: ");
        System.out.println(responseEntity);
    }
}

And the output from that testcase:

Response Code:
    400 - Bad Request

Response Headers:
    X-Frame-Options: SAMEORIGIN
    Cache-Control: no-cache, no-store, must-revalidate
    Server: Apache-Coyote/1.1
    Connection: keep-alive
    Content-Encoding: gzip
    Vary: Accept-Encoding
    Content-Length: 135
    Date: Tue, 08 Nov 2016 00:03:23 GMT
    Content-Language: en-US
    Content-Type: application/json;charset=UTF-8

Response Entity: 
�       \�1
�@E��:H
���B��C2����X�wנ��z�{%1�vw��:ga�����4$ ������k�Q�-i�����y��T��!f��� c�  ��iK-��?z�  ���dW��  

This is what the entity body is supposed to be (paste the URL in any browser and see for yourself):

{
    "errorMessage" : "Please check your details and try again.",
    "error" : 400,
    "errorTitle" : "Sorry, that is not a valid VIN.",
    "vin" : "XXXXXXXXXXXXXXXXX"
}

I am using the JDK version 1.8.0_102. I think the problem is happening when the response entity is parsed because the reported content-length of 135 is the correct value, confirmed by running this request in a Chrome browser debug window.

The Content-Type response header shows charset=UTF-8, which is what my JVM is running as. What gives? I'm completely stumped after working on this all afternoon.

Joe Ernst
  • 508
  • 6
  • 18
  • 1
    `Content-Encoding: gzip` ? – Scary Wombat Nov 08 '16 at 00:21
  • Bingo! I thought I had ruled that out because I was not sending an Accept-Encoding header of gzip. When I issue a request that returns a 200 response, it is not gzipped. I guess there is a bug on the server side that ignores the Accept-Encoding request header if the response is a 400. – Joe Ernst Nov 08 '16 at 00:52
  • If you add this as an answer instead of a comment I'll accept it as the solution. – Joe Ernst Nov 08 '16 at 17:18

2 Answers2

3

If you inspect your response headers, you will notice

Content-Encoding: gzip

The garbled text is actually zipped.

Scary Wombat
  • 44,617
  • 6
  • 35
  • 64
1

You can uncompress that response.

WebTarget target = ...
target.register(GZipEncoder.class);

After this change, the readEntity thing you are doing should work fine.

This works in Jersey 2.26.

For earlier versions, the solutions are slightly different. Refer to https://stackoverflow.com/a/7574663/2695332

Vikas
  • 1,900
  • 1
  • 19
  • 20