Javax Response adds method path when setting location header path in Status Created

We use Dropwizard / Jersey to create a web service. A resource has a path, and a method has a subpath. When you return the created response (201), the path of the method that we receive is added to the location that we provide. When you return the status "OK" with the location (as I know), everything is fine, and the location returns the same as we provided it.

How can we return a location that is not a subpath of our method location?

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

while going to "http: // localhost / foo / baz" (ok status) responds with the location "http: // localhost / wibble" 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(); } } 
+6
source share
3 answers

Happened to me on GlassFish (JavaEE6). I think this is a mistake, but I never managed to dig up the code before actually converting the URI ....

I found a workaround:

 public Response bar(@Context UriInfo info) { URI absoluteURI=info.getBaseUriBuilder().path("/wibble").build(); return Response.created(absoluteURI).build(); } 
+4
source

In case someone stumbles here about it; I burst into Jersey code to understand why this is happening. This should explain your problem and 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 that it would be nice to treat the location header differently if the response status code is 201. As Carlo noted, using absolute paths avoids this problem.
+7
source

In Jersey 2.x, the corresponding code was completely rewritten and moved to another location. Inside the org.glassfish.jersey.server.ServerRuntime class, the following method is called when writing response data:

  private static void ensureAbsolute(final URI location, final MultivaluedMap<String, Object> headers, final ContainerRequest request) { if (location == null || location.isAbsolute()) { return; } // according to RFC2616 (HTTP/1.1), this field can contain one single URI headers.putSingle(HttpHeaders.LOCATION, request.getBaseUri().resolve(location)); } 

As stated earlier, if an application does not set an absolute URI (a URI that starts with a scheme such as http: or ftp: for the Location header, Jersey will automatically add it with the query base URI.

It is strange that Jersey does not allow you to control or disable this behavior.

0
source

All Articles