提交 ae0b7c26 编写于 作者: J Juergen Hoeller

Drop Servlet 2.5 runtime compatibility

Issue: SPR-13189
上级 ff6ead1f
......@@ -39,11 +39,6 @@ import org.springframework.util.CollectionUtils;
*/
public class ServletServerHttpResponse implements ServerHttpResponse {
/** Checking for Servlet 3.0+ HttpServletResponse.getHeader(String) */
private static final boolean servlet3Present =
ClassUtils.hasMethod(HttpServletResponse.class, "getHeader", String.class);
private final HttpServletResponse servletResponse;
private final HttpHeaders headers;
......@@ -60,7 +55,7 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
public ServletServerHttpResponse(HttpServletResponse servletResponse) {
Assert.notNull(servletResponse, "HttpServletResponse must not be null");
this.servletResponse = servletResponse;
this.headers = (servlet3Present ? new ServletResponseHttpHeaders() : new HttpHeaders());
this.headers = new ServletResponseHttpHeaders();
}
......
......@@ -22,7 +22,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
......@@ -116,9 +115,9 @@ public class WebRequestDataBinder extends WebDataBinder {
if (multipartRequest != null) {
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
}
else if (ClassUtils.hasMethod(HttpServletRequest.class, "getParts")) {
HttpServletRequest serlvetRequest = ((NativeWebRequest) request).getNativeRequest(HttpServletRequest.class);
new Servlet3MultipartHelper(isBindEmptyMultipartFiles()).bindParts(serlvetRequest, mpvs);
else {
HttpServletRequest servletRequest = ((NativeWebRequest) request).getNativeRequest(HttpServletRequest.class);
bindParts(servletRequest, mpvs);
}
}
doBind(mpvs);
......@@ -133,6 +132,29 @@ public class WebRequestDataBinder extends WebDataBinder {
return (contentType != null && StringUtils.startsWithIgnoreCase(contentType, "multipart"));
}
private void bindParts(HttpServletRequest request, MutablePropertyValues mpvs) {
try {
MultiValueMap<String, Part> map = new LinkedMultiValueMap<String, Part>();
for (Part part : request.getParts()) {
map.add(part.getName(), part);
}
for (Map.Entry<String, List<Part>> entry: map.entrySet()) {
if (entry.getValue().size() == 1) {
Part part = entry.getValue().get(0);
if (isBindEmptyMultipartFiles() || part.getSize() > 0) {
mpvs.add(entry.getKey(), part);
}
}
else {
mpvs.add(entry.getKey(), entry.getValue());
}
}
}
catch (Exception ex) {
throw new MultipartException("Failed to get request parts", ex);
}
}
/**
* Treats errors as fatal.
* <p>Use this method only if it's an error if the input isn't valid.
......@@ -145,41 +167,4 @@ public class WebRequestDataBinder extends WebDataBinder {
}
}
/**
* Encapsulate Part binding code for Servlet 3.0+ only containers.
* @see javax.servlet.http.Part
*/
private static class Servlet3MultipartHelper {
private final boolean bindEmptyMultipartFiles;
public Servlet3MultipartHelper(boolean bindEmptyMultipartFiles) {
this.bindEmptyMultipartFiles = bindEmptyMultipartFiles;
}
public void bindParts(HttpServletRequest request, MutablePropertyValues mpvs) {
try {
MultiValueMap<String, Part> map = new LinkedMultiValueMap<String, Part>();
for (Part part : request.getParts()) {
map.add(part.getName(), part);
}
for (Map.Entry<String, List<Part>> entry: map.entrySet()) {
if (entry.getValue().size() == 1) {
Part part = entry.getValue().get(0);
if (this.bindEmptyMultipartFiles || part.getSize() > 0) {
mpvs.add(entry.getKey(), part);
}
}
else {
mpvs.add(entry.getKey(), entry.getValue());
}
}
}
catch (Exception ex) {
throw new MultipartException("Failed to get request parts", ex);
}
}
}
}
......@@ -23,14 +23,12 @@ import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
......@@ -73,10 +71,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
private static final Pattern ETAG_HEADER_VALUE_PATTERN = Pattern.compile("\\*|\\s*((W\\/)?(\"[^\"]*\"))\\s*,?");
/** Checking for Servlet 3.0+ HttpServletResponse.getHeader(String) */
private static final boolean servlet3Present =
ClassUtils.hasMethod(HttpServletResponse.class, "getHeader", String.class);
private boolean notModified = false;
......@@ -283,19 +277,19 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
private boolean isCompatibleWithConditionalRequests(HttpServletResponse response) {
try {
if (response == null || !servlet3Present) {
if (response == null) {
// Can't check response.getStatus() - let's assume we're good
return true;
}
return HttpStatus.valueOf(response.getStatus()).is2xxSuccessful();
}
catch (IllegalArgumentException e) {
catch (IllegalArgumentException ex) {
return true;
}
}
private boolean isHeaderAbsent(HttpServletResponse response, String header) {
if (response == null || !servlet3Present) {
if (response == null) {
// Can't check response.getHeader(header) - let's assume it's not set
return true;
}
......
/*
* Copyright 2002-2015 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.context.request.async;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.context.request.ServletWebRequest;
/**
* An {@code AsyncWebRequest} to use when there is no underlying async support.
*
* @author Rossen Stoyanchev
* @since 3.2
*/
public class NoSupportAsyncWebRequest extends ServletWebRequest implements AsyncWebRequest {
public NoSupportAsyncWebRequest(HttpServletRequest request, HttpServletResponse response) {
super(request, response);
}
@Override
public void addCompletionHandler(Runnable runnable) {
// ignored
}
@Override
public void setTimeout(Long timeout) {
// ignored
}
@Override
public void addTimeoutHandler(Runnable runnable) {
// ignored
}
@Override
public boolean isAsyncStarted() {
return false;
}
// Not supported
@Override
public void startAsync() {
throw new UnsupportedOperationException("No async support in a pre-Servlet 3.0 runtime");
}
@Override
public boolean isAsyncComplete() {
throw new UnsupportedOperationException("No async support in a pre-Servlet 3.0 runtime");
}
@Override
public void dispatch() {
throw new UnsupportedOperationException("No async support in a pre-Servlet 3.0 runtime");
}
}
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
......@@ -20,7 +20,6 @@ import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.ClassUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.WebRequest;
......@@ -35,9 +34,6 @@ public abstract class WebAsyncUtils {
public static final String WEB_ASYNC_MANAGER_ATTRIBUTE = WebAsyncManager.class.getName() + ".WEB_ASYNC_MANAGER";
// Determine whether Servlet 3.0's ServletRequest.startAsync method is available
private static final boolean startAsyncAvailable = ClassUtils.hasMethod(ServletRequest.class, "startAsync");
/**
* Obtain the {@link WebAsyncManager} for the current request, or if not
......@@ -76,19 +72,7 @@ public abstract class WebAsyncUtils {
* @return an AsyncWebRequest instance (never {@code null})
*/
public static AsyncWebRequest createAsyncWebRequest(HttpServletRequest request, HttpServletResponse response) {
return (startAsyncAvailable ? AsyncWebRequestFactory.createStandardAsyncWebRequest(request, response) :
new NoSupportAsyncWebRequest(request, response));
}
/**
* Inner class to avoid a hard dependency on the Servlet 3.0 API.
*/
private static class AsyncWebRequestFactory {
public static AsyncWebRequest createStandardAsyncWebRequest(HttpServletRequest request, HttpServletResponse response) {
return new StandardServletAsyncWebRequest(request, response);
}
return new StandardServletAsyncWebRequest(request, response);
}
}
......@@ -19,7 +19,6 @@ package org.springframework.web.filter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
......@@ -29,7 +28,6 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpMethod;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.DigestUtils;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;
......@@ -61,29 +59,30 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
private static final String STREAMING_ATTRIBUTE = ShallowEtagHeaderFilter.class.getName() + ".STREAMING";
/** Checking for Servlet 3.0+ HttpServletResponse.getHeader(String) */
private static final boolean servlet3Present =
ClassUtils.hasMethod(HttpServletResponse.class, "getHeader", String.class);
private boolean writeWeakETag = false;
/**
* Set whether the ETag value written to the response should be weak, as per rfc7232.
* Set whether the ETag value written to the response should be weak, as per RFC 7232.
* <p>Should be configured using an {@code <init-param>} for parameter name
* "writeWeakETag" in the filter definition in {@code web.xml}.
* @see <a href="https://tools.ietf.org/html/rfc7232#section-2.3">rfc7232 section-2.3</a>
* @see <a href="https://tools.ietf.org/html/rfc7232#section-2.3">RFC 7232 section 2.3</a>
* @since 4.3
*/
public boolean isWriteWeakETag() {
return writeWeakETag;
public void setWriteWeakETag(boolean writeWeakETag) {
this.writeWeakETag = writeWeakETag;
}
/**
* Return whether the ETag value written to the response should be weak, as per rfc7232.
* Return whether the ETag value written to the response should be weak, as per RFC 7232.
* @since 4.3
*/
public void setWriteWeakETag(boolean writeWeakETag) {
this.writeWeakETag = writeWeakETag;
public boolean isWriteWeakETag() {
return this.writeWeakETag;
}
/**
* The default value is "false" so that the filter may delay the generation of
* an ETag until the last asynchronously dispatched thread.
......@@ -169,10 +168,7 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
if (responseStatusCode >= 200 && responseStatusCode < 300 &&
(HttpMethod.GET.matches(method) || HttpMethod.HEAD.matches(method))) {
String cacheControl = null;
if (servlet3Present) {
cacheControl = response.getHeader(HEADER_CACHE_CONTROL);
}
String cacheControl = response.getHeader(HEADER_CACHE_CONTROL);
if (cacheControl == null || !cacheControl.contains(DIRECTIVE_NO_STORE)) {
return true;
}
......
......@@ -24,8 +24,6 @@ import javax.servlet.http.Part;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.util.ClassUtils;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.util.WebUtils;
......@@ -42,20 +40,6 @@ public abstract class MultipartResolutionDelegate {
public static final Object UNRESOLVABLE = new Object();
private static Class<?> servletPartClass = null;
static {
try {
servletPartClass = ClassUtils.forName("javax.servlet.http.Part",
MultipartResolutionDelegate.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
// Servlet 3.0 javax.servlet.http.Part type not available -
// Part references simply not supported then.
}
}
public static boolean isMultipartRequest(HttpServletRequest request) {
return (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null ||
isMultipartContent(request));
......@@ -71,15 +55,7 @@ public abstract class MultipartResolutionDelegate {
if (unwrapped != null) {
return unwrapped;
}
return adaptToMultipartHttpServletRequest(request);
}
private static MultipartHttpServletRequest adaptToMultipartHttpServletRequest(HttpServletRequest request) {
if (servletPartClass != null) {
// Servlet 3.0 available ..
return new StandardMultipartHttpServletRequest(request);
}
throw new MultipartException("Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
return new StandardMultipartHttpServletRequest(request);
}
......@@ -87,8 +63,7 @@ public abstract class MultipartResolutionDelegate {
Class<?> paramType = parameter.getNestedParameterType();
return (MultipartFile.class == paramType ||
isMultipartFileCollection(parameter) || isMultipartFileArray(parameter) ||
(servletPartClass != null && (servletPartClass == paramType ||
isPartCollection(parameter) || isPartArray(parameter))));
(Part.class == paramType || isPartCollection(parameter) || isPartArray(parameter)));
}
public static Object resolveMultipartArgument(String name, MethodParameter parameter, HttpServletRequest request)
......@@ -100,19 +75,19 @@ public abstract class MultipartResolutionDelegate {
if (MultipartFile.class == parameter.getNestedParameterType()) {
if (multipartRequest == null && isMultipart) {
multipartRequest = adaptToMultipartHttpServletRequest(request);
multipartRequest = new StandardMultipartHttpServletRequest(request);
}
return (multipartRequest != null ? multipartRequest.getFile(name) : null);
}
else if (isMultipartFileCollection(parameter)) {
if (multipartRequest == null && isMultipart) {
multipartRequest = adaptToMultipartHttpServletRequest(request);
multipartRequest = new StandardMultipartHttpServletRequest(request);
}
return (multipartRequest != null ? multipartRequest.getFiles(name) : null);
}
else if (isMultipartFileArray(parameter)) {
if (multipartRequest == null && isMultipart) {
multipartRequest = adaptToMultipartHttpServletRequest(request);
multipartRequest = new StandardMultipartHttpServletRequest(request);
}
if (multipartRequest != null) {
List<MultipartFile> multipartFiles = multipartRequest.getFiles(name);
......@@ -122,7 +97,7 @@ public abstract class MultipartResolutionDelegate {
return null;
}
}
else if (parameter.getNestedParameterType() == servletPartClass) {
else if (Part.class == parameter.getNestedParameterType()) {
return (isMultipart ? RequestPartResolver.resolvePart(request, name) : null);
}
else if (isPartCollection(parameter)) {
......@@ -145,11 +120,11 @@ public abstract class MultipartResolutionDelegate {
}
private static boolean isPartCollection(MethodParameter methodParam) {
return (servletPartClass == getCollectionParameterType(methodParam));
return (Part.class == getCollectionParameterType(methodParam));
}
private static boolean isPartArray(MethodParameter methodParam) {
return (servletPartClass == methodParam.getNestedParameterType().getComponentType());
return (Part.class == methodParam.getNestedParameterType().getComponentType());
}
private static Class<?> getCollectionParameterType(MethodParameter methodParam) {
......
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
......@@ -145,7 +145,6 @@ public class CookieGenerator {
/**
* Set whether the cookie is supposed to be marked with the "HttpOnly" attribute.
* <p>Note that this feature is only available on Servlet 3.0 and higher.
* @see javax.servlet.http.Cookie#setHttpOnly
*/
public void setCookieHttpOnly(boolean cookieHttpOnly) {
......
......@@ -162,11 +162,6 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
private static final String INIT_PARAM_DELIMITERS = ",; \t\n";
/** Checking for Servlet 3.0+ HttpServletResponse.getStatus() */
private static final boolean responseGetStatusAvailable =
ClassUtils.hasMethod(HttpServletResponse.class, "getStatus");
/** ServletContext attribute to find the WebApplicationContext in */
private String contextAttribute;
......@@ -912,8 +907,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
}
}
// Use response wrapper for Servlet 2.5 compatibility where
// the getHeader() method does not exist
// Use response wrapper in order to always add PATCH to the allowed methods
super.doOptions(request, new HttpServletResponseWrapper(response) {
@Override
public void setHeader(String name, String value) {
......@@ -1069,13 +1063,12 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
if (this.publishEvents) {
// Whether or not we succeeded, publish an event.
long processingTime = System.currentTimeMillis() - startTime;
int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);
this.webApplicationContext.publishEvent(
new ServletRequestHandledEvent(this,
request.getRequestURI(), request.getRemoteAddr(),
request.getMethod(), getServletConfig().getServletName(),
WebUtils.getSessionId(request), getUsernameForRequest(request),
processingTime, failureCause, statusCode));
processingTime, failureCause, response.getStatus()));
}
}
......
......@@ -80,10 +80,6 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
protected static final String HEADER_CACHE_CONTROL = "Cache-Control";
/** Checking for Servlet 3.0+ HttpServletResponse.getHeaders(String) */
private static final boolean servlet3Present =
ClassUtils.hasMethod(HttpServletResponse.class, "getHeaders", String.class);
/** Set of supported HTTP methods */
private Set<String> supportedMethods;
......@@ -263,8 +259,6 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
* subject to content negotiation and variances based on the value of the
* given request headers. The configured request header names are added only
* if not already present in the response "Vary" header.
* <p><strong>Note:</strong> This property is only supported on Servlet 3.0+
* which allows checking existing response header values.
* @param varyByRequestHeaders one or more request header names
* @since 4.3
*/
......@@ -398,7 +392,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
else {
applyCacheSeconds(response, this.cacheSeconds);
}
if (servlet3Present && this.varyByRequestHeaders != null) {
if (this.varyByRequestHeaders != null) {
for (String value : getVaryRequestHeadersToAdd(response)) {
response.addHeader("Vary", value);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册