Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javax Response prepends method path when setting Location header path on Status Created

We're using Dropwizard / Jersey to build a web service. The resource has a path and the method has a sub-path. When returning response created (201) the path of the method we're getting is prepended to the location we provide. When returning status OK with a location (contrived I know), all is well, and the location is returned just as we provided it.

How can we return a location that is not a sub-path of the location of our method?

In the example below: a get to "http://localhost/foo/bar" (created status) responds with location of "http://localhost/foo/bar/wibble" (note the /foo/bar)

while a get to "http://localhost/foo/baz" (ok status) responds with location of "http://localhost/wibble" which is what we want.

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import java.net.URI;

@Path("/foo")
public class FooResource {

    @POST
    @Path("/bar")
    public Response bar() {

        URI uriOfCreatedResource = URI.create("/wibble");
        return Response.created(uriOfCreatedResource).build();
    }

    @POST
    @Path("/baz")
    public Response baz() {

        URI uriOfCreatedResource = URI.create("/wibble");
        return Response.ok().location(uriOfCreatedResource).build();
    }
}
like image 928
Andrew M Avatar asked Dec 04 '12 12:12

Andrew M


2 Answers

In case someone stumbles here wondering about this; I dug into Jersey's code to see why this happens. This should explain your problem & Carlo's workaround.

com.sun.jersey.spi.container.ContainerResponse contains this gem:

private void setHeaders(MultivaluedMap<String, Object> headers) {
    this.headers = headers;
    Object location = headers.getFirst(HttpHeaders.LOCATION);
    if (location != null) {
        if (location instanceof URI) {
            final URI locationUri = (URI)location;
            if (!locationUri.isAbsolute()) {
                final URI base = (statusType.getStatusCode() == Status.CREATED.getStatusCode())
                        ? request.getAbsolutePath() // WHY!?
                        : request.getBaseUri();
                location = UriBuilder.fromUri(base).
                        path(locationUri.getRawPath()).
                        replaceQuery(locationUri.getRawQuery()).
                        fragment(locationUri.getRawFragment()).
                        build();
            }
            headers.putSingle(HttpHeaders.LOCATION, location);
        }
    }
}

In other words: for some reason, someone decided it was a good idea to treat the location header differently if the response status code is 201. Like Carlo noticed, using absolute paths avoids this issue.

like image 115
henriks Avatar answered Sep 27 '22 23:09

henriks


Happened to me on GlassFish (JavaEE6). I think it's a bug, but I never managed to dig the code to the actual URI conversion....

I've found a workaround though:

public Response bar(@Context UriInfo info) {
   URI absoluteURI=info.getBaseUriBuilder().path("/wibble").build();
   return Response.created(absoluteURI).build();
}
like image 37
Carlo Pellegrini Avatar answered Sep 27 '22 22:09

Carlo Pellegrini