Improve docs on forwarded headers

Issue: SPR-15612
This commit is contained in:
Rossen Stoyanchev 2017-06-01 22:36:12 -04:00
parent 895fa2ea7b
commit 4d52590964
4 changed files with 126 additions and 12 deletions

View File

@ -275,7 +275,7 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
/**
* Create a new {@code UriComponents} object from the URI associated with
* the given HttpRequest while also overlaying with values from the headers
* "Forwarded" (<a href="http://tools.ietf.org/html/rfc7239">RFC 7239</a>,
* "Forwarded" (<a href="http://tools.ietf.org/html/rfc7239">RFC 7239</a>),
* or "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" if
* "Forwarded" is not found.
* @param request the source request

View File

@ -70,18 +70,28 @@ import org.springframework.web.util.UriComponentsBuilder;
/**
* Creates instances of {@link org.springframework.web.util.UriComponentsBuilder}
* by pointing to Spring MVC controllers and {@code @RequestMapping} methods.
* by pointing to {@code @RequestMapping} methods on Spring MVC controllers.
*
* <p>The static {@code fromXxx(...)} methods prepare links relative to the
* current request as determined by a call to
* <p>There are several groups of methods:
* <ul>
* <li>Static {@code fromXxx(...)} methods to prepare links using information
* from the current request as determined by a call to
* {@link org.springframework.web.servlet.support.ServletUriComponentsBuilder#fromCurrentServletMapping()}.
* <li>Static {@code fromXxx(UriComponentsBuilder,...)} methods can be given
* a baseUrl when operating outside the context of a request.
* <li>Instance-based {@code withXxx(...)} methods where an instance of
* MvcUriComponentsBuilder is created with a baseUrl via
* {@link #relativeTo(org.springframework.web.util.UriComponentsBuilder)}.
* </ul>
*
* <p>The static {@code fromXxx(UriComponentsBuilder,...)} methods can be given
* the baseUrl when operating outside the context of a request.
*
* <p>You can also create an MvcUriComponentsBuilder instance with a baseUrl
* via {@link #relativeTo(org.springframework.web.util.UriComponentsBuilder)}
* and then use the non-static {@code withXxx(...)} method variants.
* <p><strong>Note:</strong> This class extracts and uses values from the headers
* "Forwarded" (<a href="http://tools.ietf.org/html/rfc7239">RFC 7239</a>),
* or "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" if
* "Forwarded" is not found, in order to reflect the client-originated protocol
* and address. As an alternative consider using the
* {@link org.springframework.web.filter.ForwardedHeaderFilter} to have such
* headers extracted once and removed, or removed only (without being used).
* See the reference for further information including security considerations.
*
* @author Oliver Gierke
* @author Rossen Stoyanchev
@ -142,6 +152,8 @@ public class MvcUriComponentsBuilder {
* Create a {@link UriComponentsBuilder} from the mapping of a controller class
* and current request information including Servlet mapping. If the controller
* contains multiple mappings, only the first one is used.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @param controllerType the controller to build a URI for
* @return a UriComponentsBuilder instance (never {@code null})
*/
@ -154,6 +166,8 @@ public class MvcUriComponentsBuilder {
* {@code UriComponentsBuilder} representing the base URL. This is useful
* when using MvcUriComponentsBuilder outside the context of processing a
* request or to apply a custom baseUrl not matching the current request.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @param builder the builder for the base URL; the builder will be cloned
* and therefore not modified and may be re-used for further calls.
* @param controllerType the controller to build a URI for
@ -171,6 +185,8 @@ public class MvcUriComponentsBuilder {
* Create a {@link UriComponentsBuilder} from the mapping of a controller
* method and an array of method argument values. This method delegates
* to {@link #fromMethod(Class, Method, Object...)}.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @param controllerType the controller
* @param methodName the method name
* @param args the argument values
@ -190,6 +206,8 @@ public class MvcUriComponentsBuilder {
* accepts a {@code UriComponentsBuilder} representing the base URL. This is
* useful when using MvcUriComponentsBuilder outside the context of processing
* a request or to apply a custom baseUrl not matching the current request.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @param builder the builder for the base URL; the builder will be cloned
* and therefore not modified and may be re-used for further calls.
* @param controllerType the controller
@ -237,6 +255,10 @@ public class MvcUriComponentsBuilder {
* controller.getAddressesForCountry("US")
* builder = MvcUriComponentsBuilder.fromMethodCall(controller);
* </pre>
*
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
*
* @param info either the value returned from a "mock" controller
* invocation or the "mock" controller itself after an invocation
* @return a UriComponents instance
@ -255,6 +277,8 @@ public class MvcUriComponentsBuilder {
* {@code UriComponentsBuilder} representing the base URL. This is useful
* when using MvcUriComponentsBuilder outside the context of processing a
* request or to apply a custom baseUrl not matching the current request.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @param builder the builder for the base URL; the builder will be cloned
* and therefore not modified and may be re-used for further calls.
* @param info either the value returned from a "mock" controller
@ -305,6 +329,10 @@ public class MvcUriComponentsBuilder {
* </pre>
* <p>Note that it's not necessary to specify all arguments. Only the ones
* required to prepare the URL, mainly {@code @RequestParam} and {@code @PathVariable}).
*
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
*
* @param mappingName the mapping name
* @return a builder to prepare the URI String
* @throws IllegalArgumentException if the mapping name is not found or
@ -320,6 +348,8 @@ public class MvcUriComponentsBuilder {
* {@code UriComponentsBuilder} representing the base URL. This is useful
* when using MvcUriComponentsBuilder outside the context of processing a
* request or to apply a custom baseUrl not matching the current request.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @param builder the builder for the base URL; the builder will be cloned
* and therefore not modified and may be re-used for further calls.
* @param name the mapping name
@ -352,6 +382,8 @@ public class MvcUriComponentsBuilder {
* {@link org.springframework.web.method.support.UriComponentsContributor
* UriComponentsContributor}) while remaining argument values are ignored and
* can be {@code null}.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @param controllerType the controller type
* @param method the controller method
* @param args argument values for the controller method
@ -368,6 +400,8 @@ public class MvcUriComponentsBuilder {
* This is useful when using MvcUriComponentsBuilder outside the context of
* processing a request or to apply a custom baseUrl not matching the
* current request.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @param baseUrl the builder for the base URL; the builder will be cloned
* and therefore not modified and may be re-used for further calls.
* @param controllerType the controller type
@ -549,6 +583,9 @@ public class MvcUriComponentsBuilder {
* <pre class="code">
* MvcUriComponentsBuilder.fromMethodCall(on(FooController.class).getFoo(1)).build();
* </pre>
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
*
* @param controllerType the target controller
*/
public static <T> T on(Class<T> controllerType) {
@ -571,6 +608,8 @@ public class MvcUriComponentsBuilder {
* fooController.saveFoo(2, null);
* builder = MvcUriComponentsBuilder.fromMethodCall(fooController);
* </pre>
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @param controllerType the target controller
*/
public static <T> T controller(Class<T> controllerType) {
@ -626,6 +665,8 @@ public class MvcUriComponentsBuilder {
/**
* An alternative to {@link #fromController(Class)} for use with an instance
* of this class created via a call to {@link #relativeTo}.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @since 4.2
*/
public UriComponentsBuilder withController(Class<?> controllerType) {
@ -635,6 +676,8 @@ public class MvcUriComponentsBuilder {
/**
* An alternative to {@link #fromMethodName(Class, String, Object...)}} for
* use with an instance of this class created via {@link #relativeTo}.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @since 4.2
*/
public UriComponentsBuilder withMethodName(Class<?> controllerType, String methodName, Object... args) {
@ -644,6 +687,8 @@ public class MvcUriComponentsBuilder {
/**
* An alternative to {@link #fromMethodCall(Object)} for use with an instance
* of this class created via {@link #relativeTo}.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @since 4.2
*/
public UriComponentsBuilder withMethodCall(Object invocationInfo) {
@ -653,6 +698,8 @@ public class MvcUriComponentsBuilder {
/**
* An alternative to {@link #fromMappingName(String)} for use with an instance
* of this class created via {@link #relativeTo}.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @since 4.2
*/
public MethodArgumentBuilder withMappingName(String mappingName) {
@ -662,6 +709,8 @@ public class MvcUriComponentsBuilder {
/**
* An alternative to {@link #fromMethod(Class, Method, Object...)}
* for use with an instance of this class created via {@link #relativeTo}.
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
* @since 4.2
*/
public UriComponentsBuilder withMethod(Class<?> controllerType, Method method, Object... args) {

View File

@ -17,7 +17,6 @@
package org.springframework.web.servlet.support;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.HttpRequest;
@ -34,7 +33,17 @@ import org.springframework.web.util.UriUtils;
import org.springframework.web.util.UrlPathHelper;
/**
* A UriComponentsBuilder that extracts information from the HttpServletRequest.
* UriComponentsBuilder with additional static factory methods to create links
* based on the current HttpServletRequest.
*
* <p><strong>Note:</strong> This class extracts and uses values from the headers
* "Forwarded" (<a href="http://tools.ietf.org/html/rfc7239">RFC 7239</a>),
* or "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" if
* "Forwarded" is not found, in order to reflect the client-originated protocol
* and address. As an alternative consider using the
* {@link org.springframework.web.filter.ForwardedHeaderFilter} to have such
* headers extracted once and removed, or removed only (without being used).
* See the reference for further information including security considerations.
*
* @author Rossen Stoyanchev
* @since 3.1
@ -71,6 +80,9 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder {
/**
* Prepare a builder from the host, port, scheme, and context path of the
* given HttpServletRequest.
*
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
*/
public static ServletUriComponentsBuilder fromContextPath(HttpServletRequest request) {
ServletUriComponentsBuilder builder = initFromRequest(request);
@ -85,6 +97,9 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder {
* will end with "/main". If the servlet is mapped otherwise, e.g.
* {@code "/"} or {@code "*.do"}, the result will be the same as
* if calling {@link #fromContextPath(HttpServletRequest)}.
*
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
*/
public static ServletUriComponentsBuilder fromServletMapping(HttpServletRequest request) {
ServletUriComponentsBuilder builder = fromContextPath(request);
@ -97,6 +112,9 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder {
/**
* Prepare a builder from the host, port, scheme, and path (but not the query)
* of the HttpServletRequest.
*
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
*/
public static ServletUriComponentsBuilder fromRequestUri(HttpServletRequest request) {
ServletUriComponentsBuilder builder = initFromRequest(request);
@ -107,6 +125,9 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder {
/**
* Prepare a builder by copying the scheme, host, port, path, and
* query string of an HttpServletRequest.
*
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
*/
public static ServletUriComponentsBuilder fromRequest(HttpServletRequest request) {
ServletUriComponentsBuilder builder = initFromRequest(request);
@ -155,6 +176,9 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder {
/**
* Same as {@link #fromContextPath(HttpServletRequest)} except the
* request is obtained through {@link RequestContextHolder}.
*
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
*/
public static ServletUriComponentsBuilder fromCurrentContextPath() {
return fromContextPath(getCurrentRequest());
@ -163,6 +187,9 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder {
/**
* Same as {@link #fromServletMapping(HttpServletRequest)} except the
* request is obtained through {@link RequestContextHolder}.
*
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
*/
public static ServletUriComponentsBuilder fromCurrentServletMapping() {
return fromServletMapping(getCurrentRequest());
@ -171,6 +198,9 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder {
/**
* Same as {@link #fromRequestUri(HttpServletRequest)} except the
* request is obtained through {@link RequestContextHolder}.
*
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
*/
public static ServletUriComponentsBuilder fromCurrentRequestUri() {
return fromRequestUri(getCurrentRequest());
@ -179,6 +209,9 @@ public class ServletUriComponentsBuilder extends UriComponentsBuilder {
/**
* Same as {@link #fromRequest(HttpServletRequest)} except the
* request is obtained through {@link RequestContextHolder}.
*
* <p><strong>Note:</strong> This method extracts values from "Forwarded"
* and "X-Forwarded-*" headers if found. See class-level docs.
*/
public static ServletUriComponentsBuilder fromCurrentRequest() {
return fromRequest(getCurrentRequest());

View File

@ -3436,6 +3436,38 @@ with a base URL and then use the instance-based "withXxx" methods. For example:
----
[[mvc-links-to-controllers-forwarded-headers]]
=== Working with "Forwarded" and "X-Forwarded-*" Headers
As a request goes through proxies such as load balancers the host, port, and
scheme may change presenting a challenge for applications that need to create links
to resources since the links should reflect the host, port, and scheme of the
original request as seen from a client perspective.
https://tools.ietf.org/html/rfc7239[RFC 7239] defines the "Forwarded" HTTP header
for proxies to use to provide information about the original request. There are also
other non-standard headers in use such as "X-Forwarded-Host", "X-Forwarded-Port",
and "X-Forwarded-Proto".
Both `ServletUriComponentsBuilder` and `MvcUriComponentsBuilder` detect, extract, and use
information from the "Forwarded" header, or from "X-Forwarded-Host", "X-Forwarded-Port",
and "X-Forwarded-Proto" if "Forwarded" is not present, so that the resulting links reflect
the original request.
The `ForwardedHeaderFilter` provides an alternative to do the same once and globally for
the entire application. The filter wraps the request in order to overlay host, port, and
scheme information and also "hides" any forwarded headers for subsequent processing.
Note that there are security considerations when using forwarded headers as explained
in Section 8 of RFC 7239. At the application level it is difficult to determine whether
forwarded headers can be trusted or not. This is why the network upstream should be
configured correctly to filter out untrusted forwarded headers from the outside.
Applications that don't have a proxy and don't need to use forwarded headers can
configure the `ForwardedHeaderFilter` to remove and ignore such headers.
[[mvc-links-to-controllers-from-views]]
=== Building URIs to Controllers and methods from views