@@ -148,7 +148,10 @@ public class ServerRuntime {
148148
149149 private final boolean processResponseErrors ;
150150
151+ /** Do not resolve relative URIs in the {@code Location} header */
151152 private final boolean disableLocationHeaderRelativeUriResolution ;
153+ /** Resolve relative URIs according to RFC7231 (not JAX-RS 2.0 compliant */
154+ private final boolean rfc7231LocationHeaderRelativeUriResolution ;
152155
153156 /*package */ static final ExternalRequestScope <Object > NOOP_EXTERNAL_REQ_SCOPE = new ExternalRequestScope <Object >() {
154157
@@ -254,6 +257,10 @@ private ServerRuntime(final Stage<RequestProcessingContext> requestProcessingRoo
254257 this .disableLocationHeaderRelativeUriResolution = ServerProperties .getValue (configuration .getProperties (),
255258 ServerProperties .LOCATION_HEADER_RELATIVE_URI_RESOLUTION_DISABLED ,
256259 Boolean .FALSE , Boolean .class );
260+
261+ this .rfc7231LocationHeaderRelativeUriResolution = ServerProperties .getValue (configuration .getProperties (),
262+ ServerProperties .LOCATION_HEADER_RELATIVE_URI_RESOLUTION_RFC7231 ,
263+ Boolean .FALSE , Boolean .class );
257264 }
258265
259266 /**
@@ -302,7 +309,9 @@ public void run() {
302309 // set base URI into response builder thread-local variable
303310 // for later resolving of relative location URIs
304311 if (!disableLocationHeaderRelativeUriResolution ) {
305- OutboundJaxrsResponse .Builder .setBaseUri (request .getRequestUri ());
312+ final URI uriToUse =
313+ rfc7231LocationHeaderRelativeUriResolution ? request .getRequestUri () : request .getBaseUri ();
314+ OutboundJaxrsResponse .Builder .setBaseUri (uriToUse );
306315 }
307316
308317 final Ref <Endpoint > endpointRef = Refs .emptyRef ();
@@ -350,14 +359,17 @@ ScheduledExecutorService getBackgroundScheduler() {
350359 * @param location location URI; value of the HTTP {@value HttpHeaders#LOCATION} response header.
351360 * @param headers mutable map of response headers.
352361 * @param request container request.
362+ * @param incompatible if set to {@code true}, uri will be resolved against the request uri, not the base uri;
363+ * this is correct against RFC7231, but does violate the JAX-RS 2.0 specs
353364 */
354365 private static void ensureAbsolute (final URI location , final MultivaluedMap <String , Object > headers ,
355- final ContainerRequest request ) {
366+ final ContainerRequest request , final boolean incompatible ) {
356367 if (location == null || location .isAbsolute ()) {
357368 return ;
358369 }
359370 // according to RFC7231 (HTTP/1.1), this field can contain one single URI reference
360- headers .putSingle (HttpHeaders .LOCATION , request .getRequestUri ().resolve (location ));
371+ final URI uri = incompatible ? request .getRequestUri () : request .getBaseUri ();
372+ headers .putSingle (HttpHeaders .LOCATION , uri .resolve (location ));
361373 }
362374
363375 private static class AsyncResponderHolder implements Value <AsyncContext > {
@@ -466,7 +478,8 @@ public void process(final Throwable throwable) {
466478 try {
467479 response = convertResponse (exceptionResponse );
468480 if (!runtime .disableLocationHeaderRelativeUriResolution ) {
469- ensureAbsolute (response .getLocation (), response .getHeaders (), request );
481+ ensureAbsolute (response .getLocation (), response .getHeaders (), request ,
482+ runtime .rfc7231LocationHeaderRelativeUriResolution );
470483 }
471484 processingContext .monitoringEventBuilder ().setContainerResponse (response )
472485 .setResponseSuccessfullyMapped (true );
@@ -659,7 +672,8 @@ private ContainerResponse writeResponse(final ContainerResponse response) {
659672 final ContainerResponseWriter writer = request .getResponseWriter ();
660673
661674 if (!runtime .disableLocationHeaderRelativeUriResolution ) {
662- ServerRuntime .ensureAbsolute (response .getLocation (), response .getHeaders (), response .getRequestContext ());
675+ ServerRuntime .ensureAbsolute (response .getLocation (), response .getHeaders (), response .getRequestContext (),
676+ runtime .rfc7231LocationHeaderRelativeUriResolution );
663677 }
664678
665679 if (!response .hasEntity ()) {
@@ -682,7 +696,7 @@ private ContainerResponse writeResponse(final ContainerResponse response) {
682696 public OutputStream getOutputStream (final int contentLength ) throws IOException {
683697 if (!runtime .disableLocationHeaderRelativeUriResolution ) {
684698 ServerRuntime .ensureAbsolute (response .getLocation (), response .getHeaders (),
685- response .getRequestContext ());
699+ response .getRequestContext (), runtime . rfc7231LocationHeaderRelativeUriResolution );
686700 }
687701 final OutputStream outputStream = writer .writeResponseStatusAndHeaders (contentLength , response );
688702 return isHead ? null : outputStream ;
@@ -914,7 +928,8 @@ public void run() {
914928 (response instanceof Response ) ? (Response ) response : Response .ok (response ).build ();
915929 if (!responder .runtime .disableLocationHeaderRelativeUriResolution ) {
916930 ServerRuntime .ensureAbsolute (jaxrsResponse .getLocation (), jaxrsResponse .getHeaders (),
917- responder .processingContext .request ());
931+ responder .processingContext .request (),
932+ responder .runtime .rfc7231LocationHeaderRelativeUriResolution );
918933 }
919934 responder .process (new ContainerResponse (responder .processingContext .request (), jaxrsResponse ));
920935 } catch (final Throwable t ) {
0 commit comments