Cache ServerHttpRequest::getMethod in AbstractServerHttpRequest

This commit ensures that the HttpMethod, exposed through
ServerHttpRequest::getMethod, is cached in AbstractServerHttpRequest so
that potentially expensive HTTP method lookups are only done once.

Closes gh-30139
This commit is contained in:
Arjen Poutsma 2023-03-21 11:29:32 +01:00
parent c27a5687dc
commit 37a4e84450
8 changed files with 62 additions and 62 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -54,8 +54,6 @@ import org.springframework.web.util.UriComponentsBuilder;
*/
public final class MockServerHttpRequest extends AbstractServerHttpRequest {
private final HttpMethod httpMethod;
private final MultiValueMap<String, HttpCookie> cookies;
@Nullable
@ -74,8 +72,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
@Nullable InetSocketAddress localAddress, @Nullable InetSocketAddress remoteAddress,
@Nullable SslInfo sslInfo, Publisher<? extends DataBuffer> body) {
super(uri, contextPath, headers);
this.httpMethod = httpMethod;
super(httpMethod, uri, contextPath, headers);
this.cookies = cookies;
this.localAddress = localAddress;
this.remoteAddress = remoteAddress;
@ -84,11 +81,6 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
}
@Override
public HttpMethod getMethod() {
return this.httpMethod;
}
@Override
@Nullable
public InetSocketAddress getLocalAddress() {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,8 +24,10 @@ import java.util.regex.Pattern;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.RequestPath;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@ -49,6 +51,10 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
private final HttpHeaders headers;
// TODO: remove @Nullable once deprecated constructors have been removed
@Nullable
private final HttpMethod method;
@Nullable
private MultiValueMap<String, String> queryParams;
@ -71,11 +77,35 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
* @param contextPath the context path for the request
* @param headers the headers for the request (as {@link MultiValueMap})
* @since 5.3
* @deprecated since 6.0.8, in favor of {@link #AbstractServerHttpRequest(HttpMethod, URI, String, MultiValueMap)}
*/
@Deprecated(since = "6.0.8", forRemoval = true)
public AbstractServerHttpRequest(URI uri, @Nullable String contextPath, MultiValueMap<String, String> headers) {
this.uri = uri;
this.path = RequestPath.parse(uri, contextPath);
this.headers = HttpHeaders.readOnlyHttpHeaders(headers);
this.method = null;
}
/**
* Constructor with the method, URI and headers for the request.
* @param method the HTTP method for the request
* @param uri the URI for the request
* @param contextPath the context path for the request
* @param headers the headers for the request (as {@link MultiValueMap})
* @since 6.0.8
*/
public AbstractServerHttpRequest(HttpMethod method, URI uri, @Nullable String contextPath,
MultiValueMap<String, String> headers) {
Assert.notNull(method, "Method must not be null");
Assert.notNull(uri, "Uri must not be null");
Assert.notNull(headers, "Headers must not be null");
this.method = method;
this.uri = uri;
this.path = RequestPath.parse(uri, contextPath);
this.headers = HttpHeaders.readOnlyHttpHeaders(headers);
}
/**
@ -83,11 +113,14 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
* @param uri the URI for the request
* @param contextPath the context path for the request
* @param headers the headers for the request (as {@link HttpHeaders})
* @deprecated since 6.0.8, in favor of {@link #AbstractServerHttpRequest(HttpMethod, URI, String, MultiValueMap)}
*/
@Deprecated(since = "6.0.8", forRemoval = true)
public AbstractServerHttpRequest(URI uri, @Nullable String contextPath, HttpHeaders headers) {
this.uri = uri;
this.path = RequestPath.parse(uri, contextPath);
this.headers = HttpHeaders.readOnlyHttpHeaders(headers);
this.method = null;
}
@ -112,6 +145,18 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
return null;
}
@Override
public HttpMethod getMethod() {
// TODO: remove null check once deprecated constructors have been removed
if (this.method != null) {
return this.method;
}
else {
throw new IllegalStateException("No HttpMethod provided in constructor, " +
"and AbstractServerHttpRequest::getMethod not overridden");
}
}
@Override
public URI getURI() {
return this.uri;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -177,8 +177,6 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder {
private static class MutatedServerHttpRequest extends AbstractServerHttpRequest {
private final HttpMethod method;
@Nullable
private final SslInfo sslInfo;
@ -194,19 +192,13 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder {
HttpMethod method, @Nullable SslInfo sslInfo, @Nullable InetSocketAddress remoteAddress,
HttpHeaders headers, Flux<DataBuffer> body, ServerHttpRequest originalRequest) {
super(uri, contextPath, headers);
this.method = method;
super(method, uri, contextPath, headers);
this.remoteAddress = (remoteAddress != null ? remoteAddress : originalRequest.getRemoteAddress());
this.sslInfo = (sslInfo != null ? sslInfo : originalRequest.getSslInfo());
this.body = body;
this.originalRequest = originalRequest;
}
@Override
public HttpMethod getMethod() {
return this.method;
}
@Override
protected MultiValueMap<String, HttpCookie> initCookies() {
return this.originalRequest.getCookies();

View File

@ -63,17 +63,15 @@ class ReactorNetty2ServerHttpRequest extends AbstractServerHttpRequest {
private final Netty5DataBufferFactory bufferFactory;
private final HttpMethod method;
public ReactorNetty2ServerHttpRequest(HttpServerRequest request, Netty5DataBufferFactory bufferFactory)
throws URISyntaxException {
super(initUri(request), "", new Netty5HeadersAdapter(request.requestHeaders()));
super(HttpMethod.valueOf(request.method().name()), initUri(request), "",
new Netty5HeadersAdapter(request.requestHeaders()));
Assert.notNull(bufferFactory, "DataBufferFactory must not be null");
this.request = request;
this.bufferFactory = bufferFactory;
this.method = HttpMethod.valueOf(request.method().name());
}
private static URI initUri(HttpServerRequest request) throws URISyntaxException {
@ -142,11 +140,6 @@ class ReactorNetty2ServerHttpRequest extends AbstractServerHttpRequest {
return uri;
}
@Override
public HttpMethod getMethod() {
return this.method;
}
@Override
protected MultiValueMap<String, HttpCookie> initCookies() {
MultiValueMap<String, HttpCookie> cookies = new LinkedMultiValueMap<>();

View File

@ -61,17 +61,15 @@ class ReactorServerHttpRequest extends AbstractServerHttpRequest {
private final NettyDataBufferFactory bufferFactory;
private final HttpMethod method;
public ReactorServerHttpRequest(HttpServerRequest request, NettyDataBufferFactory bufferFactory)
throws URISyntaxException {
super(initUri(request), "", new NettyHeadersAdapter(request.requestHeaders()));
super(HttpMethod.valueOf(request.method().name()), initUri(request), "",
new NettyHeadersAdapter(request.requestHeaders()));
Assert.notNull(bufferFactory, "DataBufferFactory must not be null");
this.request = request;
this.bufferFactory = bufferFactory;
this.method = HttpMethod.valueOf(request.method().name());
}
private static URI initUri(HttpServerRequest request) throws URISyntaxException {
@ -112,10 +110,6 @@ class ReactorServerHttpRequest extends AbstractServerHttpRequest {
return uri;
}
@Override
public HttpMethod getMethod() {
return this.method;
}
@Override
protected MultiValueMap<String, HttpCookie> initCookies() {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -90,7 +90,8 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
AsyncContext asyncContext, String servletPath, DataBufferFactory bufferFactory, int bufferSize)
throws IOException, URISyntaxException {
super(initUri(request), request.getContextPath() + servletPath, initHeaders(headers, request));
super(HttpMethod.valueOf(request.getMethod()), initUri(request), request.getContextPath() + servletPath,
initHeaders(headers, request));
Assert.notNull(bufferFactory, "'bufferFactory' must not be null");
Assert.isTrue(bufferSize > 0, "'bufferSize' must be greater than 0");
@ -162,11 +163,6 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
return (headers != null ? headers : headerValues);
}
@Override
public HttpMethod getMethod() {
return HttpMethod.valueOf(this.request.getMethod());
}
@Override
protected MultiValueMap<String, HttpCookie> initCookies() {
MultiValueMap<String, HttpCookie> httpCookies = new LinkedMultiValueMap<>();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -64,7 +64,8 @@ class UndertowServerHttpRequest extends AbstractServerHttpRequest {
public UndertowServerHttpRequest(HttpServerExchange exchange, DataBufferFactory bufferFactory)
throws URISyntaxException {
super(initUri(exchange), "", new UndertowHeadersAdapter(exchange.getRequestHeaders()));
super(HttpMethod.valueOf(exchange.getRequestMethod().toString()), initUri(exchange), "",
new UndertowHeadersAdapter(exchange.getRequestHeaders()));
this.exchange = exchange;
this.body = new RequestBodyPublisher(exchange, bufferFactory);
this.body.registerListeners(exchange);
@ -78,11 +79,6 @@ class UndertowServerHttpRequest extends AbstractServerHttpRequest {
return new URI(requestUriAndQuery);
}
@Override
public HttpMethod getMethod() {
return HttpMethod.valueOf(this.exchange.getRequestMethod().toString());
}
@Override
protected MultiValueMap<String, HttpCookie> initCookies() {
MultiValueMap<String, HttpCookie> cookies = new LinkedMultiValueMap<>();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -55,8 +55,6 @@ import org.springframework.web.util.UriComponentsBuilder;
*/
public final class MockServerHttpRequest extends AbstractServerHttpRequest {
private final HttpMethod httpMethod;
private final MultiValueMap<String, HttpCookie> cookies;
@Nullable
@ -75,8 +73,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
@Nullable InetSocketAddress localAddress, @Nullable InetSocketAddress remoteAddress,
@Nullable SslInfo sslInfo, Publisher<? extends DataBuffer> body) {
super(uri, contextPath, headers);
this.httpMethod = httpMethod;
super(httpMethod, uri, contextPath, headers);
this.cookies = cookies;
this.localAddress = localAddress;
this.remoteAddress = remoteAddress;
@ -85,11 +82,6 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest {
}
@Override
public HttpMethod getMethod() {
return this.httpMethod;
}
@Override
@Nullable
public InetSocketAddress getLocalAddress() {