Greta
Greta

Reputation: 328

How does Jersey determine the base URI of an application?

I have a java application running in a tomcat. In one endpoint of the application I want to return a HTTP-response of type See-Other.

@GET
@Path("logout")
@Produces(MediaType.TEXT_HTML)
public Response logOut(@Context HttpServletRequest request) throws URISyntaxException {
    // logout logic omitted
    Response.ResponseBuilder response = Response.seeOther(new URI("../jsp/login.jsp"));
    return response.build();
}

When I test this on my local machine everything works fine. On the production system however jersey seems to be unable to resolve the correct hostname from the relative path "../jsp/login.jsp". Although the host is called myhost the relative path is resolved as http://localhost:7080/myapplication/jsp/login.jsp.

new URI("../jsp/login.jsp") returns an Object where all fields are null and only path="../jsp/login.jsp". For this reason the root of the behavior must be in the Response class. I checked the documentation and figured that Response.seeOther makes a call to the Response.location method. The documentation states that

If a relative URI is supplied it will be converted into an absolute URI by resolving it relative to the base URI of the application

Does anyone know how Jersey determines the base URI of the application? Is there some config file in the tomcat or an environment variable I set wrong?

Upvotes: 1

Views: 572

Answers (1)

Piotr P. Karwasz
Piotr P. Karwasz

Reputation: 16045

The base URI of the application is computed using the properties of the HttpServletRequest object and is of the form:

<scheme>://<serverName>:<serverPort>/<contextPath><servletPath>/

The <serverName> and <serverPort> are usually supplied by the HTTP client, while the rest is fixed by Tomcat's or your application's configuration:

  • <scheme> is configured using the homonymous attribute of a <Connector> (cf. Tomcat's documentation) or can be set by the RemoteIpValve (cf. documentation),
  • <serverName> is supplied by the HTTP client, but can be overridden using the proxyName attribute of a connector,
  • <serverPort> is supplied by the HTTP client, but can be overridden using the proxyPort attribute of a connector or by the RemoteIpValve,
  • <contextPath> depends on how you deploy your application (e.g. it depends on the name of the WAR file in the webapps directory),
  • <servletPath> is configured in the web.xml descriptor or through the @ApplicationPath annotation.

What probably happens in your production environment is that Tomcat is behind a reverse proxy. To configure the base URI correctly in such a situation you have two choices:

  1. Statically configure the correct values of scheme, secure, proxyName and proxyPort on your <Connector>,
  2. Use the RemoteIpValve and configure the proxy server to send the original Host header and add the X-Forwarded-For and X-Forwarded-Proto headers.

If your proxy forwards different kinds of requests to Tomcat (e.g. both HTTP and HTTPS requests), the RemoteIpValve is your only choice.

Remark: The base URI can also be based on the request URI if you set the ServerProperties.LOCATION_HEADER_RELATIVE_URI_RESOLUTION_RFC7231 property to true: cf. this question.

Upvotes: 4

Related Questions