Browse Source

Consistent HttpMethod identity comparisons

pull/1693/head
Juergen Hoeller 8 years ago
parent
commit
0de36d2883
  1. 6
      spring-test/src/main/java/org/springframework/test/web/reactive/server/HttpHandlerConnector.java
  2. 4
      spring-web/src/main/java/org/springframework/http/client/SimpleBufferingAsyncClientHttpRequest.java
  3. 4
      spring-web/src/main/java/org/springframework/http/client/SimpleBufferingClientHttpRequest.java
  4. 8
      spring-web/src/main/java/org/springframework/http/server/reactive/ReactorHttpHandlerAdapter.java
  5. 2
      spring-web/src/main/java/org/springframework/http/server/reactive/ServletHttpHandlerAdapter.java
  6. 14
      spring-web/src/main/java/org/springframework/http/server/reactive/UndertowHttpHandlerAdapter.java
  7. 7
      spring-web/src/main/java/org/springframework/web/cors/reactive/CorsUtils.java
  8. 8
      spring-web/src/test/java/org/springframework/web/filter/HttpPutFormContentFilterTests.java
  9. 5
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMapping.java
  10. 16
      spring-webflux/src/test/java/org/springframework/web/reactive/result/condition/RequestMethodsRequestConditionTests.java
  11. 4
      spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java
  12. 10
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java
  13. 18
      spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java
  14. 18
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/RequestMethodsRequestConditionTests.java
  15. 30
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java
  16. 11
      spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/AbstractSockJsService.java
  17. 4
      spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandlingSockJsService.java

6
spring-test/src/main/java/org/springframework/test/web/reactive/server/HttpHandlerConnector.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -61,7 +61,6 @@ public class HttpHandlerConnector implements ClientHttpConnector {
private static Log logger = LogFactory.getLog(HttpHandlerConnector.class); private static Log logger = LogFactory.getLog(HttpHandlerConnector.class);
private final HttpHandler handler; private final HttpHandler handler;
@ -118,8 +117,7 @@ public class HttpHandlerConnector implements ClientHttpConnector {
} }
private ServerHttpResponse prepareResponse(ServerHttpResponse response, ServerHttpRequest request) { private ServerHttpResponse prepareResponse(ServerHttpResponse response, ServerHttpRequest request) {
return HttpMethod.HEAD.equals(request.getMethod()) ? return (request.getMethod() == HttpMethod.HEAD ? new HttpHeadResponseDecorator(response) : response);
new HttpHeadResponseDecorator(response) : response;
} }
private ClientHttpResponse adaptResponse(MockServerHttpResponse response, Flux<DataBuffer> body) { private ClientHttpResponse adaptResponse(MockServerHttpResponse response, Flux<DataBuffer> body) {

4
spring-web/src/main/java/org/springframework/http/client/SimpleBufferingAsyncClientHttpRequest.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -81,7 +81,7 @@ final class SimpleBufferingAsyncClientHttpRequest extends AbstractBufferingAsync
public ClientHttpResponse call() throws Exception { public ClientHttpResponse call() throws Exception {
SimpleBufferingClientHttpRequest.addHeaders(connection, headers); SimpleBufferingClientHttpRequest.addHeaders(connection, headers);
// JDK <1.8 doesn't support getOutputStream with HTTP DELETE // JDK <1.8 doesn't support getOutputStream with HTTP DELETE
if (HttpMethod.DELETE == getMethod() && bufferedOutput.length == 0) { if (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {
connection.setDoOutput(false); connection.setDoOutput(false);
} }
if (connection.getDoOutput() && outputStreaming) { if (connection.getDoOutput() && outputStreaming) {

4
spring-web/src/main/java/org/springframework/http/client/SimpleBufferingClientHttpRequest.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -69,7 +69,7 @@ final class SimpleBufferingClientHttpRequest extends AbstractBufferingClientHttp
protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException { protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
addHeaders(this.connection, headers); addHeaders(this.connection, headers);
// JDK <1.8 doesn't support getOutputStream with HTTP DELETE // JDK <1.8 doesn't support getOutputStream with HTTP DELETE
if (HttpMethod.DELETE == getMethod() && bufferedOutput.length == 0) { if (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {
this.connection.setDoOutput(false); this.connection.setDoOutput(false);
} }
if (this.connection.getDoOutput() && this.outputStreaming) { if (this.connection.getDoOutput() && this.outputStreaming) {

8
spring-web/src/main/java/org/springframework/http/server/reactive/ReactorHttpHandlerAdapter.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,12 +20,12 @@ import java.net.URISyntaxException;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpResponseStatus;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import reactor.ipc.netty.http.server.HttpServerRequest; import reactor.ipc.netty.http.server.HttpServerRequest;
import reactor.ipc.netty.http.server.HttpServerResponse; import reactor.ipc.netty.http.server.HttpServerResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.buffer.NettyDataBufferFactory; import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -67,7 +67,7 @@ public class ReactorHttpHandlerAdapter
return Mono.empty(); return Mono.empty();
} }
if (HttpMethod.HEAD.equals(adaptedRequest.getMethod())) { if (adaptedRequest.getMethod() == HttpMethod.HEAD) {
adaptedResponse = new HttpHeadResponseDecorator(adaptedResponse); adaptedResponse = new HttpHeadResponseDecorator(adaptedResponse);
} }

2
spring-web/src/main/java/org/springframework/http/server/reactive/ServletHttpHandlerAdapter.java

@ -168,7 +168,7 @@ public class ServletHttpHandlerAdapter implements Servlet {
ServerHttpRequest httpRequest = createRequest(((HttpServletRequest) request), asyncContext); ServerHttpRequest httpRequest = createRequest(((HttpServletRequest) request), asyncContext);
ServerHttpResponse httpResponse = createResponse(((HttpServletResponse) response), asyncContext); ServerHttpResponse httpResponse = createResponse(((HttpServletResponse) response), asyncContext);
if (HttpMethod.HEAD.equals(httpRequest.getMethod())) { if (httpRequest.getMethod() == HttpMethod.HEAD) {
httpResponse = new HttpHeadResponseDecorator(httpResponse); httpResponse = new HttpHeadResponseDecorator(httpResponse);
} }

14
spring-web/src/main/java/org/springframework/http/server/reactive/UndertowHttpHandlerAdapter.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,7 +19,6 @@ package org.springframework.http.server.reactive;
import java.io.IOException; import java.io.IOException;
import io.undertow.server.HttpServerExchange; import io.undertow.server.HttpServerExchange;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Subscriber; import org.reactivestreams.Subscriber;
@ -66,11 +65,10 @@ public class UndertowHttpHandlerAdapter implements io.undertow.server.HttpHandle
@Override @Override
public void handleRequest(HttpServerExchange exchange) throws Exception { public void handleRequest(HttpServerExchange exchange) throws Exception {
ServerHttpRequest request = new UndertowServerHttpRequest(exchange, getDataBufferFactory()); ServerHttpRequest request = new UndertowServerHttpRequest(exchange, getDataBufferFactory());
ServerHttpResponse response = new UndertowServerHttpResponse(exchange, getDataBufferFactory()); ServerHttpResponse response = new UndertowServerHttpResponse(exchange, getDataBufferFactory());
if (HttpMethod.HEAD.equals(request.getMethod())) { if (request.getMethod() == HttpMethod.HEAD) {
response = new HttpHeadResponseDecorator(response); response = new HttpHeadResponseDecorator(response);
} }
@ -83,7 +81,6 @@ public class UndertowHttpHandlerAdapter implements io.undertow.server.HttpHandle
private final HttpServerExchange exchange; private final HttpServerExchange exchange;
public HandlerResultSubscriber(HttpServerExchange exchange) { public HandlerResultSubscriber(HttpServerExchange exchange) {
this.exchange = exchange; this.exchange = exchange;
} }
@ -95,7 +92,7 @@ public class UndertowHttpHandlerAdapter implements io.undertow.server.HttpHandle
@Override @Override
public void onNext(Void aVoid) { public void onNext(Void aVoid) {
// no op // no-op
} }
@Override @Override
@ -106,8 +103,8 @@ public class UndertowHttpHandlerAdapter implements io.undertow.server.HttpHandle
logger.debug("Closing connection"); logger.debug("Closing connection");
this.exchange.getConnection().close(); this.exchange.getConnection().close();
} }
catch (IOException e) { catch (IOException ex2) {
// Ignore // ignore
} }
} }
else { else {
@ -123,4 +120,5 @@ public class UndertowHttpHandlerAdapter implements io.undertow.server.HttpHandle
this.exchange.endExchange(); this.exchange.endExchange();
} }
} }
} }

7
spring-web/src/main/java/org/springframework/web/cors/reactive/CorsUtils.java

@ -44,7 +44,7 @@ public abstract class CorsUtils {
* Returns {@code true} if the request is a valid CORS pre-flight one. * Returns {@code true} if the request is a valid CORS pre-flight one.
*/ */
public static boolean isPreFlightRequest(ServerHttpRequest request) { public static boolean isPreFlightRequest(ServerHttpRequest request) {
return (isCorsRequest(request) && HttpMethod.OPTIONS == request.getMethod() && return (request.getMethod() == HttpMethod.OPTIONS && isCorsRequest(request) &&
request.getHeaders().get(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD) != null); request.getHeaders().get(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD) != null);
} }
@ -53,7 +53,7 @@ public abstract class CorsUtils {
* {@code Forwarded}, {@code X-Forwarded-Proto}, {@code X-Forwarded-Host} and * {@code Forwarded}, {@code X-Forwarded-Proto}, {@code X-Forwarded-Host} and
* @code X-Forwarded-Port} headers. * @code X-Forwarded-Port} headers.
* @return {@code true} if the request is a same-origin one, {@code false} in case * @return {@code true} if the request is a same-origin one, {@code false} in case
* of cross-origin request. * of a cross-origin request
*/ */
public static boolean isSameOrigin(ServerHttpRequest request) { public static boolean isSameOrigin(ServerHttpRequest request) {
String origin = request.getHeaders().getOrigin(); String origin = request.getHeaders().getOrigin();
@ -67,7 +67,8 @@ public abstract class CorsUtils {
Assert.notNull(actualHost, "Actual request host must not be null"); Assert.notNull(actualHost, "Actual request host must not be null");
Assert.isTrue(actualPort != -1, "Actual request port must not be undefined"); Assert.isTrue(actualPort != -1, "Actual request port must not be undefined");
UriComponents originUrl = UriComponentsBuilder.fromOriginHeader(origin).build(); UriComponents originUrl = UriComponentsBuilder.fromOriginHeader(origin).build();
return (actualHost.equals(originUrl.getHost()) && actualPort == getPort(originUrl.getScheme(), originUrl.getPort())); return (actualHost.equals(originUrl.getHost()) &&
actualPort == getPort(originUrl.getScheme(), originUrl.getPort()));
} }
private static int getPort(@Nullable String scheme, int port) { private static int getPort(@Nullable String scheme, int port) {

8
spring-web/src/test/java/org/springframework/web/filter/HttpPutFormContentFilterTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -46,6 +46,7 @@ public class HttpPutFormContentFilterTests {
private MockFilterChain filterChain; private MockFilterChain filterChain;
@Before @Before
public void setup() { public void setup() {
filter = new HttpPutFormContentFilter(); filter = new HttpPutFormContentFilter();
@ -56,6 +57,7 @@ public class HttpPutFormContentFilterTests {
filterChain = new MockFilterChain(); filterChain = new MockFilterChain();
} }
@Test @Test
public void wrapPutAndPatchOnly() throws Exception { public void wrapPutAndPatchOnly() throws Exception {
request.setContent("foo=bar".getBytes("ISO-8859-1")); request.setContent("foo=bar".getBytes("ISO-8859-1"));
@ -63,7 +65,7 @@ public class HttpPutFormContentFilterTests {
request.setMethod(method.name()); request.setMethod(method.name());
filterChain = new MockFilterChain(); filterChain = new MockFilterChain();
filter.doFilter(request, response, filterChain); filter.doFilter(request, response, filterChain);
if (method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PATCH)) { if (method == HttpMethod.PUT || method == HttpMethod.PATCH) {
assertNotSame("Should wrap HTTP method " + method, request, filterChain.getRequest()); assertNotSame("Should wrap HTTP method " + method, request, filterChain.getRequest());
} }
else { else {
@ -204,7 +206,7 @@ public class HttpPutFormContentFilterTests {
assertArrayEquals(new String[] {"value4"}, parameters.get("name4")); assertArrayEquals(new String[] {"value4"}, parameters.get("name4"));
} }
@Test // SPR-15835 @Test // SPR-15835
public void hiddenHttpMethodFilterFollowedByHttpPutFormContentFilter() throws Exception { public void hiddenHttpMethodFilterFollowedByHttpPutFormContentFilter() throws Exception {
request.addParameter("_method", "PUT"); request.addParameter("_method", "PUT");
request.addParameter("hiddenField", "testHidden"); request.addParameter("hiddenField", "testHidden");

5
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMapping.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -45,7 +45,6 @@ import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.UnsupportedMediaTypeStatusException; import org.springframework.web.server.UnsupportedMediaTypeStatusException;
import org.springframework.web.util.pattern.PathPattern; import org.springframework.web.util.pattern.PathPattern;
/** /**
* Abstract base class for classes for which {@link RequestMappingInfo} defines * Abstract base class for classes for which {@link RequestMappingInfo} defines
* the mapping between a request and a handler method. * the mapping between a request and a handler method.
@ -358,7 +357,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
private static Set<HttpMethod> initAllowedHttpMethods(Set<HttpMethod> declaredMethods) { private static Set<HttpMethod> initAllowedHttpMethods(Set<HttpMethod> declaredMethods) {
if (declaredMethods.isEmpty()) { if (declaredMethods.isEmpty()) {
return EnumSet.allOf(HttpMethod.class).stream() return EnumSet.allOf(HttpMethod.class).stream()
.filter(method -> !method.equals(HttpMethod.TRACE)) .filter(method -> method != HttpMethod.TRACE)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
else { else {

16
spring-webflux/src/test/java/org/springframework/web/reactive/result/condition/RequestMethodsRequestConditionTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -29,16 +29,8 @@ import org.springframework.mock.web.test.server.MockServerWebExchange;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull; import static org.springframework.web.bind.annotation.RequestMethod.*;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.HEAD;
import static org.springframework.web.bind.annotation.RequestMethod.OPTIONS;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
/** /**
* Unit tests for {@link RequestMethodsRequestCondition}. * Unit tests for {@link RequestMethodsRequestCondition}.
@ -67,7 +59,7 @@ public class RequestMethodsRequestConditionTests {
public void getMatchingConditionWithEmptyConditions() throws Exception { public void getMatchingConditionWithEmptyConditions() throws Exception {
RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition(); RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition();
for (RequestMethod method : RequestMethod.values()) { for (RequestMethod method : RequestMethod.values()) {
if (!OPTIONS.equals(method)) { if (method != OPTIONS) {
ServerWebExchange exchange = getExchange(method.name()); ServerWebExchange exchange = getExchange(method.name());
assertNotNull(condition.getMatchingCondition(exchange)); assertNotNull(condition.getMatchingCondition(exchange));
} }

4
spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -848,7 +848,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
throws ServletException, IOException { throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (HttpMethod.PATCH == httpMethod || httpMethod == null) { if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response); processRequest(request, response);
} }
else { else {

10
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -434,16 +434,16 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
Set<HttpMethod> result = new LinkedHashSet<>(declaredMethods.size()); Set<HttpMethod> result = new LinkedHashSet<>(declaredMethods.size());
if (declaredMethods.isEmpty()) { if (declaredMethods.isEmpty()) {
for (HttpMethod method : HttpMethod.values()) { for (HttpMethod method : HttpMethod.values()) {
if (!HttpMethod.TRACE.equals(method)) { if (method != HttpMethod.TRACE) {
result.add(method); result.add(method);
} }
} }
} }
else { else {
boolean hasHead = declaredMethods.contains("HEAD");
for (String method : declaredMethods) { for (String method : declaredMethods) {
result.add(HttpMethod.valueOf(method)); HttpMethod httpMethod = HttpMethod.valueOf(method);
if (!hasHead && "GET".equals(method)) { result.add(httpMethod);
if (httpMethod == HttpMethod.GET) {
result.add(HttpMethod.HEAD); result.add(HttpMethod.HEAD);
} }
} }

18
spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -174,7 +174,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
if (this.supportedMethods == null) { if (this.supportedMethods == null) {
allowedMethods = new ArrayList<>(HttpMethod.values().length - 1); allowedMethods = new ArrayList<>(HttpMethod.values().length - 1);
for (HttpMethod method : HttpMethod.values()) { for (HttpMethod method : HttpMethod.values()) {
if (!HttpMethod.TRACE.equals(method)) { if (method != HttpMethod.TRACE) {
allowedMethods.add(method.name()); allowedMethods.add(method.name());
} }
} }
@ -191,13 +191,13 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
} }
/** /**
* Return the "Allow" header value to use in response to an HTTP OPTIONS * Return the "Allow" header value to use in response to an HTTP OPTIONS request
* request based on the configured {@link #setSupportedMethods supported * based on the configured {@link #setSupportedMethods supported methods} also
* methods} also automatically adding "OPTIONS" to the list even if not * automatically adding "OPTIONS" to the list even if not present as a supported
* present as a supported method. This means sub-classes don't have to * method. This means subclasses don't have to explicitly list "OPTIONS" as a
* explicitly list "OPTIONS" as a supported method as long as HTTP OPTIONS * supported method as long as HTTP OPTIONS requests are handled before making a
* requests are handled before making a call to * call to {@link #checkRequest(HttpServletRequest)}.
* {@link #checkRequest(HttpServletRequest)}. * @since 4.3
*/ */
@Nullable @Nullable
protected String getAllowHeader() { protected String getAllowHeader() {

18
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/RequestMethodsRequestConditionTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,7 +17,6 @@
package org.springframework.web.servlet.mvc.condition; package org.springframework.web.servlet.mvc.condition;
import java.util.Collections; import java.util.Collections;
import javax.servlet.DispatcherType; import javax.servlet.DispatcherType;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -27,17 +26,8 @@ import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull; import static org.springframework.web.bind.annotation.RequestMethod.*;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.HEAD;
import static org.springframework.web.bind.annotation.RequestMethod.OPTIONS;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
/** /**
* @author Arjen Poutsma * @author Arjen Poutsma
@ -63,7 +53,7 @@ public class RequestMethodsRequestConditionTests {
public void getMatchingConditionWithEmptyConditions() { public void getMatchingConditionWithEmptyConditions() {
RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition(); RequestMethodsRequestCondition condition = new RequestMethodsRequestCondition();
for (RequestMethod method : RequestMethod.values()) { for (RequestMethod method : RequestMethod.values()) {
if (!OPTIONS.equals(method)) { if (method != OPTIONS) {
HttpServletRequest request = new MockHttpServletRequest(method.name(), ""); HttpServletRequest request = new MockHttpServletRequest(method.name(), "");
assertNotNull(condition.getMatchingCondition(request)); assertNotNull(condition.getMatchingCondition(request));
} }

30
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMappingTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,9 +16,6 @@
package org.springframework.web.servlet.mvc.method; package org.springframework.web.servlet.mvc.method;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -26,7 +23,6 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.junit.Before; import org.junit.Before;
@ -63,6 +59,8 @@ import org.springframework.web.servlet.mvc.condition.ProducesRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition; import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.UrlPathHelper;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/** /**
* Test fixture with {@link RequestMappingInfoHandlerMapping}. * Test fixture with {@link RequestMappingInfoHandlerMapping}.
@ -157,9 +155,7 @@ public class RequestMappingInfoHandlerMappingTests {
} }
} }
// SPR-9603 @Test(expected = HttpMediaTypeNotAcceptableException.class) // SPR-9603
@Test(expected = HttpMediaTypeNotAcceptableException.class)
public void getHandlerRequestMethodMatchFalsePositive() throws Exception { public void getHandlerRequestMethodMatchFalsePositive() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/users"); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/users");
request.addHeader("Accept", "application/xml"); request.addHeader("Accept", "application/xml");
@ -167,9 +163,7 @@ public class RequestMappingInfoHandlerMappingTests {
this.handlerMapping.getHandler(request); this.handlerMapping.getHandler(request);
} }
// SPR-8462 @Test // SPR-8462
@Test
public void getHandlerMediaTypeNotSupported() throws Exception { public void getHandlerMediaTypeNotSupported() throws Exception {
testHttpMediaTypeNotSupportedException("/person/1"); testHttpMediaTypeNotSupportedException("/person/1");
testHttpMediaTypeNotSupportedException("/person/1/"); testHttpMediaTypeNotSupportedException("/person/1/");
@ -197,18 +191,14 @@ public class RequestMappingInfoHandlerMappingTests {
} }
} }
// SPR-8462 @Test // SPR-8462
@Test
public void getHandlerMediaTypeNotAccepted() throws Exception { public void getHandlerMediaTypeNotAccepted() throws Exception {
testHttpMediaTypeNotAcceptableException("/persons"); testHttpMediaTypeNotAcceptableException("/persons");
testHttpMediaTypeNotAcceptableException("/persons/"); testHttpMediaTypeNotAcceptableException("/persons/");
testHttpMediaTypeNotAcceptableException("/persons.json"); testHttpMediaTypeNotAcceptableException("/persons.json");
} }
// SPR-12854 @Test // SPR-12854
@Test
public void getHandlerUnsatisfiedServletRequestParameterException() throws Exception { public void getHandlerUnsatisfiedServletRequestParameterException() throws Exception {
try { try {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/params"); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/params");
@ -275,10 +265,8 @@ public class RequestMappingInfoHandlerMappingTests {
assertEquals("2", uriVariables.get("path2")); assertEquals("2", uriVariables.get("path2"));
} }
// SPR-9098
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Test @Test // SPR-9098
public void handleMatchUriTemplateVariablesDecode() { public void handleMatchUriTemplateVariablesDecode() {
RequestMappingInfo key = RequestMappingInfo.paths("/{group}/{identifier}").build(); RequestMappingInfo key = RequestMappingInfo.paths("/{group}/{identifier}").build();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/group/a%2Fb"); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/group/a%2Fb");
@ -502,6 +490,7 @@ public class RequestMappingInfoHandlerMappingTests {
} }
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Controller @Controller
private static class UserController { private static class UserController {
@ -515,6 +504,7 @@ public class RequestMappingInfoHandlerMappingTests {
} }
} }
private static class TestRequestMappingInfoHandlerMapping extends RequestMappingInfoHandlerMapping { private static class TestRequestMappingInfoHandlerMapping extends RequestMappingInfoHandlerMapping {
public void registerHandler(Object handler) { public void registerHandler(Object handler) {

11
spring-websocket/src/main/java/org/springframework/web/socket/sockjs/support/AbstractSockJsService.java

@ -23,7 +23,6 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
@ -515,7 +514,7 @@ public abstract class AbstractSockJsService implements SockJsService, CorsConfig
protected void sendMethodNotAllowed(ServerHttpResponse response, HttpMethod... httpMethods) { protected void sendMethodNotAllowed(ServerHttpResponse response, HttpMethod... httpMethods) {
logger.warn("Sending Method Not Allowed (405)"); logger.warn("Sending Method Not Allowed (405)");
response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED); response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED);
response.getHeaders().setAllow(new HashSet<>(Arrays.asList(httpMethods))); response.getHeaders().setAllow(new LinkedHashSet<>(Arrays.asList(httpMethods)));
} }
@ -545,7 +544,7 @@ public abstract class AbstractSockJsService implements SockJsService, CorsConfig
@Override @Override
public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException { public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException {
if (HttpMethod.GET == request.getMethod()) { if (request.getMethod() == HttpMethod.GET) {
addNoCacheHeaders(response); addNoCacheHeaders(response);
if (checkOrigin(request, response)) { if (checkOrigin(request, response)) {
response.getHeaders().setContentType(new MediaType("application", "json", StandardCharsets.UTF_8)); response.getHeaders().setContentType(new MediaType("application", "json", StandardCharsets.UTF_8));
@ -555,14 +554,14 @@ public abstract class AbstractSockJsService implements SockJsService, CorsConfig
} }
} }
else if (HttpMethod.OPTIONS == request.getMethod()) { else if (request.getMethod() == HttpMethod.OPTIONS) {
if (checkOrigin(request, response)) { if (checkOrigin(request, response)) {
addCacheHeaders(response); addCacheHeaders(response);
response.setStatusCode(HttpStatus.NO_CONTENT); response.setStatusCode(HttpStatus.NO_CONTENT);
} }
} }
else { else {
sendMethodNotAllowed(response, HttpMethod.OPTIONS, HttpMethod.GET); sendMethodNotAllowed(response, HttpMethod.GET, HttpMethod.OPTIONS);
} }
} }
}; };
@ -590,7 +589,7 @@ public abstract class AbstractSockJsService implements SockJsService, CorsConfig
@Override @Override
public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException { public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException {
if (!HttpMethod.GET.equals(request.getMethod())) { if (request.getMethod() != HttpMethod.GET) {
sendMethodNotAllowed(response, HttpMethod.GET); sendMethodNotAllowed(response, HttpMethod.GET);
return; return;
} }

4
spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/TransportHandlingSockJsService.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -252,7 +252,7 @@ public class TransportHandlingSockJsService extends AbstractSockJsService implem
try { try {
HttpMethod supportedMethod = transportType.getHttpMethod(); HttpMethod supportedMethod = transportType.getHttpMethod();
if (supportedMethod != request.getMethod()) { if (supportedMethod != request.getMethod()) {
if (HttpMethod.OPTIONS == request.getMethod() && transportType.supportsCors()) { if (request.getMethod() == HttpMethod.OPTIONS && transportType.supportsCors()) {
if (checkOrigin(request, response, HttpMethod.OPTIONS, supportedMethod)) { if (checkOrigin(request, response, HttpMethod.OPTIONS, supportedMethod)) {
response.setStatusCode(HttpStatus.NO_CONTENT); response.setStatusCode(HttpStatus.NO_CONTENT);
addCacheHeaders(response); addCacheHeaders(response);

Loading…
Cancel
Save