Add support for POST, clean up request impl, add test
This commit is contained in:
@@ -27,7 +27,6 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.security.Principal;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
@@ -41,10 +40,10 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
@@ -60,21 +59,15 @@ import javax.servlet.http.Part;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
|
||||
private static final String HTTP = "http";
|
||||
|
||||
private static final String HTTPS = "https";
|
||||
|
||||
private static final String CHARSET_PREFIX = "charset=";
|
||||
|
||||
private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
|
||||
@@ -90,53 +83,6 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
private static final String[] DATE_FORMATS = new String[] { "EEE, dd MMM yyyy HH:mm:ss zzz",
|
||||
"EEE, dd-MMM-yy HH:mm:ss zzz", "EEE MMM dd HH:mm:ss yyyy" };
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Public constants
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The default protocol: 'HTTP/1.1'.
|
||||
*
|
||||
* @since 4.3.7
|
||||
*/
|
||||
public static final String DEFAULT_PROTOCOL = "HTTP/1.1";
|
||||
|
||||
/**
|
||||
* The default scheme: 'http'.
|
||||
*
|
||||
* @since 4.3.7
|
||||
*/
|
||||
public static final String DEFAULT_SCHEME = HTTP;
|
||||
|
||||
/**
|
||||
* The default server address: '127.0.0.1'.
|
||||
*/
|
||||
public static final String DEFAULT_SERVER_ADDR = "127.0.0.1";
|
||||
|
||||
/**
|
||||
* The default server name: 'localhost'.
|
||||
*/
|
||||
public static final String DEFAULT_SERVER_NAME = "localhost";
|
||||
|
||||
/**
|
||||
* The default server port: '80'.
|
||||
*/
|
||||
public static final int DEFAULT_SERVER_PORT = 80;
|
||||
|
||||
/**
|
||||
* The default remote address: '127.0.0.1'.
|
||||
*/
|
||||
public static final String DEFAULT_REMOTE_ADDR = "127.0.0.1";
|
||||
|
||||
/**
|
||||
* The default remote host: 'localhost'.
|
||||
*/
|
||||
public static final String DEFAULT_REMOTE_HOST = "localhost";
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Lifecycle properties
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private final ServletContext servletContext;
|
||||
|
||||
private boolean active = true;
|
||||
@@ -224,26 +170,7 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
|
||||
private final MultiValueMap<String, Part> parts = new LinkedMultiValueMap<>();
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Constructors
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a new {@code MockHttpServletRequest} with the supplied
|
||||
* {@link ServletContext}, {@code method}, and {@code requestURI}.
|
||||
* <p>
|
||||
* The preferred locale will be set to {@link Locale#ENGLISH}.
|
||||
*
|
||||
* @param servletContext the ServletContext that the request runs in (may be
|
||||
* {@code null} to use a default
|
||||
* {@link MockServletContext})
|
||||
* @param method the request method (may be {@code null})
|
||||
* @param requestURI the request URI (may be {@code null})
|
||||
* @see #setMethod
|
||||
* @see #setRequestURI
|
||||
* @see #setPreferredLocales
|
||||
* @see MockServletContext
|
||||
*/
|
||||
public ProxyHttpServletRequest(ServletContext servletContext, String method, String requestURI) {
|
||||
this.servletContext = servletContext;
|
||||
this.method = method;
|
||||
@@ -251,10 +178,6 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
this.locales.add(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Lifecycle methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return the ServletContext that this request is associated with. (Not
|
||||
* available in the standard HttpServletRequest interface for some reason.)
|
||||
@@ -264,49 +187,13 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
return this.servletContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this request is still active (that is, not completed yet).
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this request as completed, keeping its state.
|
||||
*/
|
||||
public void close() {
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate this request, clearing its state.
|
||||
*/
|
||||
public void invalidate() {
|
||||
close();
|
||||
clearAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this request is still active (that is, not completed yet),
|
||||
* throwing an IllegalStateException if not active anymore.
|
||||
*/
|
||||
protected void checkActive() throws IllegalStateException {
|
||||
Assert.state(this.active, "Request is not active anymore");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// ServletRequest interface
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name) {
|
||||
checkActive();
|
||||
return this.attributes.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getAttributeNames() {
|
||||
checkActive();
|
||||
return Collections.enumeration(new LinkedHashSet<>(this.attributes.keySet()));
|
||||
}
|
||||
|
||||
@@ -426,7 +313,34 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() {
|
||||
throw new UnsupportedOperationException();
|
||||
InputStream stream = new ByteArrayInputStream(this.content);
|
||||
return new ServletInputStream() {
|
||||
|
||||
boolean finished = false;
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int readByte = stream.read();
|
||||
if (readByte == -1) {
|
||||
finished = true;
|
||||
}
|
||||
return readByte;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return !finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return finished;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -561,19 +475,8 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
return Collections.unmodifiableMap(this.parameters);
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
// this.protocol = protocol;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
// return this.protocol;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void setScheme(String scheme) {
|
||||
// this.scheme = scheme;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@@ -643,7 +546,6 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, @Nullable Object value) {
|
||||
checkActive();
|
||||
Assert.notNull(name, "Attribute name must not be null");
|
||||
if (value != null) {
|
||||
this.attributes.put(name, value);
|
||||
@@ -655,7 +557,6 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
checkActive();
|
||||
Assert.notNull(name, "Attribute name must not be null");
|
||||
this.attributes.remove(name);
|
||||
}
|
||||
@@ -795,7 +696,6 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
|
||||
@Override
|
||||
public int getLocalPort() {
|
||||
// return this.localPort;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@@ -846,10 +746,6 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
return this.dispatcherType;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// HttpServletRequest interface
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
public void setAuthType(@Nullable String authType) {
|
||||
this.authType = authType;
|
||||
}
|
||||
@@ -860,21 +756,6 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
return this.authType;
|
||||
}
|
||||
|
||||
public void setCookies(@Nullable Cookie... cookies) {
|
||||
this.cookies = (ObjectUtils.isEmpty(cookies) ? null : cookies);
|
||||
if (this.cookies == null) {
|
||||
removeHeader(HttpHeaders.COOKIE);
|
||||
}
|
||||
else {
|
||||
doAddHeaderValue(HttpHeaders.COOKIE, encodeCookies(this.cookies), true);
|
||||
}
|
||||
}
|
||||
|
||||
private static String encodeCookies(@NonNull Cookie... cookies) {
|
||||
return Arrays.stream(cookies).map(c -> c.getName() + '=' + (c.getValue() == null ? "" : c.getValue()))
|
||||
.collect(Collectors.joining("; "));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Cookie[] getCookies() {
|
||||
@@ -945,16 +826,6 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove already registered entries for the specified HTTP header, if any.
|
||||
*
|
||||
* @since 4.3.20
|
||||
*/
|
||||
public void removeHeader(String name) {
|
||||
Assert.notNull(name, "Header name must not be null");
|
||||
this.headers.remove(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the long timestamp for the date header with the given {@code name}.
|
||||
* <p>
|
||||
@@ -1104,8 +975,6 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
@Override
|
||||
public boolean isUserInRole(String role) {
|
||||
throw new UnsupportedOperationException();
|
||||
// return (this.userRoles.contains(role) || (this.servletContext instanceof MockServletContext &&
|
||||
// ((MockServletContext) this.servletContext).getDeclaredRoles().contains(role)));
|
||||
}
|
||||
|
||||
public void setUserPrincipal(@Nullable Principal userPrincipal) {
|
||||
@@ -1140,20 +1009,7 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
|
||||
@Override
|
||||
public StringBuffer getRequestURL() {
|
||||
String scheme = getScheme();
|
||||
String server = getServerName();
|
||||
int port = getServerPort();
|
||||
String uri = getRequestURI();
|
||||
|
||||
StringBuffer url = new StringBuffer(scheme).append("://").append(server);
|
||||
if (port > 0
|
||||
&& ((HTTP.equalsIgnoreCase(scheme) && port != 80) || (HTTPS.equalsIgnoreCase(scheme) && port != 443))) {
|
||||
url.append(':').append(port);
|
||||
}
|
||||
if (StringUtils.hasText(uri)) {
|
||||
url.append(uri);
|
||||
}
|
||||
return url;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void setServletPath(String servletPath) {
|
||||
@@ -1166,28 +1022,13 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
}
|
||||
|
||||
public void setSession(HttpSession session) {
|
||||
// this.session = session;
|
||||
// if (session instanceof MockHttpSession) {
|
||||
// MockHttpSession mockSession = ((MockHttpSession) session);
|
||||
// mockSession.access();
|
||||
// }
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public HttpSession getSession(boolean create) {
|
||||
checkActive();
|
||||
// Reset session if invalidated.
|
||||
// if (this.session instanceof MockHttpSession && ((MockHttpSession) this.session).isInvalid()) {
|
||||
// this.session = null;
|
||||
// }
|
||||
// // Create new session if necessary.
|
||||
// if (this.session == null && create) {
|
||||
// this.session = new MockHttpSession(this.servletContext);
|
||||
// }
|
||||
return this.session;
|
||||
// throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1196,20 +1037,8 @@ public class ProxyHttpServletRequest implements HttpServletRequest {
|
||||
return getSession(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* The implementation of this (Servlet 3.1+) method calls
|
||||
* {@link MockHttpSession#changeSessionId()} if the session is a mock session.
|
||||
* Otherwise it simply returns the current session id.
|
||||
*
|
||||
* @since 4.0.3
|
||||
*/
|
||||
@Override
|
||||
public String changeSessionId() {
|
||||
// Assert.isTrue(this.session != null, "The request does not have a session");
|
||||
// if (this.session instanceof MockHttpSession) {
|
||||
// return ((MockHttpSession) this.session).changeSessionId();
|
||||
// }
|
||||
// return this.session.getId();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
public class ProxyMvc {
|
||||
@@ -45,6 +46,8 @@ public class ProxyMvc {
|
||||
|
||||
private final Filter[] filters;
|
||||
|
||||
private final ConfigurableWebApplicationContext applicationContext;
|
||||
|
||||
@Nullable
|
||||
private Charset defaultResponseCharacterEncoding;
|
||||
|
||||
@@ -53,13 +56,16 @@ public class ProxyMvc {
|
||||
*
|
||||
* @see org.springframework.test.web.servlet.setup.MockMvcBuilders
|
||||
*/
|
||||
public ProxyMvc(DispatcherServlet servlet, Filter... filters) {
|
||||
public ProxyMvc(DispatcherServlet servlet, ConfigurableWebApplicationContext applicationContext) {
|
||||
Assert.notNull(servlet, "DispatcherServlet is required");
|
||||
Assert.notNull(filters, "Filters cannot be null");
|
||||
Assert.noNullElements(filters, "Filters cannot contain null values");
|
||||
this.applicationContext = applicationContext;
|
||||
|
||||
this.servlet = servlet;
|
||||
this.filters = filters;
|
||||
this.filters = applicationContext.getBeansOfType(Filter.class).values().toArray(new Filter[0]);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
this.applicationContext.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,11 +107,15 @@ public class ProxyMvc {
|
||||
* @see org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
* @see org.springframework.test.web.servlet.result.MockMvcResultMatchers
|
||||
*/
|
||||
public void perform(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
public void service(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
ProxyFilterChain filterChain = new ProxyFilterChain(this.servlet, this.filters);
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
public ConfigurableWebApplicationContext getApplicationContext() {
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
private static class ProxyFilterChain implements FilterChain {
|
||||
|
||||
@Nullable
|
||||
|
||||
Reference in New Issue
Block a user