restwebserveretagjavaxif-none-match

javax Request object not evaluating precondition for If-None-Match header


I am running a REST service in Wildfly and I am attempting to use the Request.evaluatePreconditions method to generate a 304 Not Modified response.

I am passing an eTag value in the request's If-None-Match header, but the evaluatePreconditions method is not generating the 304 response even when the EntityTag matches the value in the If-None-Match header.

Here is the code:

import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.inject.Inject;
import javax.persistence.PersistenceException;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.EntityTag
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;

import com.mycompany.DataClient;
import com.mycompany.ResponseData;

@Path ("entities")
@Stateless
@TransactionManagement (TransactionManagementType.BEAN)
public class RESTService
{
    @Inject
    private DataClient m_DataClient;

    @GET
    @Produces (MediaType.APPLICATION_JSON)
    public Response findAllEntities (@Context Request request)
    {
        Response.ResponseBuilder response = null;

        try
        {
            ResponseData responseData = m_DataClient.findAll ();

            EntityTag tag = new EntityTag (responseData.getETag ());

            response = request.evaluatePreconditions (tag);

            if (response == null)
            {
                response = Response.status (responseData.getStatusCode ()).entity (responseData.getEntities ()).tag (responseData.getETag ());
            }
        }
        catch (IllegalStateException | PersistenceException | InterruptedException | ExecutionException ex)
        {
            m_Logger.log (Level.SEVERE, "Find All Data Exception", ex);
            response = Response.serverError ();
        }

        return response.build ();
    }
}

Here's my request to the server:

curl -H "Accept:application/json" -H "If-None-Match:7056166173985" -H "Authorization:Bearer adsf" -k -v https://mycompany.com/entities

Here's the response header from the server:

< HTTP/1.1 200 OK
< ETag: "7056166173985"
< X-Powered-By: caffeine
< Access-Control-Allow-Credentials: true
< Content-Type: application/json
< Content-Length: 1227
< Date: Fri, 27 Oct 2017 02:00:39 GMT
< Via: 1.1 google
< Alt-Svc: clear
<

As you can see, the ETag value in the response header matches the value in the If-None-Match request header. Why am I not receiving a 304 Not Modified response?


Solution

  • I found the issue. The problem was in another part of my code that loads the eTag value into the responseData object. As a result, the responseData.getETag () method was returning a string that included the opening and closing double quotes. I was able to get things to work by changing

    EntityTag tag = new EntityTag (responseData.getETag ());
    

    to

    EntityTag tag = new EntityTag (responseData.getETag ().replaceAll ("^\"|\"$", ""));
    

    Specifically, I am pulling my data and the associated eTag from a remote server, and I am using the Apache HttpClient to retrieve them. The following code retrieves the eTag from the header:

    private String retrieveETag (HttpResponse response)
    {
        Header eTagHeader = response.getLastHeader ("etag");
    
        if (eTagHeader != null)
        {
            return eTagHeader.getValue ();
        }
    
        return null;
    }
    

    The raw eTag header is ETag: \"etagvalue\". I had expected eTagHeader.getValue () to return etagvalue, but instead it returns \"etagvalue\".