From 5382260f30be45d69d24ef23a3f5231eb6a5eeaf Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 22 Nov 2018 17:43:53 +0100 Subject: [PATCH] Client/ServerRequest defensively accesses internal attribute map Issue: SPR-17486 --- .../function/client/ClientRequest.java | 11 +-- .../function/server/ServerRequest.java | 94 +++++++++---------- 2 files changed, 47 insertions(+), 58 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientRequest.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientRequest.java index 50301b7710c..a43dab0008e 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientRequest.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientRequest.java @@ -76,13 +76,7 @@ public interface ClientRequest { * @return the attribute value */ default Optional attribute(String name) { - Map attributes = attributes(); - if (attributes.containsKey(name)) { - return Optional.of(attributes.get(name)); - } - else { - return Optional.empty(); - } + return Optional.ofNullable(attributes().get(name)); } /** @@ -91,8 +85,7 @@ public interface ClientRequest { Map attributes(); /** - * Writes this request to the given {@link ClientHttpRequest}. - * + * Write this request to the given {@link ClientHttpRequest}. * @param request the client http request to write to * @param strategies the strategies to use when writing * @return {@code Mono} to indicate when writing is complete diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java index e220a03c0f7..69fac023bc4 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java @@ -50,7 +50,8 @@ import org.springframework.web.util.UriBuilder; /** * Represents a server-side HTTP request, as handled by a {@code HandlerFunction}. - * Access to headers and body is offered by {@link Headers} and + * + *

Access to headers and body is offered by {@link Headers} and * {@link #body(BodyExtractor)}, respectively. * * @author Arjen Poutsma @@ -60,7 +61,7 @@ import org.springframework.web.util.UriBuilder; public interface ServerRequest { /** - * Return the HTTP method. + * Get the HTTP method. * @return the HTTP method as an HttpMethod enum value, or {@code null} * if not resolvable (e.g. in case of a non-standard HTTP method) */ @@ -70,18 +71,18 @@ public interface ServerRequest { } /** - * Return the name of the HTTP method. + * Get the name of the HTTP method. * @return the HTTP method as a String */ String methodName(); /** - * Return the request URI. + * Get the request URI. */ URI uri(); /** - * Return a {@code UriBuilderComponents} from the URI associated with this + * Get a {@code UriBuilderComponents} from the URI associated with this * {@code ServerRequest}, while also overlaying with values from the headers * "Forwarded" (RFC 7239), * or "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" if @@ -91,26 +92,26 @@ public interface ServerRequest { UriBuilder uriBuilder(); /** - * Return the request path. + * Get the request path. */ default String path() { return uri().getRawPath(); } /** - * Return the request path as {@code PathContainer}. + * Get the request path as a {@code PathContainer}. */ default PathContainer pathContainer() { return PathContainer.parsePath(path()); } /** - * Return the headers of this request. + * Get the headers of this request. */ Headers headers(); /** - * Return the cookies of this request. + * Get the cookies of this request. */ MultiValueMap cookies(); @@ -166,28 +167,22 @@ public interface ServerRequest { Flux bodyToFlux(ParameterizedTypeReference typeReference); /** - * Return the request attribute value if present. + * Get the request attribute value if present. * @param name the attribute name * @return the attribute value */ default Optional attribute(String name) { - Map attributes = attributes(); - if (attributes.containsKey(name)) { - return Optional.of(attributes.get(name)); - } - else { - return Optional.empty(); - } + return Optional.ofNullable(attributes().get(name)); } /** - * Return a mutable map of request attributes. + * Get a mutable map of request attributes. * @return the request attributes */ Map attributes(); /** - * Return the first query parameter with the given name, if present. + * Get the first query parameter with the given name, if present. * @param name the parameter name * @return the parameter value */ @@ -206,12 +201,12 @@ public interface ServerRequest { } /** - * Return all query parameters for this request. + * Get all query parameters for this request. */ MultiValueMap queryParams(); /** - * Return the path variable with the given name, if present. + * Get the path variable with the given name, if present. * @param name the variable name * @return the variable value * @throws IllegalArgumentException if there is no path variable with the given name @@ -227,38 +222,38 @@ public interface ServerRequest { } /** - * Return all path variables for this request. + * Get all path variables for this request. */ Map pathVariables(); /** - * Return the web session for this request. Always guaranteed to - * return an instance either matching to the session id requested by the - * client, or with a new session id either because the client did not - * specify one or because the underlying session had expired. Use of this - * method does not automatically create a session. + * Get the web session for this request. + *

Always guaranteed to return an instance either matching the session id + * requested by the client, or with a new session id either because the client + * did not specify one or because the underlying session had expired. + *

Use of this method does not automatically create a session. */ Mono session(); /** - * Return the authenticated user for the request, if any. + * Get the authenticated user for the request, if any. */ Mono principal(); /** - * Return the form data from the body of the request if the Content-Type is + * Get the form data from the body of the request if the Content-Type is * {@code "application/x-www-form-urlencoded"} or an empty map otherwise. *

Note: calling this method causes the request body to - * be read and parsed in full and the resulting {@code MultiValueMap} is + * be read and parsed in full, and the resulting {@code MultiValueMap} is * cached so that this method is safe to call more than once. */ Mono> formData(); /** - * Return the parts of a multipart request if the Content-Type is + * Get the parts of a multipart request if the Content-Type is * {@code "multipart/form-data"} or an empty map otherwise. *

Note: calling this method causes the request body to - * be read and parsed in full and the resulting {@code MultiValueMap} is + * be read and parsed in full, and the resulting {@code MultiValueMap} is * cached so that this method is safe to call more than once. */ Mono> multipartData(); @@ -285,59 +280,60 @@ public interface ServerRequest { interface Headers { /** - * Return the list of acceptable {@code MediaType media types}, - * as specified by the {@code Accept} header. - *

Returns an empty list when the acceptable media types are unspecified. + * Get the list of acceptable media types, as specified by the {@code Accept} + * header. + *

Returns an empty list if the acceptable media types are unspecified. */ List accept(); /** - * Return the list of acceptable {@code Charset charsets}, - * as specified by the {@code Accept-Charset} header. + * Get the list of acceptable charsets, as specified by the + * {@code Accept-Charset} header. */ List acceptCharset(); /** - * Return the list of acceptable {@code Locale.LanguageRange languages}, - * as specified by the {@code Accept-Language} header. + * Get the list of acceptable languages, as specified by the + * {@code Accept-Language} header. */ List acceptLanguage(); /** - * Return the length of the body in bytes, as specified by the + * Get the length of the body in bytes, as specified by the * {@code Content-Length} header. */ OptionalLong contentLength(); /** - * Return the {@code MediaType media type} of the body, as specified - * by the {@code Content-Type} header. + * Get the media type of the body, as specified by the + * {@code Content-Type} header. */ Optional contentType(); /** - * Return the value of the required {@code Host} header. - *

If the header value does not contain a port, the returned - * {@linkplain InetSocketAddress#getPort() port} will be {@code 0}. + * Get the value of the {@code Host} header, if available. + *

If the header value does not contain a port, the + * {@linkplain InetSocketAddress#getPort() port} in the returned address will + * be {@code 0}. */ @Nullable InetSocketAddress host(); /** - * Return the value of the {@code Range} header. + * Get the value of the {@code Range} header. *

Returns an empty list when the range is unknown. */ List range(); /** - * Return the header value(s), if any, for the header of the given name. - *

Return an empty list if no header values are found. + * Get the header value(s), if any, for the header of the given name. + *

Returns an empty list if no header values are found. * @param headerName the header name */ List header(String headerName); /** - * Return the headers as a {@link HttpHeaders} instance. + * Get the headers as an instance of {@link HttpHeaders}. */ HttpHeaders asHttpHeaders(); }