diff --git a/spring-web/src/main/java/org/springframework/http/ReadOnlyHttpHeaders.java b/spring-web/src/main/java/org/springframework/http/ReadOnlyHttpHeaders.java index 39f64d4b6af..341938f1ba2 100644 --- a/spring-web/src/main/java/org/springframework/http/ReadOnlyHttpHeaders.java +++ b/spring-web/src/main/java/org/springframework/http/ReadOnlyHttpHeaders.java @@ -31,7 +31,7 @@ import org.springframework.util.MultiValueMap; * {@code HttpHeaders} object that can only be read, not written to. * * @author Brian Clozel - * @since 5.1 + * @since 5.1.1 */ class ReadOnlyHttpHeaders extends HttpHeaders { @@ -59,10 +59,7 @@ class ReadOnlyHttpHeaders extends HttpHeaders { @Override public List get(Object key) { List values = this.headers.get(key); - if (values != null) { - return Collections.unmodifiableList(values); - } - return values; + return (values != null ? Collections.unmodifiableList(values) : null); } @Override diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/JettyHeadersAdapter.java b/spring-web/src/main/java/org/springframework/http/server/reactive/JettyHeadersAdapter.java index 5ffc0779acc..c1c0a1f5d7e 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/JettyHeadersAdapter.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/JettyHeadersAdapter.java @@ -36,16 +36,18 @@ import org.springframework.util.MultiValueMap; * {@code MultiValueMap} implementation for wrapping Jetty HTTP headers. * * @author Brian Clozel - * @since 5.1 + * @since 5.1.1 */ class JettyHeadersAdapter implements MultiValueMap { private final HttpFields headers; + JettyHeadersAdapter(HttpFields headers) { this.headers = headers; } + @Override public String getFirst(String key) { return this.headers.get(key); @@ -95,24 +97,18 @@ class JettyHeadersAdapter implements MultiValueMap { @Override public boolean isEmpty() { - return this.headers.size() == 0; + return (this.headers.size() == 0); } @Override public boolean containsKey(Object key) { - if (key instanceof String) { - return this.headers.containsKey((String) key); - } - return false; + return (key instanceof String && this.headers.containsKey((String) key)); } @Override public boolean containsValue(Object value) { - if (value instanceof String) { - return this.headers.stream() - .anyMatch(field -> field.contains((String) value)); - } - return false; + return (value instanceof String && + this.headers.stream().anyMatch(field -> field.contains((String) value))); } @Nullable @@ -144,8 +140,8 @@ class JettyHeadersAdapter implements MultiValueMap { } @Override - public void putAll(Map> m) { - m.forEach(this::put); + public void putAll(Map> map) { + map.forEach(this::put); } @Override @@ -179,6 +175,7 @@ class JettyHeadersAdapter implements MultiValueMap { }; } + private class EntryIterator implements Iterator>> { private Enumeration names = headers.getFieldNames(); @@ -194,6 +191,7 @@ class JettyHeadersAdapter implements MultiValueMap { } } + private class HeaderEntry implements Entry> { private final String key; @@ -204,7 +202,7 @@ class JettyHeadersAdapter implements MultiValueMap { @Override public String getKey() { - return this.key.toString(); + return this.key; } @Override @@ -219,4 +217,5 @@ class JettyHeadersAdapter implements MultiValueMap { return previousValues; } } + } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/JettyHttpHandlerAdapter.java b/spring-web/src/main/java/org/springframework/http/server/reactive/JettyHttpHandlerAdapter.java index 86c9660aacc..4f0aa9f0b79 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/JettyHttpHandlerAdapter.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/JettyHttpHandlerAdapter.java @@ -34,12 +34,14 @@ import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; +import org.springframework.util.Assert; /** * {@link ServletHttpHandlerAdapter} extension that uses Jetty APIs for writing * to the response with {@link ByteBuffer}. * * @author Violeta Georgieva + * @author Brian Clozel * @since 5.0 * @see org.springframework.web.server.adapter.AbstractReactiveWebInitializer */ @@ -53,6 +55,8 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter { @Override protected ServletServerHttpRequest createRequest(HttpServletRequest request, AsyncContext context) throws IOException, URISyntaxException { + + Assert.notNull(getServletPath(), "Servlet path is not initialized"); return new JettyServerHttpRequest(request, context, getServletPath(), getDataBufferFactory(), getBufferSize()); } @@ -64,6 +68,7 @@ public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter { response, context, getDataBufferFactory(), getBufferSize(), request); } + private static final class JettyServerHttpRequest extends ServletServerHttpRequest { JettyServerHttpRequest(HttpServletRequest request, AsyncContext asyncContext, diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/NettyHeadersAdapter.java b/spring-web/src/main/java/org/springframework/http/server/reactive/NettyHeadersAdapter.java index 6d68ceb1d85..ffd5680eab2 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/NettyHeadersAdapter.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/NettyHeadersAdapter.java @@ -34,16 +34,18 @@ import org.springframework.util.MultiValueMap; * {@code MultiValueMap} implementation for wrapping Netty HTTP headers. * * @author Brian Clozel - * @since 5.1 + * @since 5.1.1 */ class NettyHeadersAdapter implements MultiValueMap { private final HttpHeaders headers; + NettyHeadersAdapter(HttpHeaders headers) { this.headers = headers; } + @Override @Nullable public String getFirst(String key) { @@ -99,14 +101,14 @@ class NettyHeadersAdapter implements MultiValueMap { @Override public boolean containsKey(Object key) { - return (key instanceof String) && this.headers.contains((String) key); + return (key instanceof String && this.headers.contains((String) key)); } @Override public boolean containsValue(Object value) { - return (value instanceof String) && + return (value instanceof String && this.headers.entries().stream() - .anyMatch(entry -> value != null && value.equals(entry.getValue())); + .anyMatch(entry -> value.equals(entry.getValue()))); } @Override @@ -138,8 +140,8 @@ class NettyHeadersAdapter implements MultiValueMap { } @Override - public void putAll(Map> m) { - m.forEach(this.headers::add); + public void putAll(Map> map) { + map.forEach(this.headers::add); } @Override @@ -173,6 +175,7 @@ class NettyHeadersAdapter implements MultiValueMap { }; } + private class EntryIterator implements Iterator>> { private Iterator names = headers.names().iterator(); @@ -188,6 +191,7 @@ class NettyHeadersAdapter implements MultiValueMap { } } + private class HeaderEntry implements Entry> { private final String key; diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHeadersAdapter.java b/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHeadersAdapter.java index e667a3e86c0..9b0e462dda5 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHeadersAdapter.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHeadersAdapter.java @@ -38,23 +38,25 @@ import org.springframework.util.MultiValueMap; * {@code MultiValueMap} implementation for wrapping Tomcat HTTP headers. * * @author Brian Clozel - * @since 5.1 + * @since 5.1.1 */ class TomcatHeadersAdapter implements MultiValueMap { private final MimeHeaders headers; + TomcatHeadersAdapter(MimeHeaders headers) { this.headers = headers; } + @Override public String getFirst(String key) { return this.headers.getHeader(key); } @Override - public void add(String key, String value) { + public void add(String key, @Nullable String value) { this.headers.addValue(key).setString(value); } @@ -69,7 +71,7 @@ class TomcatHeadersAdapter implements MultiValueMap { } @Override - public void set(String key, String value) { + public void set(String key, @Nullable String value) { this.headers.setValue(key).setString(value); } @@ -98,13 +100,13 @@ class TomcatHeadersAdapter implements MultiValueMap { @Override public boolean isEmpty() { - return this.headers.size() == 0; + return (this.headers.size() == 0); } @Override public boolean containsKey(Object key) { if (key instanceof String) { - return this.headers.findHeader((String) key, 0) != -1; + return (this.headers.findHeader((String) key, 0) != -1); } return false; } @@ -152,8 +154,8 @@ class TomcatHeadersAdapter implements MultiValueMap { } @Override - public void putAll(Map> m) { - m.forEach(this::put); + public void putAll(Map> map) { + map.forEach(this::put); } @Override @@ -191,6 +193,7 @@ class TomcatHeadersAdapter implements MultiValueMap { }; } + private class EntryIterator implements Iterator>> { private Enumeration names = headers.names(); @@ -206,11 +209,12 @@ class TomcatHeadersAdapter implements MultiValueMap { } } + private final class HeaderEntry implements Entry> { private final String key; - private HeaderEntry(String key) { + HeaderEntry(String key) { this.key = key; } @@ -234,4 +238,5 @@ class TomcatHeadersAdapter implements MultiValueMap { return previous; } } + } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHttpHandlerAdapter.java b/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHttpHandlerAdapter.java index 9e1c9ee2a20..de85f104811 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHttpHandlerAdapter.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHttpHandlerAdapter.java @@ -48,7 +48,6 @@ import org.springframework.util.ReflectionUtils; * * @author Violeta Georgieva * @author Brian Clozel - * @author Brian Clozel * @since 5.0 * @see org.springframework.web.server.adapter.AbstractReactiveWebInitializer */ @@ -64,7 +63,7 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter { protected ServletServerHttpRequest createRequest(HttpServletRequest request, AsyncContext asyncContext) throws IOException, URISyntaxException { - Assert.notNull(getServletPath(), "servletPath is not initialized."); + Assert.notNull(getServletPath(), "Servlet path is not initialized"); return new TomcatServerHttpRequest( request, asyncContext, getServletPath(), getDataBufferFactory(), getBufferSize()); } @@ -77,16 +76,20 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter { response, asyncContext, getDataBufferFactory(), getBufferSize(), request); } + private static final class TomcatServerHttpRequest extends ServletServerHttpRequest { - private static final Field COYOTE_REQUEST_FIELD = ReflectionUtils.findField(RequestFacade.class, "request"); + private static final Field COYOTE_REQUEST_FIELD; private final int bufferSize; private final DataBufferFactory factory; static { - ReflectionUtils.makeAccessible(COYOTE_REQUEST_FIELD); + Field field = ReflectionUtils.findField(RequestFacade.class, "request"); + Assert.state(field != null, "Incompatible Tomcat implementation"); + ReflectionUtils.makeAccessible(field); + COYOTE_REQUEST_FIELD = field; } TomcatServerHttpRequest(HttpServletRequest request, AsyncContext context, @@ -99,8 +102,10 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter { } private static HttpHeaders createTomcatHttpHeaders(HttpServletRequest request) { - Request tomcatRequest = ((org.apache.catalina.connector.Request) ReflectionUtils - .getField(COYOTE_REQUEST_FIELD, request)).getCoyoteRequest(); + org.apache.catalina.connector.Request connectorRequest = (org.apache.catalina.connector.Request) + ReflectionUtils.getField(COYOTE_REQUEST_FIELD, request); + Assert.state(connectorRequest != null, "No Tomcat connector request"); + Request tomcatRequest = connectorRequest.getCoyoteRequest(); TomcatHeadersAdapter headers = new TomcatHeadersAdapter(tomcatRequest.getMimeHeaders()); return new HttpHeaders(headers); } @@ -112,11 +117,9 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter { DataBuffer dataBuffer = this.factory.allocateBuffer(capacity); try { ByteBuffer byteBuffer = dataBuffer.asByteBuffer(0, capacity); - ServletRequest request = getNativeRequest(); int read = ((CoyoteInputStream) request.getInputStream()).read(byteBuffer); logBytesRead(read); - if (read > 0) { dataBuffer.writePosition(read); release = false; @@ -140,10 +143,13 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter { private static final class TomcatServerHttpResponse extends ServletServerHttpResponse { - private static final Field COYOTE_RESPONSE_FIELD = ReflectionUtils.findField(ResponseFacade.class, "response"); + private static final Field COYOTE_RESPONSE_FIELD; static { - ReflectionUtils.makeAccessible(COYOTE_RESPONSE_FIELD); + Field field = ReflectionUtils.findField(ResponseFacade.class, "response"); + Assert.state(field != null, "Incompatible Tomcat implementation"); + ReflectionUtils.makeAccessible(field); + COYOTE_RESPONSE_FIELD = field; } TomcatServerHttpResponse(HttpServletResponse response, AsyncContext context, @@ -153,8 +159,10 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter { } private static HttpHeaders createTomcatHttpHeaders(HttpServletResponse response) { - Response tomcatResponse = ((org.apache.catalina.connector.Response) ReflectionUtils - .getField(COYOTE_RESPONSE_FIELD, response)).getCoyoteResponse(); + org.apache.catalina.connector.Response connectorResponse = (org.apache.catalina.connector.Response) + ReflectionUtils.getField(COYOTE_RESPONSE_FIELD, response); + Assert.state(connectorResponse != null, "No Tomcat connector response"); + Response tomcatResponse = connectorResponse.getCoyoteResponse(); TomcatHeadersAdapter headers = new TomcatHeadersAdapter(tomcatResponse.getMimeHeaders()); return new HttpHeaders(headers); } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowHeadersAdapter.java b/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowHeadersAdapter.java index 3e817c906f6..5dc80a9bbe4 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowHeadersAdapter.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowHeadersAdapter.java @@ -36,16 +36,18 @@ import org.springframework.util.MultiValueMap; * {@code MultiValueMap} implementation for wrapping Undertow HTTP headers. * * @author Brian Clozel - * @since 5.1 + * @since 5.1.1 */ class UndertowHeadersAdapter implements MultiValueMap { private final HeaderMap headers; + UndertowHeadersAdapter(HeaderMap headers) { this.headers = headers; } + @Override public String getFirst(String key) { return this.headers.getFirst(key); @@ -92,25 +94,20 @@ class UndertowHeadersAdapter implements MultiValueMap { @Override public boolean isEmpty() { - return this.headers.size() == 0; + return (this.headers.size() == 0); } @Override public boolean containsKey(Object key) { - if (key instanceof String) { - return this.headers.contains((String) key); - } - return false; + return (key instanceof String && this.headers.contains((String) key)); } @Override public boolean containsValue(Object value) { - if (value instanceof String) { - return this.headers.getHeaderNames().stream() - .map(this.headers::get) - .anyMatch(values -> values.contains(value)); - } - return false; + return (value instanceof String && + this.headers.getHeaderNames().stream() + .map(this.headers::get) + .anyMatch(values -> values.contains(value))); } @Override @@ -140,8 +137,8 @@ class UndertowHeadersAdapter implements MultiValueMap { } @Override - public void putAll(Map> m) { - m.forEach((key, values) -> + public void putAll(Map> map) { + map.forEach((key, values) -> this.headers.putAll(HttpString.tryFromString(key), values)); } @@ -179,6 +176,7 @@ class UndertowHeadersAdapter implements MultiValueMap { }; } + private class EntryIterator implements Iterator>> { private Iterator names = headers.getHeaderNames().iterator(); @@ -194,6 +192,7 @@ class UndertowHeadersAdapter implements MultiValueMap { } } + private class HeaderEntry implements Entry> { private final HttpString key; @@ -219,4 +218,5 @@ class UndertowHeadersAdapter implements MultiValueMap { return previousValues; } } + }