Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpClient: Determine empty entity in response

I'm wondering how to determine an empty http response. With empty http response I mean, that the http response will only have set some headers, but contains an empty http body.

For example: I do a HTTP POST to an webserver, but the webserver will only return an status code for my HTTP POST and nothing else.

The problem is, that I have written a little http framework on top of apache HttpClient to do auto json parsing etc. So the default use case of this framework is to make a request and parse the response. However if the response does not contain data, like mentioned in the example above, I will ensure that my framework skip json parsing.

So I do something like this:

HttpResponse response = httpClient.execute(uriRequest);
HttpEntity entity = response.getEntity();
if (entity != null){
    InputStream in = entity.getContent();
    // json parsing
}

However entity is always != null. And also the retrieved inputstream is != null. Is there a simple way to determine if the http body is empty or not?

The only way I see is that the server response contains the Content-Length header field set to 0. But not every server set this field.

Any suggestions?

like image 868
sockeqwe Avatar asked Jun 09 '13 15:06

sockeqwe


2 Answers

In HttpClient, getEntity() can return null. See the latest samples.

However, there's a difference between an empty entity, and no entity. Sounds like you've got an empty entity. (Sorry to be pedantic -- it's just that HTTP is pedantic. :) With respect to detecting empty entities, have you tried reading from the entity input stream? If the response is an empty entity, you should get an immediate EOF.

Do you need to determine if the entity is empty without reading any bytes from the entity body? Based on the code above, I don't think you do. If that's the case, you can just wrap the entity InputStream with a PushbackInputStream and check:

HttpResponse response = httpClient.execute(uriRequest);
HttpEntity entity = response.getEntity();
if(entity != null) {
    InputStream in = new PushbackInputStream(entity.getContent());
    try {
        int firstByte=in.read();
        if(firstByte != -1) {
            in.unread(firstByte);
            // json parsing
        }
        else {
            // empty
        }
    }
    finally {
        // Don't close so we can reuse the connection
        EntityUtils.consumeQuietly(entity);
        // Or, if you're sure you won't re-use the connection
        in.close();
    }
}

It's best not to read the entire response into memory just in case it's large. This solution will test for emptiness using constant memory (4 bytes :).

EDIT: <pedantry> In HTTP, if a request has no Content-Length header, then there should be a Transfer-Encoding: chunked header. If there is no Transfer-Encoding: chunked header either, then you should have no entity as opposed to an empty entity. </pedantry>

like image 144
sigpwned Avatar answered Sep 21 '22 00:09

sigpwned


I would suggest to use the class EntityUtils to get the response as String. If it returns the empty string, then the response is empty.

String resp = EntityUtils.toString(client.execute(uriRequest).getEntity())
if (resp == null || "".equals(resp)) {
    // no entity or empty entity
} else {
    // got something
    JSON.parse(resp);
}

The assumption here is that, for sake of code simplicity and manutenibility, you don't care to distinguish between empty entity and no entity, and that if there is a response, you need to read it anyway.

like image 45
namero999 Avatar answered Sep 17 '22 00:09

namero999