/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you 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.apache.click.servlet; | |
import java.io.BufferedReader; | |
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.CharArrayReader; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.IOException; | |
import java.io.OutputStream; | |
import java.io.UnsupportedEncodingException; | |
import java.net.URLEncoder; | |
import java.security.Principal; | |
import java.text.DateFormat; | |
import java.text.ParseException; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.Enumeration; | |
import java.util.HashMap; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Locale; | |
import java.util.Map; | |
import java.util.Random; | |
import javax.servlet.RequestDispatcher; | |
import javax.servlet.ServletContext; | |
import javax.servlet.ServletInputStream; | |
import javax.servlet.http.Cookie; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpSession; | |
import org.apache.click.util.ClickUtils; | |
import org.apache.commons.fileupload.FileUploadBase; | |
import org.apache.commons.io.IOUtils; | |
import org.apache.commons.lang.StringUtils; | |
/** | |
* Mock implementation of {@link javax.servlet.http.HttpServletRequest}. | |
* <p/> | |
* Implements all of the methods from the standard HttpServletRequest class | |
* plus helper methods to aid setting up a request. | |
* <p/> | |
* This class was adapted from <a href="http://wicket.apache.org">Apache Wicket</a>. | |
*/ | |
public class MockRequest implements HttpServletRequest { | |
// -------------------------------------------------------- Constants | |
/** Newline indicator. */ | |
private static final String CRLF = "\r\n"; | |
/** File attachment boundary indicator. */ | |
private static final String BOUNDARY = "--abcdefgABCDEFG"; | |
/** The REMOTE_USER header. */ | |
public static final String REMOTE_USER = "REMOTE_USER"; | |
// -------------------------------------------------------- Variables | |
/** The request default locale. */ | |
private Locale locale = Locale.getDefault(); | |
/** The request attributes map. */ | |
private final Map<String, Object> attributes = new HashMap<String, Object>(); | |
/** The request authentication type (BASIC, FORM, DIGEST, CLIENT_CERT). */ | |
private String authType; | |
/** The request character encoding. */ | |
private String characterEncoding; | |
/** The request servlet context. */ | |
private ServletContext servletContext; | |
/** The request list of cookies. */ | |
private final List<Cookie> cookies = new ArrayList<Cookie>(); | |
/** The request headers map. */ | |
private final Map<String, List<String>> headers = new HashMap<String, List<String>>(); | |
/** The name of the HTTP method with which this request was made. */ | |
private String method = "POST"; | |
/** The request parameter map. */ | |
private final Map<String, Object> parameters = new HashMap<String, Object>(); | |
/** The request HTTP session. */ | |
private HttpSession session; | |
/** | |
* Map of uploaded files, where the fieldname is the key and uploaded file | |
* is the value. | |
*/ | |
private Map<String, UploadedFile> uploadedFiles = new HashMap<String, UploadedFile>(); | |
/** | |
* Indicates if this request is multipart (contains binary attachment) or | |
* not, false by default. | |
*/ | |
private boolean useMultiPartContentType; | |
/** The url that was forwarded to. */ | |
private String forward; | |
/** The list of server side included url's. */ | |
private List<String> includes = new ArrayList<String>(); | |
/** The scheme used to make this request, defaults to "http". */ | |
private String scheme = "http"; | |
/** The request context path, defaults to {@link MockServletContext#DEFAULT_CONTEXT_PATH}. */ | |
private String contextPath = MockServletContext.DEFAULT_CONTEXT_PATH; | |
/** The request servlet path, defaults to an empty String "". */ | |
private String servletPath = ""; | |
/** The request path info, defaults to an empty String "". */ | |
private String pathInfo = ""; | |
/** The host name to which the request was sent, defaults to "localhost". */ | |
private String serverName = "localhost"; | |
/** The port number to which the request was sent, defaults to 8080. */ | |
private int serverPort = 8080; | |
/** A random number generator to create unique session id's. */ | |
private Random random = new Random(); | |
/** The user principal. */ | |
private Principal userPrincipal; | |
/** | |
* Create new MockRequest. | |
*/ | |
public MockRequest() { | |
initialize(); | |
} | |
/** | |
* Create new MockRequest for the specified local. | |
* | |
* @param locale locale for this request | |
*/ | |
public MockRequest(final Locale locale) { | |
this(locale, null); | |
} | |
/** | |
* Create a new MockRequest for the specified context. | |
* | |
* @param servletContext the servletContext for this request | |
*/ | |
public MockRequest(final ServletContext servletContext) { | |
this(null, servletContext); | |
} | |
/** | |
* Create a new MockRequest for the specified locale and servletContext. | |
* | |
* @param locale locale for this request | |
* @param servletContext the servletContext for this request | |
*/ | |
public MockRequest(final Locale locale, final ServletContext servletContext) { | |
this(locale, servletContext, null); | |
} | |
/** | |
* Create a new MockRequest for the specified arguments. | |
* | |
* @param locale The request locale, or null to use the default locale | |
* @param session The session object | |
* @param servletContext The current servlet context | |
*/ | |
public MockRequest(final Locale locale, final ServletContext servletContext, | |
final HttpSession session) { | |
this(locale, MockServletContext.DEFAULT_CONTEXT_PATH, "", servletContext, session); | |
} | |
/** | |
* Create a new MockRequest for the specified arguments. | |
* | |
* @param locale The request locale, or null to use the default locale | |
* @param contextPath the request context path | |
* @param servletPath the request servlet path | |
* @param servletContext The current servlet context | |
* @param session the request session | |
*/ | |
public MockRequest(Locale locale, String contextPath, String servletPath, | |
final ServletContext servletContext, final HttpSession session) { | |
if (locale != null) { | |
this.locale = locale; | |
} | |
this.contextPath = contextPath; | |
this.servletPath = servletPath; | |
this.session = session; | |
this.servletContext = servletContext; | |
initialize(); | |
} | |
// -------------------------------------------------------- Mock intialization methods | |
/** | |
* Set the request's servletContext instance. | |
* | |
* @param servletContext the new ServletContext instance | |
*/ | |
public void setServletContext(ServletContext servletContext) { | |
this.servletContext = servletContext; | |
} | |
/** | |
* Set the request's session instance. | |
* | |
* @param session the new HttpSession instance | |
*/ | |
public void setHttpSession(HttpSession session) { | |
this.session = session; | |
} | |
/** | |
* Add a new cookie. | |
* | |
* @param cookie The cookie | |
*/ | |
public void addCookie(final Cookie cookie) { | |
cookies.add(cookie); | |
} | |
/** | |
* Add an uploaded file to the request. Use this to simulate a file that | |
* has been uploaded to a field. | |
* | |
* @param fieldName The fieldname of the upload field. | |
* @param file The file to upload. | |
* @param contentType The content type of the file. Must be a correct | |
* mimetype. | |
*/ | |
public void addFile(String fieldName, File file, String contentType) { | |
if (file == null) { | |
throw new IllegalArgumentException("File must not be null"); | |
} | |
if (file.exists() == false) { | |
throw new IllegalArgumentException( | |
"File does not exist. You must provide an existing file: " | |
+ file.getAbsolutePath()); | |
} | |
if (file.isFile() == false) { | |
throw new IllegalArgumentException( | |
"You can only add a File, which is not a directory. Only files " | |
+ "can be uploaded."); | |
} | |
if (uploadedFiles == null) { | |
uploadedFiles = new HashMap<String, UploadedFile>(); | |
} | |
UploadedFile uf = new UploadedFile(fieldName, file, contentType); | |
uploadedFiles.put(fieldName, uf); | |
setUseMultiPartContentType(true); | |
} | |
/** | |
* Add a header to the request. | |
* | |
* @param name the name of the header to add | |
* @param value the value | |
*/ | |
public void addHeader(String name, String value) { | |
List<String> list = headers.get(name); | |
if (list == null) { | |
list = new ArrayList<String>(1); | |
headers.put(name, list); | |
} | |
list.add(value); | |
} | |
/** | |
* Set request header value. The existing header value will be replaced. | |
* | |
* @param name the name of the header to set | |
* @param value the header value | |
*/ | |
public void setHeader(String name, String value) { | |
setHeader(name, new String[] {value}); | |
} | |
/** | |
* Set request header values. The existing header values will be replaced. | |
* | |
* @param name the name of the header to set | |
* @param values the header values | |
*/ | |
public void setHeader(String name, String... values) { | |
List<String> list = new ArrayList<String>(values.length); | |
headers.put(name, list); | |
Collections.addAll(list, values); | |
} | |
/** | |
* Get an attribute. | |
* | |
* @param name The attribute name | |
* @return The value, or null | |
*/ | |
public Object getAttribute(final String name) { | |
return attributes.get(name); | |
} | |
/** | |
* Get the names of all of the values. | |
* | |
* @return The names | |
*/ | |
public Enumeration<String> getAttributeNames() { | |
return Collections.enumeration(attributes.keySet()); | |
} | |
// -------------------------------------------------------- HttpServletRequest methods | |
/** | |
* Get the auth type. | |
* | |
* @return The auth type | |
*/ | |
public String getAuthType() { | |
return authType; | |
} | |
/** | |
* Get the current character encoding. | |
* | |
* @return The character encoding | |
*/ | |
public String getCharacterEncoding() { | |
return characterEncoding; | |
} | |
/** | |
* True will force Request to generate multiPart ContentType and ContentLength. | |
* | |
* @param useMultiPartContentType true if the request is multi-part, false | |
* otherwise | |
*/ | |
public void setUseMultiPartContentType(boolean useMultiPartContentType) { | |
this.useMultiPartContentType = useMultiPartContentType; | |
} | |
/** | |
* Return the length of the content. This is always -1 except if | |
* useMultiPartContentType set as true. Then the length will be the length | |
* of the generated request. | |
* | |
* @return -1 if useMultiPartContentType is false. Else the length of the | |
* generated request. | |
*/ | |
public int getContentLength() { | |
if (useMultiPartContentType) { | |
byte[] request = buildRequest(); | |
return request.length; | |
} | |
return -1; | |
} | |
/** | |
* If useMultiPartContentType set as true return the correct content-type. | |
* | |
* @return The correct multipart content-type if useMultiPartContentType | |
* is true. Else null. | |
*/ | |
public String getContentType() { | |
if (useMultiPartContentType) { | |
return FileUploadBase.MULTIPART_FORM_DATA + "; boundary=abcdefgABCDEFG"; | |
} | |
return null; | |
} | |
/** | |
* Get all of the cookies for this request. | |
* | |
* @return The cookies | |
*/ | |
public Cookie[] getCookies() { | |
if (cookies.size() == 0) { | |
return null; | |
} | |
Cookie[] result = new Cookie[cookies.size()]; | |
return cookies.toArray(result); | |
} | |
/** | |
* Get the given header as a date. | |
* | |
* @param name The header name | |
* @return The date, or -1 if header not found | |
* @throws IllegalArgumentException If the header cannot be converted | |
*/ | |
public long getDateHeader(final String name) | |
throws IllegalArgumentException { | |
String value = getHeader(name); | |
if (value == null) { | |
return -1; | |
} | |
DateFormat df = DateFormat.getDateInstance(DateFormat.FULL); | |
try { | |
return df.parse(value).getTime(); | |
} catch (ParseException e) { | |
throw new IllegalArgumentException("Can't convert header to date " + name + ": " + value); | |
} | |
} | |
/** | |
* Get the given header value. | |
* | |
* @param name The header name | |
* @return The header value or null | |
*/ | |
public String getHeader(final String name) { | |
final List<String> l = headers.get(name); | |
if (l == null || l.size() < 1) { | |
return null; | |
} else { | |
return l.get(0); | |
} | |
} | |
/** | |
* Get the names of all of the headers. | |
* | |
* @return The header names | |
*/ | |
public Enumeration<String> getHeaderNames() { | |
return Collections.enumeration(headers.keySet()); | |
} | |
/** | |
* Get enumeration of all header values with the given name. | |
* | |
* @param name The name | |
* @return The header values | |
*/ | |
public Enumeration<String> getHeaders(final String name) { | |
List<String> list = headers.get(name); | |
if (list == null) { | |
list = new ArrayList<String>(); | |
} | |
return Collections.enumeration(list); | |
} | |
/** | |
* Return the map of headers for this request. | |
* | |
* @return the map of headers for this request | |
*/ | |
public Map<String, List<String>> getHeaders() { | |
return headers; | |
} | |
/** | |
* Returns an input stream if there has been added some uploaded files. Use | |
* {@link #addFile(String, File, String)} to add some uploaded files. | |
* | |
* @return The input stream | |
* @throws IOException If an I/O related problem occurs | |
*/ | |
public ServletInputStream getInputStream() throws IOException { | |
if (uploadedFiles != null && uploadedFiles.size() > 0) { | |
byte[] request = buildRequest(); | |
// Ok lets make an input stream to return | |
final ByteArrayInputStream bais = new ByteArrayInputStream(request); | |
return new ServletInputStream() { | |
@Override | |
public int read() { | |
return bais.read(); | |
} | |
}; | |
} else { | |
return new ServletInputStream() { | |
@Override | |
public int read() { | |
return -1; | |
} | |
}; | |
} | |
} | |
/** | |
* Get the given header as an int. | |
* | |
* @param name The header name | |
* @return The header value or -1 if header not found | |
* @throws NumberFormatException If the header is not formatted correctly | |
*/ | |
public int getIntHeader(final String name) { | |
String value = getHeader(name); | |
if (value == null) { | |
return -1; | |
} | |
return Integer.valueOf(value).intValue(); | |
} | |
/** | |
* Get the locale of the request. Attempts to decode the Accept-Language | |
* header and if not found returns the default locale of the JVM. | |
* | |
* @return The locale | |
*/ | |
public Locale getLocale() { | |
final String header = getHeader("Accept-Language"); | |
if (header == null) { | |
return Locale.getDefault(); | |
} | |
final String[] firstLocale = header.split(","); | |
if (firstLocale.length < 1) { | |
return Locale.getDefault(); | |
} | |
final String[] bits = firstLocale[0].split("-"); | |
if (bits.length < 1) { | |
return Locale.getDefault(); | |
} | |
final String language = bits[0].toLowerCase(); | |
if (bits.length > 1) { | |
final String country = bits[1].toUpperCase(); | |
return new Locale(language, country); | |
} else { | |
return new Locale(language); | |
} | |
} | |
/** | |
* Return all the accepted locales. This implementation always returns just | |
* one. | |
* | |
* @return The locales | |
*/ | |
public Enumeration<Locale> getLocales() { | |
List<Locale> list = new ArrayList<Locale>(1); | |
list.add(getLocale()); | |
return Collections.enumeration(list); | |
} | |
/** | |
* Get the method. | |
* <p/> | |
* The returned string will be in upper case eg. <tt>POST</tt>. | |
* | |
* @return The method | |
*/ | |
public String getMethod() { | |
return StringUtils.upperCase(method); | |
} | |
/** | |
* Get the request parameter with the given name. | |
* | |
* @param name The parameter name | |
* @return The parameter value, or null | |
*/ | |
public String getParameter(final String name) { | |
Object value = parameters.get(name); | |
if (value instanceof String[]) { | |
return ((String[]) value)[0]; | |
} else { | |
return (String) value; | |
} | |
} | |
/** | |
* Get the map of all of the parameters. | |
* | |
* @return The parameters | |
*/ | |
public Map<String, Object> getParameterMap() { | |
return parameters; | |
} | |
/** | |
* Get the names of all of the parameters. | |
* | |
* @return The parameter names | |
*/ | |
public Enumeration<String> getParameterNames() { | |
return Collections.enumeration(parameters.keySet()); | |
} | |
/** | |
* Get the values for the given parameter. | |
* | |
* @param name The name of the parameter | |
* @return The return values | |
*/ | |
public String[] getParameterValues(final String name) { | |
Object value = parameters.get(name); | |
if (value == null) { | |
return new String[0]; | |
} | |
if (value instanceof String[]) { | |
return (String[]) value; | |
} else { | |
String[] result = new String[1]; | |
result[0] = value.toString(); | |
return result; | |
} | |
} | |
/** | |
* Get the path info. | |
* | |
* @return The path info | |
*/ | |
public String getPathInfo() { | |
return pathInfo; | |
} | |
/** | |
* Always returns null. | |
* | |
* @return null | |
*/ | |
public String getPathTranslated() { | |
return null; | |
} | |
/** | |
* Get the protocol. | |
* | |
* @return Always HTTP/1.1 | |
*/ | |
public String getProtocol() { | |
return "HTTP/1.1"; | |
} | |
/** | |
* Get the query string part of the request. | |
* | |
* @return The query string | |
*/ | |
public String getQueryString() { | |
if (parameters.size() == 0) { | |
return null; | |
} else { | |
final StringBuffer buf = new StringBuffer(); | |
try { | |
for (Iterator<String> iterator = parameters.keySet().iterator(); iterator.hasNext();) { | |
final String name = iterator.next(); | |
final Object value = parameters.get(name); | |
if (value instanceof String[]) { | |
String[] aValue = (String[]) value; | |
for (int i = 0; i < aValue.length; i++) { | |
buf.append(URLEncoder.encode(name, "UTF-8")); | |
buf.append('='); | |
buf.append(URLEncoder.encode(aValue[i], "UTF-8")); | |
if (i < aValue.length) { | |
buf.append("&"); | |
} | |
} | |
} else { | |
buf.append(URLEncoder.encode(name, "UTF-8")); | |
buf.append('='); | |
buf.append(URLEncoder.encode((String) value, "UTF-8")); | |
} | |
if (iterator.hasNext()) { | |
buf.append("&"); | |
} | |
} | |
} catch (UnsupportedEncodingException e) { | |
// Should never happen! | |
} | |
return buf.toString(); | |
} | |
} | |
/** | |
* This feature is not implemented at this time as we are not supporting | |
* binary servlet input. This functionality may be added in the future. | |
* | |
* @return The reader | |
* @throws IOException If an I/O related problem occurs | |
*/ | |
public BufferedReader getReader() throws IOException { | |
return new BufferedReader(new CharArrayReader(new char[0])); | |
} | |
/** | |
* Deprecated method - should not be used. | |
* | |
* @param name The name | |
* | |
* @return The path | |
* | |
* @deprecated Use ServletContext.getRealPath(String) instead. | |
*/ | |
public String getRealPath(String name) { | |
return servletContext.getRealPath(name); | |
} | |
/** | |
* Get the remote address of the client. | |
* | |
* @return Always 127.0.0.1 | |
*/ | |
public String getRemoteAddr() { | |
return "127.0.0.1"; | |
} | |
/** | |
* Get the remote host. | |
* | |
* @return Always localhost | |
*/ | |
public String getRemoteHost() { | |
return "localhost"; | |
} | |
/** | |
* Return the name of the {@link #userPrincipal} if set, otherwise | |
* the value of the {@value #REMOTE_USER} header. | |
* <p/> | |
* To set the remote user, create an instance of a {@link MockPrincipal} | |
* and set it on the request through the method | |
* {@link #setUserPrincipal(java.security.Principal)}. | |
* | |
* @return the name of the remote user | |
*/ | |
public String getRemoteUser() { | |
if (userPrincipal != null) { | |
return userPrincipal.getName(); | |
} | |
return getHeader(REMOTE_USER); | |
} | |
/** | |
* Return the local address, <em>"127.0.0.1"</em>. | |
* | |
* @return "127.0.0.1" as the local address | |
*/ | |
public String getLocalAddr() { | |
return "127.0.0.1"; | |
} | |
/** | |
* Return the local name, <em>"127.0.0.1"</em>. | |
* | |
* @return "127.0.0.1" as the local name | |
*/ | |
public String getLocalName() { | |
return "127.0.0.1"; | |
} | |
/** | |
* Return the local port, <em>80</em>. | |
* | |
* @return 80 as the local port | |
*/ | |
public int getLocalPort() { | |
return 80; | |
} | |
/** | |
* Return the remote port, <em>80</em>. | |
* | |
* @return 80 as the remote port | |
*/ | |
public int getRemotePort() { | |
return 80; | |
} | |
/** | |
* Returns a RequestDispatcher for the specified path. The dispatcher | |
* will not dispatch to the resource. It only records the specified path | |
* so that one can test if the correct path was dispatched to. | |
* | |
* @param path a String specifying the pathname to the resource | |
* @return a dispatcher for the specified path | |
*/ | |
public RequestDispatcher getRequestDispatcher(String path) { | |
return servletContext.getRequestDispatcher(path); | |
} | |
/** | |
* Get the requested session id. Always returns the id of the current | |
* session. | |
* | |
* @return The session id | |
*/ | |
public String getRequestedSessionId() { | |
return session.getId(); | |
} | |
/** | |
* Returns context path and servlet path concatenated, typically | |
* <tt>/applicationClassName/applicationClassName</tt>. | |
* | |
* @return The path value | |
* @see javax.servlet.http.HttpServletRequest#getRequestURI() | |
*/ | |
public String getRequestURI() { | |
return getContextPath() + getServletPath(); | |
} | |
/** | |
* Returns (an attempt at) a reconstructed URL based on it's constituent | |
* parts. | |
* | |
* @return a StringBuffer object containing the reconstructed URL | |
*/ | |
public StringBuffer getRequestURL() { | |
StringBuffer buffer = new StringBuffer().append(getScheme()); | |
buffer.append("://"); | |
buffer.append(this.getServerName()); | |
buffer.append(":"); | |
buffer.append(this.getServerPort()); | |
buffer.append(this.contextPath); | |
buffer.append(this.servletPath); | |
if (getPathInfo() != null) { | |
buffer.append(getPathInfo()); | |
} | |
if (!isPost()) { | |
final String query = getQueryString(); | |
if (query != null) { | |
buffer.append('?'); | |
buffer.append(query); | |
} | |
} | |
return buffer; | |
} | |
/** | |
* Return whether the request is a post or not. | |
* | |
* @return true if the request is a post, false otherwise | |
*/ | |
public boolean isPost() { | |
return getMethod().equalsIgnoreCase("post"); | |
} | |
/** | |
* Get the scheme http, https, or ftp. | |
* | |
* @return the scheme used by this request | |
*/ | |
public String getScheme() { | |
return scheme; | |
} | |
/** | |
* Set the request's scheme, for example http, https, or ftp. | |
* | |
* @param scheme the request's scheme | |
*/ | |
public void setScheme(String scheme) { | |
this.scheme = scheme; | |
} | |
/** | |
* Get the host server name to which the request was sent. | |
* | |
* @return always the host server name | |
*/ | |
public String getServerName() { | |
return serverName; | |
} | |
/** | |
* Sets the host server name to which the request was sent. | |
* | |
* @param serverName the server name the request was sent to | |
*/ | |
public void setServerName(String serverName) { | |
this.serverName = serverName; | |
} | |
/** | |
* Returns the port number to which the request was sent. | |
* | |
* @return the server port to which the request was sent | |
*/ | |
public int getServerPort() { | |
return serverPort; | |
} | |
/** | |
* Set the port number to which the request was sent. | |
* | |
* @param serverPort the port number to which the request was sent | |
*/ | |
public void setServerPort(int serverPort) { | |
this.serverPort = serverPort; | |
} | |
/** | |
* Returns the portion of the request URI that indicates the context of the | |
* request. | |
* | |
* @return the portion of the request URI that indicates the context of | |
* the request. | |
*/ | |
public String getContextPath() { | |
// If request's contextPath was set manually (eg user set | |
// servletContext's contextPath), return that value. | |
if (!MockServletContext.DEFAULT_CONTEXT_PATH.equals(contextPath)) { | |
return contextPath; | |
} | |
// If servletContext path was set manually (eg user set servletContext's | |
// contextPath) then use that value in preference to the request default | |
// contextPath. | |
if (servletContext instanceof MockServletContext) { | |
MockServletContext mockServletContext = (MockServletContext) servletContext; | |
if (!MockServletContext.DEFAULT_CONTEXT_PATH.equals(mockServletContext.getContextPath())) { | |
return mockServletContext.getContextPath(); | |
} | |
} | |
// Lastly fallback to the default contextPath. | |
return contextPath; | |
} | |
/** | |
* Set the portion of the request URI that indicates the context of the | |
* request. | |
* | |
* @param contextPath the portion of the request URI that indicates the | |
* context of the request. | |
*/ | |
public void setContextPath(String contextPath) { | |
this.contextPath = contextPath; | |
} | |
/** | |
* Return a String containing the name or path of the servlet being called. | |
* | |
* @return The servlet path | |
*/ | |
public String getServletPath() { | |
return servletPath; | |
} | |
/** | |
* Set the string containing the name or path of the servlet being called. | |
* | |
* @param servletPath a String containing the name or path of the servlet | |
* being called | |
*/ | |
public void setServletPath(String servletPath) { | |
this.servletPath = servletPath; | |
} | |
/** | |
* Returns the current HttpSession associated with this request. | |
* | |
* @return the session associated with this request | |
*/ | |
public HttpSession getSession() { | |
return getSession(true); | |
} | |
/** | |
* Set the current HttpSession associated with this request. | |
* | |
* @param session the HttpSession to associate with this request | |
*/ | |
public void setSession(HttpSession session) { | |
this.session = session; | |
} | |
/** | |
* Returns the current HttpSession associated with this request. | |
* | |
* @param create if true creates a new session if one does not exist | |
* @return the current HttpSession associated with this request. | |
*/ | |
public HttpSession getSession(boolean create) { | |
if (session != null) { | |
return session; | |
} | |
if (create) { | |
String sessionId = createSessionId(); | |
session = new MockSession(sessionId, servletContext); | |
} | |
return session; | |
} | |
/** | |
* Get the user principal. If no user principal was set this method will | |
* create a user principal for the {@link #getRemoteUser()}. | |
* | |
* @return the user principal | |
*/ | |
public Principal getUserPrincipal() { | |
if (userPrincipal == null) { | |
final String user = getRemoteUser(); | |
if (user == null) { | |
return null; | |
} else { | |
userPrincipal = new MockPrincipal() { | |
@Override | |
public String getName() { | |
return user; | |
} | |
}; | |
} | |
} | |
return userPrincipal; | |
} | |
/** | |
* Set the user principal. | |
* | |
* @param userPrincipal the user principal | |
*/ | |
public void setUserPrincipal(Principal userPrincipal) { | |
this.userPrincipal = userPrincipal; | |
} | |
/** | |
* @return True if there has been added files to this request using | |
* {@link #addFile(String, File, String)}. | |
*/ | |
public boolean hasUploadedFiles() { | |
return uploadedFiles != null; | |
} | |
/** | |
* Reset the request back to a default state. | |
*/ | |
public final void initialize() { | |
authType = null; | |
method = "post"; | |
cookies.clear(); | |
setDefaultHeaders(); | |
pathInfo = null; | |
characterEncoding = "UTF-8"; | |
parameters.clear(); | |
attributes.clear(); | |
} | |
/** | |
* Delegate to initialize method. | |
*/ | |
public void reset() { | |
initialize(); | |
} | |
/** | |
* Check whether session id is from a cookie. Always returns true. | |
* | |
* @return Always true | |
*/ | |
public boolean isRequestedSessionIdFromCookie() { | |
return true; | |
} | |
/** | |
* Check whether session id is from a url rewrite. Always returns false. | |
* | |
* @return Always false | |
*/ | |
public boolean isRequestedSessionIdFromUrl() { | |
return false; | |
} | |
/** | |
* Check whether session id is from a url rewrite. Always returns false. | |
* | |
* @return Always false | |
*/ | |
public boolean isRequestedSessionIdFromURL() { | |
return false; | |
} | |
/** | |
* Check whether the session id is valid. | |
* | |
* @return Always true | |
*/ | |
public boolean isRequestedSessionIdValid() { | |
return true; | |
} | |
/** | |
* Always returns false. | |
* | |
* @return Always false | |
*/ | |
public boolean isSecure() { | |
return this.scheme.equalsIgnoreCase("https"); | |
} | |
/** | |
* Returns true if the {@link #getUserPrincipal() authenticated user} is | |
* included in the given role, false otherwise. | |
* <p/> | |
* To mock up roles for a user, create a {@link MockPrincipal user principal} | |
* and set the necessary roles. See {@link MockPrincipal} for an example. | |
* | |
* @param role the role name | |
* @return true if the user is included in the specified role, false | |
* otherwise | |
*/ | |
public boolean isUserInRole(String role) { | |
Principal principal = getUserPrincipal(); | |
if (principal instanceof MockPrincipal) { | |
return ((MockPrincipal) principal).getRoles().contains(role); | |
} | |
return false; | |
} | |
/** | |
* Remove the given attribute. | |
* | |
* @param name The name of the attribute | |
*/ | |
public void removeAttribute(final String name) { | |
attributes.remove(name); | |
} | |
/** | |
* Set the given attribute. | |
* | |
* @param name The attribute name | |
* @param o The value to set | |
*/ | |
public void setAttribute(final String name, final Object o) { | |
attributes.put(name, o); | |
} | |
/** | |
* Set the auth type. | |
* | |
* @param authType The auth type | |
*/ | |
public void setAuthType(final String authType) { | |
this.authType = authType; | |
} | |
/** | |
* Set the character encoding. | |
* | |
* @param encoding The character encoding | |
* @throws UnsupportedEncodingException If encoding not supported | |
*/ | |
public void setCharacterEncoding(final String encoding) | |
throws UnsupportedEncodingException { | |
characterEncoding = encoding; | |
} | |
/** | |
* Set the cookies. | |
* | |
* @param theCookies The cookies | |
*/ | |
public void setCookies(final Cookie[] theCookies) { | |
cookies.clear(); | |
for (int i = 0; i < theCookies.length; i++) { | |
cookies.add(theCookies[i]); | |
} | |
} | |
/** | |
* Set the method. | |
* | |
* @param method The method | |
*/ | |
public void setMethod(final String method) { | |
this.method = method; | |
} | |
/** | |
* Set a parameter. | |
* | |
* @param name The name | |
* @param value The value | |
*/ | |
public void setParameter(final String name, final String value) { | |
parameters.put(name, value); | |
} | |
/** | |
* Set the specified parameter name to the array of strings. | |
* | |
* @param name name of the parameter | |
* @param values the parameter values | |
*/ | |
public void setParameter(final String name, final String[] values) { | |
parameters.put(name, values); | |
} | |
/** | |
* Remove the specified parameter. | |
* | |
* @param name the parameter name to remove | |
*/ | |
public void removeParameter(final String name) { | |
parameters.remove(name); | |
} | |
/** | |
* Sets a map of parameters. | |
* | |
* @param parameters the parameters to set | |
*/ | |
public void setParameters(final Map<String, Object> parameters) { | |
this.parameters.putAll(parameters); | |
} | |
/** | |
* Set the path that this request is supposed to be serving. The path is | |
* relative to the web application root and should start with a / character | |
* | |
* @param path specifies the request path to serve | |
*/ | |
public void setPathInfo(final String path) { | |
this.pathInfo = path; | |
} | |
/** | |
* Returns the url that was forwarded to, otherwise return null. | |
* | |
* @see org.apache.click.servlet.MockRequestDispatcher#forward(javax.servlet.ServletRequest, | |
* javax.servlet.ServletResponse) | |
* | |
* @return url that was forwarded to | |
*/ | |
public String getForward() { | |
return this.forward; | |
} | |
/** | |
* Returns the list of server side included url's. | |
* | |
* @see org.apache.click.servlet.MockRequestDispatcher#include(javax.servlet.ServletRequest, | |
* javax.servlet.ServletResponse) | |
* | |
* @return list of urls that were included | |
*/ | |
public List<String> getIncludes() { | |
return this.includes; | |
} | |
/** | |
* Returns the String representation of the mock request. | |
* | |
* @return string representation of the mock request | |
*/ | |
@Override | |
public String toString() { | |
return getRequestURL().toString(); | |
} | |
// ------------------------------------------------ package methods | |
/** | |
* MockRequestDispatcher adds server side included url's to the request. | |
* | |
* @param url the url to include | |
*/ | |
void addInclude(String url) { | |
this.includes.add(url); | |
} | |
/** | |
* MockRequestDispatcher sets the forward url on the request. | |
* | |
* @param url the url to forward to | |
*/ | |
void setForward(String url) { | |
this.forward = url; | |
} | |
// -------------------------------------------------------- Private methods | |
/** | |
* Helper method to create some default headers for the request. | |
*/ | |
private void setDefaultHeaders() { | |
headers.clear(); | |
addHeader("Accept", "text/xml,application/xml,application/xhtml+xml," + "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"); | |
addHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); | |
Locale l = locale; | |
addHeader("Accept-Language", l.getLanguage().toLowerCase() + "-" | |
+ l.getCountry().toLowerCase() + "," + l.getLanguage().toLowerCase() + ";q=0.5"); | |
addHeader("User-Agent", | |
"Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7) Gecko/20040707 Firefox/0.9.2"); | |
} | |
/** | |
* Helper method to create new attachment. | |
* | |
* @param out the output stream to add attachment to | |
* @throws java.io.IOException if an I/O error occurs | |
*/ | |
private void newAttachment(OutputStream out) throws IOException { | |
out.write(BOUNDARY.getBytes()); | |
out.write(CRLF.getBytes()); | |
out.write("Content-Disposition: form-data".getBytes()); | |
} | |
/** | |
* Build the request based on the uploaded files and the parameters. | |
* | |
* @return The request as a string. | |
*/ | |
private byte[] buildRequest() { | |
try { | |
// Build up the input stream based on the files and parameters | |
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |
// Add parameters | |
for (String name : parameters.keySet()) { | |
newAttachment(out); | |
out.write("; name=\"".getBytes()); | |
out.write(name.getBytes()); | |
out.write("\"".getBytes()); | |
out.write(CRLF.getBytes()); | |
out.write(CRLF.getBytes()); | |
out.write(parameters.get(name).toString().getBytes()); | |
out.write(CRLF.getBytes()); | |
} | |
// Add files | |
if (uploadedFiles != null) { | |
for (String fieldName : uploadedFiles.keySet()) { | |
UploadedFile uf = uploadedFiles.get(fieldName); | |
newAttachment(out); | |
out.write("; name=\"".getBytes()); | |
out.write(fieldName.getBytes()); | |
out.write("\"; filename=\"".getBytes()); | |
out.write(uf.getFile().getName().getBytes()); | |
out.write("\"".getBytes()); | |
out.write(CRLF.getBytes()); | |
out.write("Content-Type: ".getBytes()); | |
out.write(uf.getContentType().getBytes()); | |
out.write(CRLF.getBytes()); | |
out.write(CRLF.getBytes()); | |
// Load the file and put it into the the inputstream | |
FileInputStream fis = new FileInputStream(uf.getFile()); | |
IOUtils.copy(fis, out); | |
fis.close(); | |
out.write(CRLF.getBytes()); | |
} | |
} | |
out.write(BOUNDARY.getBytes()); | |
out.write("--".getBytes()); | |
out.write(CRLF.getBytes()); | |
return out.toByteArray(); | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
/** | |
* Create and return a new session id. | |
* | |
* @return new session id | |
*/ | |
private String createSessionId() { | |
String mockId = getRemoteAddr().replaceAll("\\.", "") + "_" | |
+ System.currentTimeMillis() + "_" | |
+ Math.abs(random.nextLong()); | |
try { | |
//make it look secure ;-) | |
mockId = ClickUtils.toMD5Hash(mockId); | |
} catch (Exception e) { | |
//ignore | |
} | |
return mockId; | |
} | |
/** | |
* A holder class for an uploaded file. | |
* | |
* @author Frank Bille (billen) | |
*/ | |
private static class UploadedFile { | |
/** Name of the file field. */ | |
private String fieldName; | |
/** The uploaded file. */ | |
private File file; | |
/** The uploaded file content type. */ | |
private String contentType; | |
/** | |
* Construct. | |
* | |
* @param fieldName name of the file field | |
* @param file the uploaded file | |
* @param contentType the uploaded file content type | |
*/ | |
public UploadedFile(String fieldName, File file, String contentType) { | |
this.fieldName = fieldName; | |
this.file = file; | |
this.contentType = contentType; | |
} | |
/** | |
* Return the uploaded file content type. | |
* | |
* @return The content type of the file. Mime type. | |
*/ | |
public String getContentType() { | |
return contentType; | |
} | |
/** | |
* Set the uploaded file content type. | |
* | |
* @param contentType The content type. | |
*/ | |
@SuppressWarnings("unused") | |
public void setContentType(String contentType) { | |
this.contentType = contentType; | |
} | |
/** | |
* Return the file field name. | |
* | |
* @return The field name. | |
*/ | |
@SuppressWarnings("unused") | |
public String getFieldName() { | |
return fieldName; | |
} | |
/** | |
* Set the file field name. | |
* | |
* @param fieldName the name of the file field | |
*/ | |
@SuppressWarnings("unused") | |
public void setFieldName(String fieldName) { | |
this.fieldName = fieldName; | |
} | |
/** | |
* Return the uploaded file. | |
* | |
* @return The uploaded file. | |
*/ | |
public File getFile() { | |
return file; | |
} | |
/** | |
* Set the uploaded file. | |
* | |
* @param file the uploaded file | |
*/ | |
@SuppressWarnings("unused") | |
public void setFile(File file) { | |
this.file = file; | |
} | |
} | |
} |