/* | |
* 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.wicket.protocol.http.mock; | |
import java.io.BufferedReader; | |
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.FileInputStream; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.io.OutputStream; | |
import java.io.UnsupportedEncodingException; | |
import java.nio.charset.Charset; | |
import java.security.Principal; | |
import java.text.DateFormat; | |
import java.text.ParseException; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.Date; | |
import java.util.Enumeration; | |
import java.util.HashMap; | |
import java.util.Iterator; | |
import java.util.LinkedHashMap; | |
import java.util.List; | |
import java.util.Locale; | |
import java.util.Map; | |
import jakarta.servlet.AsyncContext; | |
import jakarta.servlet.DispatcherType; | |
import jakarta.servlet.ReadListener; | |
import jakarta.servlet.RequestDispatcher; | |
import jakarta.servlet.ServletContext; | |
import jakarta.servlet.ServletException; | |
import jakarta.servlet.ServletInputStream; | |
import jakarta.servlet.ServletRequest; | |
import jakarta.servlet.ServletResponse; | |
import jakarta.servlet.http.Cookie; | |
import jakarta.servlet.http.HttpServletRequest; | |
import jakarta.servlet.http.HttpServletResponse; | |
import jakarta.servlet.http.HttpSession; | |
import jakarta.servlet.http.HttpUpgradeHandler; | |
import jakarta.servlet.http.Part; | |
import org.apache.commons.fileupload.FileUploadBase; | |
import org.apache.wicket.Application; | |
import org.apache.wicket.WicketRuntimeException; | |
import org.apache.wicket.mock.MockRequestParameters; | |
import org.apache.wicket.request.Url; | |
import org.apache.wicket.request.Url.QueryParameter; | |
import org.apache.wicket.util.encoding.UrlDecoder; | |
import org.apache.wicket.util.encoding.UrlEncoder; | |
import org.apache.wicket.util.file.File; | |
import org.apache.wicket.util.io.IOUtils; | |
import org.apache.wicket.util.string.StringValue; | |
import org.apache.wicket.util.string.Strings; | |
import org.apache.wicket.util.value.ValueMap; | |
/** | |
* Mock servlet request. Implements all of the methods from the standard HttpServletRequest class | |
* plus helper methods to aid setting up a request. | |
* | |
* @author Chris Turner | |
*/ | |
public class MockHttpServletRequest implements HttpServletRequest | |
{ | |
/** | |
* A holder class for an uploaded file. | |
* | |
* @author Frank Bille (billen) | |
*/ | |
private static class UploadedFile | |
{ | |
private File file; | |
private String contentType; | |
/** | |
* Construct. | |
* | |
* @param fieldName | |
* @param file | |
* @param contentType | |
*/ | |
public UploadedFile(String fieldName, File file, String contentType) | |
{ | |
this.file = file; | |
this.contentType = contentType; | |
} | |
/** | |
* @return The content type of the file. Mime type. | |
*/ | |
public String getContentType() | |
{ | |
return contentType; | |
} | |
/** | |
* @return The uploaded file. | |
*/ | |
public File getFile() | |
{ | |
return file; | |
} | |
} | |
private final ValueMap attributes = new ValueMap(); | |
private String authType; | |
private String characterEncoding = "UTF-8"; | |
private final ServletContext context; | |
private final Map<Cookies.Key, Cookie> cookies = new LinkedHashMap<>(); | |
private final ValueMap headers = new ValueMap(); | |
private String method; | |
private final LinkedHashMap<String, String[]> parameters = new LinkedHashMap<>(); | |
private final LinkedHashMap<String, Part> parts = new LinkedHashMap<>(); | |
private String path; | |
private final HttpSession session; | |
private String url; | |
private Map<String, List<UploadedFile>> uploadedFiles; | |
private boolean useMultiPartContentType; | |
private boolean secure = false; | |
private String remoteAddr = "127.0.0.1"; | |
private String scheme = "http"; | |
private String serverName = "localhost"; | |
private int serverPort = 80; | |
/** | |
* Create the request using the supplied session object. Note that in order for temporary | |
* sessions to work, the supplied session must be an instance of {@link MockHttpSession} | |
* | |
* @param application | |
* The application that this request is for | |
* @param session | |
* The session object | |
* @param context | |
* The current servlet context | |
* @param locale | |
* The current locale | |
*/ | |
public MockHttpServletRequest(final Application application, final HttpSession session, | |
final ServletContext context, Locale locale) | |
{ | |
this.session = session; | |
this.context = context; | |
initialize(locale); | |
} | |
public MockHttpServletRequest(final Application application, final HttpSession session, | |
final ServletContext context) | |
{ | |
this(application, session, context, Locale.getDefault()); | |
} | |
/** | |
* Add a new cookie. | |
* | |
* @param cookie | |
* The cookie | |
*/ | |
public void addCookie(final Cookie cookie) | |
{ | |
cookies.put(Cookies.keyOf(cookie), cookie); | |
} | |
/** | |
* @param cookies | |
*/ | |
public void addCookies(Iterable<Cookie> cookies) | |
{ | |
for (Cookie cookie : cookies) | |
{ | |
addCookie(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) { | |
if (file.exists() == false) | |
{ | |
throw new IllegalArgumentException( | |
"File does not exists. 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<>(); | |
} | |
UploadedFile uf = new UploadedFile(fieldName, file, contentType); | |
List<UploadedFile> filesPerField = uploadedFiles.get(fieldName); | |
if (filesPerField == null) | |
{ | |
filesPerField = new ArrayList<>(); | |
uploadedFiles.put(fieldName, filesPerField); | |
} | |
filesPerField.add(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) | |
{ | |
@SuppressWarnings("unchecked") | |
List<String> list = (List<String>)headers.get(name); | |
if (list == null) | |
{ | |
list = new ArrayList<>(1); | |
headers.put(name, list); | |
} | |
list.add(value); | |
} | |
/** | |
* Sets a header to the request. Overrides any previous value of this header. | |
* | |
* @param name | |
* The name of the header to add | |
* @param value | |
* The value | |
* @see #addHeader(String, String) | |
*/ | |
public void setHeader(String name, String value) | |
{ | |
@SuppressWarnings("unchecked") | |
List<String> list = (List<String>)headers.get(name); | |
if (list == null) | |
{ | |
list = new ArrayList<>(1); | |
headers.put(name, list); | |
} | |
list.clear(); | |
list.add(value); | |
} | |
/** | |
* @param name | |
* @param date | |
*/ | |
public void addDateHeader(String name, long date) | |
{ | |
DateFormat df = DateFormat.getDateInstance(DateFormat.FULL); | |
String dateString = df.format(new Date(date)); | |
addHeader(name, dateString); | |
} | |
/** | |
* Get an attribute. | |
* | |
* @param name | |
* The attribute name | |
* @return The value, or null | |
*/ | |
@Override | |
public Object getAttribute(final String name) | |
{ | |
return attributes.get(name); | |
} | |
/** | |
* Get the names of all of the values. | |
* | |
* @return The names | |
*/ | |
@Override | |
public Enumeration<String> getAttributeNames() | |
{ | |
return Collections.enumeration(attributes.keySet()); | |
} | |
// HttpServletRequest methods | |
/** | |
* Get the auth type. | |
* | |
* @return The auth type | |
*/ | |
@Override | |
public String getAuthType() | |
{ | |
return authType; | |
} | |
/** | |
* Get the current character encoding. | |
* | |
* @return The character encoding | |
*/ | |
@Override | |
public String getCharacterEncoding() | |
{ | |
return characterEncoding; | |
} | |
/** | |
* Get the current character set. | |
* | |
* @return The character set | |
*/ | |
public Charset getCharset() | |
{ | |
return Charset.forName(characterEncoding); | |
} | |
/** | |
* true will force Request generate multiPart ContentType and ContentLength | |
* | |
* @param useMultiPartContentType | |
*/ | |
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. | |
*/ | |
@Override | |
public int getContentLength() | |
{ | |
if (useMultiPartContentType) | |
{ | |
byte[] request = buildRequest(); | |
return request.length; | |
} | |
return -1; | |
} | |
@Override | |
public long getContentLengthLong() | |
{ | |
return getContentLength(); | |
} | |
/** | |
* If useMultiPartContentType set as true return the correct content-type. | |
* | |
* @return The correct multipart content-type if useMultiPartContentType is true. Else null. | |
*/ | |
@Override | |
public String getContentType() | |
{ | |
if (useMultiPartContentType) | |
{ | |
return FileUploadBase.MULTIPART_FORM_DATA + "; boundary=abcdefgABCDEFG"; | |
} | |
return null; | |
} | |
/** | |
* Get the context path. For this mock implementation the name of the application is always | |
* returned. | |
* | |
* @return The context path | |
*/ | |
@Override | |
public String getContextPath() | |
{ | |
// return "/" + application.getName(); | |
return "/context"; | |
} | |
/** | |
* @param name | |
* @return Cookie | |
*/ | |
public Cookie getCookie(String name) | |
{ | |
Cookie[] cookies = getCookies(); | |
if (cookies == null) | |
{ | |
return null; | |
} | |
for (Cookie cookie : cookies) | |
{ | |
if (cookie.getName().equals(name)) | |
{ | |
return Cookies.copyOf(cookie); | |
} | |
} | |
return null; | |
} | |
/** | |
* Get all of the cookies for this request. | |
* | |
* @return The cookies | |
*/ | |
@Override | |
public Cookie[] getCookies() | |
{ | |
if (cookies.isEmpty()) | |
{ | |
return null; | |
} | |
List<Cookie> cookieValues = new ArrayList<Cookie>(); | |
cookieValues.addAll(cookies.values()); | |
return cookieValues.toArray(new Cookie[cookieValues.size()]); | |
} | |
/** | |
* 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 | |
*/ | |
@Override | |
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 | |
*/ | |
@Override | |
public String getHeader(final String name) | |
{ | |
@SuppressWarnings("unchecked") | |
final List<String> l = (List<String>)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 | |
*/ | |
@Override | |
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 | |
*/ | |
@Override | |
public Enumeration<String> getHeaders(final String name) | |
{ | |
@SuppressWarnings("unchecked") | |
List<String> list = (List<String>)headers.get(name); | |
if (list == null) | |
{ | |
list = new ArrayList<String>(); | |
} | |
return Collections.enumeration(list); | |
} | |
/** | |
* 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 | |
*/ | |
@Override | |
public ServletInputStream getInputStream() throws IOException | |
{ | |
byte[] request = buildRequest(); | |
// Ok lets make an input stream to return | |
final ByteArrayInputStream bais = new ByteArrayInputStream(request); | |
return new ServletInputStream() | |
{ | |
private boolean isFinished = false; | |
private boolean isReady = true; | |
@Override | |
public boolean isFinished() | |
{ | |
return isFinished; | |
} | |
@Override | |
public boolean isReady() | |
{ | |
return isReady; | |
} | |
@Override | |
public void setReadListener(ReadListener readListener) | |
{ | |
} | |
@Override | |
public int read() | |
{ | |
isFinished = true; | |
isReady = false; | |
return bais.read(); | |
} | |
}; | |
} | |
/** | |
* 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 | |
*/ | |
@Override | |
public int getIntHeader(final String name) | |
{ | |
String value = getHeader(name); | |
if (value == null) | |
{ | |
return -1; | |
} | |
return Integer.valueOf(value); | |
} | |
/** | |
* 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 | |
*/ | |
@Override | |
public Locale getLocale() | |
{ | |
return getLocales().nextElement(); | |
} | |
public void setLocale(Locale locale) { | |
setHeader("Accept-Language", locale.getLanguage() + '-' + locale.getCountry()); | |
} | |
/** | |
* | |
* @param value | |
* @return locale | |
*/ | |
private Locale getLocale(final String value) | |
{ | |
final String[] bits = Strings.split(value, '-'); | |
if (bits.length < 1) | |
{ | |
return null; | |
} | |
final String language = bits[0].toLowerCase(Locale.ROOT); | |
if (bits.length > 1) | |
{ | |
final String country = bits[1].toUpperCase(Locale.ROOT); | |
return new Locale(language, country); | |
} | |
else | |
{ | |
return new Locale(language); | |
} | |
} | |
/** | |
* Return all the accepted locales. This implementation always returns just one. | |
* | |
* @return The locales | |
*/ | |
@Override | |
public Enumeration<Locale> getLocales() | |
{ | |
List<Locale> list = new ArrayList<>(); | |
String header = getHeader("Accept-Language"); | |
if (header != null) | |
{ | |
int idxOfSemicolon = header.indexOf(';'); | |
if (idxOfSemicolon > -1) { | |
header = header.substring(0 , idxOfSemicolon); | |
} | |
final String[] locales = Strings.split(header, ','); | |
for (String value : locales) | |
{ | |
Locale locale = getLocale(value); | |
if (locale != null) | |
{ | |
list.add(locale); | |
} | |
} | |
} | |
if (list.size() == 0) | |
{ | |
list.add(Locale.getDefault()); | |
} | |
return Collections.enumeration(list); | |
} | |
/** | |
* Get the method. | |
* | |
* @return The method | |
*/ | |
@Override | |
public String getMethod() | |
{ | |
return method; | |
} | |
/** | |
* Get the request parameter with the given name. | |
* | |
* @param name | |
* The parameter name | |
* @return The parameter value, or null | |
*/ | |
@Override | |
public String getParameter(final String name) | |
{ | |
String[] param = getParameterMap().get(name); | |
if (param == null) | |
{ | |
return null; | |
} | |
else | |
{ | |
return param[0]; | |
} | |
} | |
/** | |
* Get the map of all of the parameters. | |
* | |
* @return The parameters | |
*/ | |
@Override | |
public Map<String, String[]> getParameterMap() | |
{ | |
Map<String, String[]> params = new HashMap<>(parameters); | |
for (String name : post.getParameterNames()) | |
{ | |
List<StringValue> values = post.getParameterValues(name); | |
for (StringValue value : values) | |
{ | |
String[] present = params.get(name); | |
if (present == null) | |
{ | |
params.put(name, new String[] { value.toString() }); | |
} | |
else | |
{ | |
String[] newval = new String[present.length + 1]; | |
System.arraycopy(present, 0, newval, 0, present.length); | |
newval[newval.length - 1] = value.toString(); | |
params.put(name, newval); | |
} | |
} | |
} | |
return params; | |
} | |
/** | |
* Get the names of all of the parameters. | |
* | |
* @return The parameter names | |
*/ | |
@Override | |
public Enumeration<String> getParameterNames() | |
{ | |
return Collections.enumeration(getParameterMap().keySet()); | |
} | |
/** | |
* Get the values for the given parameter. | |
* | |
* @param name | |
* The name of the parameter | |
* @return The return values | |
*/ | |
@Override | |
public String[] getParameterValues(final String name) | |
{ | |
Object value = getParameterMap().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 | |
*/ | |
@Override | |
public String getPathInfo() | |
{ | |
return path; | |
} | |
/** | |
* Always returns null. | |
* | |
* @return null | |
*/ | |
@Override | |
public String getPathTranslated() | |
{ | |
return null; | |
} | |
/** | |
* Get the protocol. | |
* | |
* @return Always HTTP/1.1 | |
*/ | |
@Override | |
public String getProtocol() | |
{ | |
return "HTTP/1.1"; | |
} | |
/** | |
* Get the query string part of the request. | |
* | |
* @return The query string | |
*/ | |
@Override | |
public String getQueryString() | |
{ | |
if (parameters.size() == 0) | |
{ | |
return null; | |
} | |
else | |
{ | |
final StringBuilder buf = new StringBuilder(); | |
for (Iterator<String> iterator = parameters.keySet().iterator(); iterator.hasNext();) | |
{ | |
final String name = iterator.next(); | |
final String[] values = getParameterValues(name); | |
for (int i = 0; i < values.length; i++) | |
{ | |
if (name != null) | |
{ | |
buf.append(UrlEncoder.QUERY_INSTANCE.encode(name, getCharset())); | |
} | |
buf.append('='); | |
if (values[i] != null) | |
{ | |
buf.append(UrlEncoder.QUERY_INSTANCE.encode(values[i], getCharset())); | |
} | |
if (i + 1 < values.length) | |
{ | |
buf.append('&'); | |
} | |
} | |
if (iterator.hasNext()) | |
{ | |
buf.append('&'); | |
} | |
} | |
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 | |
*/ | |
@Override | |
public BufferedReader getReader() throws IOException | |
{ | |
return new BufferedReader(new InputStreamReader(getInputStream())); | |
} | |
/** | |
* Deprecated method - should not be used. | |
* | |
* @param name | |
* The name | |
* @return The path | |
* @deprecated Use ServletContext.getRealPath(String) instead. | |
*/ | |
@Override | |
@Deprecated | |
public String getRealPath(String name) | |
{ | |
return context.getRealPath(name); | |
} | |
/** | |
* @return the remote address of the client | |
*/ | |
@Override | |
public String getRemoteAddr() | |
{ | |
return remoteAddr; | |
} | |
/** | |
* | |
* @param addr | |
* Format: "aaa.bbb.ccc.ddd" | |
*/ | |
public void setRemoteAddr(String addr) | |
{ | |
remoteAddr = addr; | |
} | |
/** | |
* Get the remote host. | |
* | |
* @return Return 'localhost' by default | |
*/ | |
@Override | |
public String getRemoteHost() | |
{ | |
return "localhost"; | |
} | |
/** | |
* Get the name of the remote user from the REMOTE_USER header. | |
* | |
* @return The name of the remote user | |
*/ | |
@Override | |
public String getRemoteUser() | |
{ | |
return getHeader("REMOTE_USER"); | |
} | |
/** | |
* Return a dummy dispatcher that just records that dispatch has occurred without actually doing | |
* anything. | |
* | |
* @param name | |
* The name to dispatch to | |
* @return The dispatcher | |
*/ | |
@Override | |
public RequestDispatcher getRequestDispatcher(String name) | |
{ | |
return context.getRequestDispatcher(name); | |
} | |
/** | |
* Get the requested session id. Always returns the id of the current session. | |
* | |
* @return The session id | |
*/ | |
@Override | |
public String getRequestedSessionId() | |
{ | |
if (session instanceof MockHttpSession && ((MockHttpSession)session).isTemporary()) | |
{ | |
return null; | |
} | |
return session.getId(); | |
} | |
/** | |
* Returns context path and servlet path concatenated, typically | |
* /applicationClassName/applicationClassName | |
* | |
* @return The path value | |
* @see jakarta.servlet.http.HttpServletRequest#getRequestURI() | |
*/ | |
@Override | |
public String getRequestURI() | |
{ | |
if (url == null) | |
{ | |
return getContextPath() + getServletPath(); | |
} | |
else | |
{ | |
int index = url.indexOf("?"); | |
if (index != -1) | |
{ | |
return url.substring(0, index); | |
} | |
} | |
return url; | |
} | |
/** | |
* Try to build a rough URL. | |
* | |
* @return The url | |
* @see jakarta.servlet.http.HttpServletRequest#getRequestURL() | |
*/ | |
@Override | |
public StringBuffer getRequestURL() | |
{ | |
StringBuffer buf = new StringBuffer(); | |
buf.append("http://localhost"); | |
buf.append(getContextPath()); | |
if (getPathInfo() != null) | |
{ | |
buf.append(getPathInfo()); | |
} | |
// No query parameter. See | |
// http://download.oracle.com/javaee/5/api/javax/servlet/http/HttpServletRequest.html#getRequestURL() | |
return buf; | |
} | |
/** | |
* Get the scheme. | |
* | |
* @return the scheme of this request | |
*/ | |
@Override | |
public String getScheme() | |
{ | |
return scheme; | |
} | |
/** | |
* Sets the scheme of this request | |
* <p/> | |
* set the <code>secure</code> flag accordingly (<code>true</code> for 'https', | |
* <code>false</code> otherwise) | |
* | |
* @param scheme | |
* protocol scheme (e.g. https, http, ftp) | |
* | |
* @see #isSecure() | |
*/ | |
public void setScheme(String scheme) | |
{ | |
this.scheme = scheme; | |
secure = "https".equalsIgnoreCase(scheme); | |
} | |
/** | |
* Get the server name. | |
* | |
* @return by default returns 'localhost' | |
*/ | |
@Override | |
public String getServerName() | |
{ | |
return serverName; | |
} | |
/** | |
* Set the server name. | |
* | |
* @param serverName | |
* content of 'Host' header | |
*/ | |
public void setServerName(final String serverName) | |
{ | |
this.serverName = serverName; | |
} | |
/** | |
* @return the server port of this request | |
*/ | |
@Override | |
public int getServerPort() | |
{ | |
return serverPort; | |
} | |
/** | |
* Sets the server port for this request | |
* | |
* @param port | |
*/ | |
public void setServerPort(int port) | |
{ | |
serverPort = port; | |
} | |
/** | |
* The servlet path may either be the application name or /. For test purposes we always return | |
* the servlet name. | |
* | |
* @return The servlet path | |
*/ | |
@Override | |
public String getServletPath() | |
{ | |
return "/servlet"; | |
} | |
/** | |
* Get the sessions. | |
* | |
* @return The session | |
*/ | |
@Override | |
public HttpSession getSession() | |
{ | |
return getSession(true); | |
} | |
@Override | |
public String changeSessionId() | |
{ | |
final HttpSession oldSession = getSession(false); | |
if (oldSession == null) | |
{ | |
throw new IllegalStateException("There is no active session associated with the current request"); | |
} | |
oldSession.invalidate(); | |
final HttpSession newSession = getSession(true); | |
return newSession.getId(); | |
} | |
/** | |
* Get the session. | |
* | |
* @param createNew | |
* Ignored, there is always a session | |
* @return The session | |
*/ | |
@Override | |
public HttpSession getSession(boolean createNew) | |
{ | |
HttpSession sess = null; | |
if (session instanceof MockHttpSession) | |
{ | |
MockHttpSession mockHttpSession = (MockHttpSession)session; | |
if (createNew) | |
{ | |
mockHttpSession.setTemporary(false); | |
} | |
if (mockHttpSession.isTemporary() == false) | |
{ | |
sess = session; | |
} | |
} | |
return sess; | |
} | |
/** | |
* Get the user principal. | |
* | |
* @return A user principal | |
*/ | |
@Override | |
public Principal getUserPrincipal() | |
{ | |
final String user = getRemoteUser(); | |
if (user == null) | |
{ | |
return null; | |
} | |
else | |
{ | |
return new Principal() | |
{ | |
@Override | |
public String getName() | |
{ | |
return user; | |
} | |
}; | |
} | |
} | |
/** | |
* @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. | |
* @param locale | |
*/ | |
public void initialize(Locale locale) | |
{ | |
authType = null; | |
method = "post"; | |
cookies.clear(); | |
setDefaultHeaders(locale); | |
path = null; | |
url = null; | |
characterEncoding = "UTF-8"; | |
parameters.clear(); | |
attributes.clear(); | |
post.reset(); | |
} | |
/** | |
* Check whether session id is from a cookie. Always returns true. | |
* | |
* @return Always true | |
*/ | |
@Override | |
public boolean isRequestedSessionIdFromCookie() | |
{ | |
return true; | |
} | |
/** | |
* Check whether session id is from a url rewrite. Always returns false. | |
* | |
* @return Always false | |
*/ | |
@Override | |
public boolean isRequestedSessionIdFromUrl() | |
{ | |
return false; | |
} | |
@Override | |
public boolean authenticate(HttpServletResponse response) throws IOException, ServletException | |
{ | |
return false; | |
} | |
@Override | |
public void login(String username, String password) throws ServletException | |
{ | |
} | |
@Override | |
public void logout() throws ServletException | |
{ | |
} | |
@Override | |
public Collection<Part> getParts() throws IOException, ServletException | |
{ | |
return parts.values(); | |
} | |
@Override | |
public Part getPart(String name) throws IOException, ServletException | |
{ | |
return parts.get(name); | |
} | |
@Override | |
public <T extends HttpUpgradeHandler> T upgrade(Class<T> aClass) throws IOException, ServletException | |
{ | |
return null; | |
} | |
public MockHttpServletRequest setPart(String name, Part part) { | |
parts.put(name, part); | |
return this; | |
} | |
/** | |
* Check whether session id is from a url rewrite. Always returns false. | |
* | |
* @return Always false | |
*/ | |
@Override | |
public boolean isRequestedSessionIdFromURL() | |
{ | |
return false; | |
} | |
/** | |
* Check whether the session id is valid. | |
* | |
* @return Always true | |
*/ | |
@Override | |
public boolean isRequestedSessionIdValid() | |
{ | |
return true; | |
} | |
/** | |
* @return <code>true</code> if this request's scheme is 'https', <code>false</code> - otherwise | |
*/ | |
@Override | |
public boolean isSecure() | |
{ | |
return secure; | |
} | |
/** | |
* | |
* @param secure | |
*/ | |
public void setSecure(boolean secure) | |
{ | |
this.secure = secure; | |
} | |
/** | |
* NOT IMPLEMENTED. | |
* | |
* @param name | |
* The role name | |
* @return Always false | |
*/ | |
@Override | |
public boolean isUserInRole(String name) | |
{ | |
return false; | |
} | |
/** | |
* Remove the given attribute. | |
* | |
* @param name | |
* The name of the attribute | |
*/ | |
@Override | |
public void removeAttribute(final String name) | |
{ | |
attributes.remove(name); | |
} | |
/** | |
* Set the given attribute. | |
* | |
* @param name | |
* The attribute name | |
* @param o | |
* The value to set | |
*/ | |
@Override | |
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 | |
*/ | |
@Override | |
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(); | |
addCookies(Arrays.asList(theCookies)); | |
} | |
/** | |
* 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) | |
{ | |
if (value == null) | |
{ | |
parameters.remove(name); | |
} | |
else | |
{ | |
parameters.put(name, new String[] { value }); | |
} | |
} | |
/** | |
* @param name | |
* @param value | |
*/ | |
public void addParameter(final String name, final String value) | |
{ | |
if (value == null) | |
{ | |
return; | |
} | |
String[] val = parameters.get(name); | |
if (val == null) | |
{ | |
parameters.put(name, new String[] { value }); | |
} | |
else | |
{ | |
String[] newval = new String[val.length + 1]; | |
System.arraycopy(val, 0, newval, 0, val.length); | |
newval[val.length] = value; | |
parameters.put(name, newval); | |
} | |
} | |
/** | |
* Sets a map of parameters. | |
* | |
* @param parameters | |
* the parameters to set | |
*/ | |
public void setParameters(final Map<String, String[]> 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 | |
*/ | |
public void setPath(final String path) | |
{ | |
this.path = UrlDecoder.PATH_INSTANCE.decode(path, getCharset()); | |
} | |
/** | |
* Set the complete url for this request. The url will be analyzed. | |
* | |
* @param url | |
*/ | |
public void setURL(String url) | |
{ | |
setUrl(Url.parse(url)); | |
} | |
/** | |
* Helper method to create some default headers for the request | |
* @param l | |
*/ | |
private void setDefaultHeaders(Locale l) | |
{ | |
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"); | |
addHeader("Accept-Language", l.getLanguage().toLowerCase(Locale.ROOT) + "-" | |
+ l.getCountry().toLowerCase(Locale.ROOT) + "," + l.getLanguage().toLowerCase(Locale.ROOT) + ";q=0.5"); | |
addHeader("User-Agent", | |
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:41.0) Gecko/20100101 Firefox/41.0"); | |
} | |
private static final String crlf = "\r\n"; | |
private static final String boundary = "--abcdefgABCDEFG"; | |
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() | |
{ | |
if (uploadedFiles == null && useMultiPartContentType == false) | |
{ | |
if (post.getParameterNames().size() == 0) | |
{ | |
return "".getBytes(); | |
} | |
Url url = new Url(); | |
for (final String parameterName : post.getParameterNames()) | |
{ | |
List<StringValue> values = post.getParameterValues(parameterName); | |
for (StringValue value : values) | |
{ | |
url.addQueryParameter(parameterName, value.toString()); | |
} | |
} | |
String body = url.toString().substring(1); | |
return body.getBytes(); | |
} | |
try | |
{ | |
// Build up the input stream based on the files and parameters | |
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |
// Add parameters | |
for (final String parameterName : post.getParameterNames()) | |
{ | |
List<StringValue> values = post.getParameterValues(parameterName); | |
for (StringValue value : values) | |
{ | |
newAttachment(out); | |
out.write("; name=\"".getBytes()); | |
out.write(parameterName.getBytes()); | |
out.write("\"".getBytes()); | |
out.write(crlf.getBytes()); | |
out.write(crlf.getBytes()); | |
out.write(value.toString().getBytes()); | |
out.write(crlf.getBytes()); | |
} | |
} | |
// Add files | |
if (uploadedFiles != null) | |
{ | |
for (Map.Entry<String, List<UploadedFile>> entry : uploadedFiles.entrySet()) | |
{ | |
String fieldName = entry.getKey(); | |
List<UploadedFile> files = entry.getValue(); | |
for (UploadedFile uf : files) | |
{ | |
newAttachment(out); | |
out.write("; name=\"".getBytes()); | |
out.write(fieldName.getBytes()); | |
out.write("\"; filename=\"".getBytes()); | |
if (uf.getFile() != null) { | |
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()); | |
if (uf.getFile() != null) { | |
// Load the file and put it into the the inputstream | |
FileInputStream fis = new FileInputStream(uf.getFile()); | |
try | |
{ | |
IOUtils.copy(fis, out); | |
} | |
finally | |
{ | |
fis.close(); | |
} | |
} | |
out.write(crlf.getBytes()); | |
} | |
} | |
} | |
out.write(boundary.getBytes()); | |
out.write("--".getBytes()); | |
out.write(crlf.getBytes()); | |
return out.toByteArray(); | |
} | |
catch (IOException e) | |
{ | |
// NOTE: IllegalStateException(Throwable) only exists since Java 1.5 | |
throw new WicketRuntimeException(e); | |
} | |
} | |
/** | |
* @return local address | |
*/ | |
@Override | |
public String getLocalAddr() | |
{ | |
return "127.0.0.1"; | |
} | |
/** | |
* @return local host name | |
*/ | |
@Override | |
public String getLocalName() | |
{ | |
return "127.0.0.1"; | |
} | |
/** | |
* @return local port | |
*/ | |
@Override | |
public int getLocalPort() | |
{ | |
return 80; | |
} | |
/** | |
* @return remote port | |
*/ | |
@Override | |
public int getRemotePort() | |
{ | |
return 80; | |
} | |
/** | |
* @param url | |
*/ | |
public void setUrl(Url url) | |
{ | |
if (url.getProtocol() != null) | |
{ | |
setScheme(url.getProtocol()); | |
} | |
if (url.getHost() != null) | |
{ | |
serverName = url.getHost(); | |
} | |
if (url.getPort() != null) | |
{ | |
serverPort = url.getPort(); | |
} | |
String path = url.getPath(getCharset()); | |
if (path.startsWith("/") == false) | |
{ | |
path = getContextPath() + getServletPath() + '/' + path; | |
} | |
this.url = path; | |
if (path.startsWith(getContextPath())) | |
{ | |
path = path.substring(getContextPath().length()); | |
} | |
if (path.startsWith(getServletPath())) | |
{ | |
path = path.substring(getServletPath().length()); | |
} | |
setPath(path); | |
// | |
// We can't clear the parameters here because users may have set custom | |
// parameters in request. An better place to clear they is when tester | |
// setups the next request cycle | |
// | |
// parameters.clear(); | |
for (QueryParameter parameter : url.getQueryParameters()) | |
{ | |
addParameter(parameter.getName(), parameter.getValue()); | |
} | |
} | |
/** | |
* @return request url | |
*/ | |
public Url getUrl() | |
{ | |
final String urlString; | |
final String queryString = getQueryString(); | |
if (Strings.isEmpty(queryString)) | |
{ | |
urlString = getRequestURI(); | |
} | |
else | |
{ | |
urlString = getRequestURI() + '?' + queryString; | |
} | |
final Url url = Url.parse(urlString, getCharset()); | |
url.setProtocol(scheme); | |
url.setHost(serverName); | |
url.setPort(serverPort); | |
return url; | |
} | |
/** | |
* @return post parameters | |
*/ | |
public MockRequestParameters getPostParameters() | |
{ | |
return post; | |
} | |
/** | |
* @return filter prefix | |
*/ | |
public String getFilterPrefix() | |
{ | |
return getServletPath().substring(1); | |
} | |
private final MockRequestParameters post = new MockRequestParameters(); | |
/** | |
* @return ServletContext | |
*/ | |
@Override | |
public ServletContext getServletContext() | |
{ | |
return context; | |
} | |
@Override | |
public AsyncContext startAsync() throws IllegalStateException | |
{ | |
return null; | |
} | |
@Override | |
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) | |
throws IllegalStateException | |
{ | |
return null; | |
} | |
@Override | |
public boolean isAsyncStarted() | |
{ | |
return false; | |
} | |
@Override | |
public boolean isAsyncSupported() | |
{ | |
return false; | |
} | |
@Override | |
public AsyncContext getAsyncContext() | |
{ | |
return null; | |
} | |
@Override | |
public DispatcherType getDispatcherType() | |
{ | |
return null; | |
} | |
} |