434386 - Request Dispatcher extracts args and prevents asyncIO.
Avoid to read the content from within include() or forward(), therefore making possible to proxy the content as-is to an upstream server.
This commit is contained in:
parent
3b4435c1e3
commit
ba4ed86e31
|
@ -22,7 +22,6 @@ import java.io.IOException;
|
|||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
|
@ -360,7 +359,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
{
|
||||
LOG.debug("auth rePOST {}->{}",authentication,j_uri);
|
||||
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
base_request.setParameters(j_post);
|
||||
base_request.setContentParameters(j_post);
|
||||
}
|
||||
session.removeAttribute(__J_URI);
|
||||
session.removeAttribute(__J_METHOD);
|
||||
|
@ -395,8 +394,9 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
if (MimeTypes.Type.FORM_ENCODED.is(req.getContentType()) && HttpMethod.POST.is(request.getMethod()))
|
||||
{
|
||||
Request base_request = (req instanceof Request)?(Request)req:HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
base_request.extractParameters();
|
||||
session.setAttribute(__J_POST, new MultiMap<String>(base_request.getParameters()));
|
||||
MultiMap<String> formParameters = new MultiMap<>();
|
||||
base_request.extractFormParameters(formParameters);
|
||||
session.setAttribute(__J_POST, formParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.io.IOException;
|
|||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -34,13 +33,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.UrlEncoded;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Servlet RequestDispatcher.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class Dispatcher implements RequestDispatcher
|
||||
{
|
||||
/** Dispatch include attribute names */
|
||||
|
@ -49,71 +42,41 @@ public class Dispatcher implements RequestDispatcher
|
|||
/** Dispatch include attribute names */
|
||||
public final static String __FORWARD_PREFIX="javax.servlet.forward.";
|
||||
|
||||
/** JSP attributes */
|
||||
public final static String __JSP_FILE="org.apache.catalina.jsp_file";
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private final ContextHandler _contextHandler;
|
||||
private final String _uri;
|
||||
private final String _path;
|
||||
private final String _dQuery;
|
||||
private final String _query;
|
||||
private final String _named;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param contextHandler
|
||||
* @param uri
|
||||
* @param pathInContext
|
||||
* @param query
|
||||
*/
|
||||
public Dispatcher(ContextHandler contextHandler, String uri, String pathInContext, String query)
|
||||
{
|
||||
_contextHandler=contextHandler;
|
||||
_uri=uri;
|
||||
_path=pathInContext;
|
||||
_dQuery=query;
|
||||
_query=query;
|
||||
_named=null;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param contextHandler
|
||||
* @param name
|
||||
*/
|
||||
public Dispatcher(ContextHandler contextHandler,String name)
|
||||
throws IllegalStateException
|
||||
public Dispatcher(ContextHandler contextHandler, String name) throws IllegalStateException
|
||||
{
|
||||
_contextHandler=contextHandler;
|
||||
_named=name;
|
||||
_uri=null;
|
||||
_path=null;
|
||||
_dQuery=null;
|
||||
_query=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
|
||||
*/
|
||||
@Override
|
||||
public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
forward(request, response, DispatcherType.FORWARD);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
|
||||
*/
|
||||
public void error(ServletRequest request, ServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
forward(request, response, DispatcherType.ERROR);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see javax.servlet.RequestDispatcher#include(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
|
||||
*/
|
||||
@Override
|
||||
public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
|
@ -126,70 +89,48 @@ public class Dispatcher implements RequestDispatcher
|
|||
|
||||
final DispatcherType old_type = baseRequest.getDispatcherType();
|
||||
final Attributes old_attr=baseRequest.getAttributes();
|
||||
MultiMap<String> old_params=baseRequest.getParameters();
|
||||
final MultiMap<String> old_query_params=baseRequest.getQueryParameters();
|
||||
try
|
||||
{
|
||||
baseRequest.setDispatcherType(DispatcherType.INCLUDE);
|
||||
baseRequest.getResponse().include();
|
||||
if (_named!=null)
|
||||
{
|
||||
_contextHandler.handle(_named,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
|
||||
}
|
||||
else
|
||||
{
|
||||
String query=_dQuery;
|
||||
|
||||
if (query!=null)
|
||||
{
|
||||
// force parameter extraction
|
||||
if (old_params==null)
|
||||
{
|
||||
baseRequest.extractParameters();
|
||||
old_params=baseRequest.getParameters();
|
||||
}
|
||||
|
||||
MultiMap<String> parameters=new MultiMap<>();
|
||||
UrlEncoded.decodeTo(query,parameters,baseRequest.getCharacterEncoding(),-1);
|
||||
|
||||
if(old_params != null) {
|
||||
// Merge parameters.
|
||||
parameters.addAllValues(old_params);
|
||||
}
|
||||
baseRequest.setParameters(parameters);
|
||||
}
|
||||
|
||||
IncludeAttributes attr = new IncludeAttributes(old_attr);
|
||||
|
||||
attr._requestURI=_uri;
|
||||
attr._contextPath=_contextHandler.getContextPath();
|
||||
attr._servletPath=null; // set by ServletHandler
|
||||
attr._pathInfo=_path;
|
||||
attr._query=query;
|
||||
attr._query=_query;
|
||||
|
||||
if (_query!=null)
|
||||
baseRequest.mergeQueryParameters(_query, false);
|
||||
baseRequest.setAttributes(attr);
|
||||
|
||||
_contextHandler.handle(_path,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
|
||||
_contextHandler.handle(_path, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
baseRequest.setAttributes(old_attr);
|
||||
baseRequest.getResponse().included();
|
||||
baseRequest.setParameters(old_params);
|
||||
baseRequest.setQueryParameters(old_query_params);
|
||||
baseRequest.resetParameters();
|
||||
baseRequest.setDispatcherType(old_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
|
||||
*/
|
||||
protected void forward(ServletRequest request, ServletResponse response, DispatcherType dispatch) throws ServletException, IOException
|
||||
{
|
||||
Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
|
||||
Response base_response=baseRequest.getResponse();
|
||||
base_response.resetForForward();
|
||||
|
||||
|
||||
if (!(request instanceof HttpServletRequest))
|
||||
request = new ServletRequestHttpWrapper(request);
|
||||
if (!(response instanceof HttpServletResponse))
|
||||
|
@ -201,9 +142,9 @@ public class Dispatcher implements RequestDispatcher
|
|||
final String old_servlet_path=baseRequest.getServletPath();
|
||||
final String old_path_info=baseRequest.getPathInfo();
|
||||
final String old_query=baseRequest.getQueryString();
|
||||
final MultiMap<String> old_query_params=baseRequest.getQueryParameters();
|
||||
final Attributes old_attr=baseRequest.getAttributes();
|
||||
final DispatcherType old_type=baseRequest.getDispatcherType();
|
||||
MultiMap<String> old_params=baseRequest.getParameters();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -211,24 +152,11 @@ public class Dispatcher implements RequestDispatcher
|
|||
baseRequest.setDispatcherType(dispatch);
|
||||
|
||||
if (_named!=null)
|
||||
_contextHandler.handle(_named,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
|
||||
{
|
||||
_contextHandler.handle(_named, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// process any query string from the dispatch URL
|
||||
String query=_dQuery;
|
||||
if (query!=null)
|
||||
{
|
||||
// force parameter extraction
|
||||
if (old_params==null)
|
||||
{
|
||||
baseRequest.extractParameters();
|
||||
old_params=baseRequest.getParameters();
|
||||
}
|
||||
|
||||
baseRequest.mergeQueryString(query);
|
||||
}
|
||||
|
||||
ForwardAttributes attr = new ForwardAttributes(old_attr);
|
||||
|
||||
//If we have already been forwarded previously, then keep using the established
|
||||
|
@ -256,9 +184,11 @@ public class Dispatcher implements RequestDispatcher
|
|||
baseRequest.setContextPath(_contextHandler.getContextPath());
|
||||
baseRequest.setServletPath(null);
|
||||
baseRequest.setPathInfo(_uri);
|
||||
if (_query!=null)
|
||||
baseRequest.mergeQueryParameters(_query, true);
|
||||
baseRequest.setAttributes(attr);
|
||||
|
||||
_contextHandler.handle(_path,baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
|
||||
_contextHandler.handle(_path, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
|
||||
|
||||
if (!baseRequest.getHttpChannelState().isAsync())
|
||||
commitResponse(response,baseRequest);
|
||||
|
@ -271,15 +201,14 @@ public class Dispatcher implements RequestDispatcher
|
|||
baseRequest.setContextPath(old_context_path);
|
||||
baseRequest.setServletPath(old_servlet_path);
|
||||
baseRequest.setPathInfo(old_path_info);
|
||||
baseRequest.setAttributes(old_attr);
|
||||
baseRequest.setParameters(old_params);
|
||||
baseRequest.setQueryString(old_query);
|
||||
baseRequest.setQueryParameters(old_query_params);
|
||||
baseRequest.resetParameters();
|
||||
baseRequest.setAttributes(old_attr);
|
||||
baseRequest.setDispatcherType(old_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void commitResponse(ServletResponse response, Request baseRequest) throws IOException
|
||||
{
|
||||
if (baseRequest.getResponse().isWriting())
|
||||
|
@ -306,10 +235,6 @@ public class Dispatcher implements RequestDispatcher
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
private class ForwardAttributes implements Attributes
|
||||
{
|
||||
final Attributes _attr;
|
||||
|
@ -349,7 +274,6 @@ public class Dispatcher implements RequestDispatcher
|
|||
return _attr.getAttribute(key);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Enumeration<String> getAttributeNames()
|
||||
{
|
||||
|
@ -381,7 +305,6 @@ public class Dispatcher implements RequestDispatcher
|
|||
return Collections.enumeration(set);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void setAttribute(String key, Object value)
|
||||
{
|
||||
|
@ -409,21 +332,18 @@ public class Dispatcher implements RequestDispatcher
|
|||
_attr.setAttribute(key,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "FORWARD+"+_attr.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void clearAttributes()
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void removeAttribute(String name)
|
||||
{
|
||||
|
@ -431,7 +351,6 @@ public class Dispatcher implements RequestDispatcher
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private class IncludeAttributes implements Attributes
|
||||
{
|
||||
final Attributes _attr;
|
||||
|
@ -447,9 +366,6 @@ public class Dispatcher implements RequestDispatcher
|
|||
_attr=attributes;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Object getAttribute(String key)
|
||||
{
|
||||
|
@ -468,7 +384,6 @@ public class Dispatcher implements RequestDispatcher
|
|||
return _attr.getAttribute(key);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Enumeration<String> getAttributeNames()
|
||||
{
|
||||
|
@ -499,7 +414,6 @@ public class Dispatcher implements RequestDispatcher
|
|||
return Collections.enumeration(set);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void setAttribute(String key, Object value)
|
||||
{
|
||||
|
@ -521,21 +435,18 @@ public class Dispatcher implements RequestDispatcher
|
|||
_attr.setAttribute(key,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "INCLUDE+"+_attr.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void clearAttributes()
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void removeAttribute(String name)
|
||||
{
|
||||
|
|
|
@ -40,7 +40,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncListener;
|
||||
import javax.servlet.DispatcherType;
|
||||
|
@ -177,7 +176,6 @@ public class Request implements HttpServletRequest
|
|||
private boolean _requestedSessionIdFromCookie = false;
|
||||
private volatile Attributes _attributes;
|
||||
private Authentication _authentication;
|
||||
private MultiMap<String> _baseParameters;
|
||||
private String _characterEncoding;
|
||||
private ContextHandler.Context _context;
|
||||
private String _contextPath;
|
||||
|
@ -186,6 +184,8 @@ public class Request implements HttpServletRequest
|
|||
private int _inputState = __NONE;
|
||||
private HttpMethod _httpMethod;
|
||||
private String _httpMethodString;
|
||||
private MultiMap<String> _queryParameters;
|
||||
private MultiMap<String> _contentParameters;
|
||||
private MultiMap<String> _parameters;
|
||||
private String _pathInfo;
|
||||
private int _port;
|
||||
|
@ -237,148 +237,43 @@ public class Request implements HttpServletRequest
|
|||
throw new IllegalArgumentException(listener.getClass().toString());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Extract Parameters from query string and/or form _content.
|
||||
*/
|
||||
public void extractParameters()
|
||||
{
|
||||
if (_baseParameters == null)
|
||||
_baseParameters = new MultiMap<>();
|
||||
|
||||
if (_paramsExtracted)
|
||||
{
|
||||
if (_parameters == null)
|
||||
_parameters = _baseParameters;
|
||||
return;
|
||||
}
|
||||
|
||||
_paramsExtracted = true;
|
||||
|
||||
try
|
||||
// Extract query string parameters; these may be replaced by a forward()
|
||||
// and may have already been extracted by mergeQueryParameters().
|
||||
if (_queryParameters == null)
|
||||
_queryParameters = extractQueryParameters();
|
||||
|
||||
// Extract content parameters; these cannot be replaced by a forward()
|
||||
// once extracted and may have already been extracted by getParts() or
|
||||
// by a processing happening after a form-based authentication.
|
||||
if (_contentParameters == null)
|
||||
_contentParameters = extractContentParameters();
|
||||
|
||||
_parameters = restoreParameters();
|
||||
}
|
||||
|
||||
private MultiMap<String> extractQueryParameters()
|
||||
{
|
||||
MultiMap<String> result = new MultiMap<>();
|
||||
if (_uri != null && _uri.hasQuery())
|
||||
{
|
||||
// Handle query string
|
||||
if (_uri != null && _uri.hasQuery())
|
||||
if (_queryEncoding == null)
|
||||
{
|
||||
if (_queryEncoding == null)
|
||||
_uri.decodeQueryTo(_baseParameters);
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
_uri.decodeQueryTo(_baseParameters,_queryEncoding);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.warn(e);
|
||||
else
|
||||
LOG.warn(e.toString());
|
||||
}
|
||||
}
|
||||
_uri.decodeQueryTo(result);
|
||||
}
|
||||
|
||||
// handle any _content.
|
||||
String encoding = getCharacterEncoding();
|
||||
String content_type = getContentType();
|
||||
if (content_type != null && content_type.length() > 0)
|
||||
{
|
||||
content_type = HttpFields.valueParameters(content_type,null);
|
||||
|
||||
if (MimeTypes.Type.FORM_ENCODED.is(content_type) && _inputState == __NONE &&
|
||||
(HttpMethod.POST.is(getMethod()) || HttpMethod.PUT.is(getMethod())))
|
||||
{
|
||||
int content_length = getContentLength();
|
||||
if (content_length != 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
int maxFormContentSize = -1;
|
||||
int maxFormKeys = -1;
|
||||
|
||||
if (_context != null)
|
||||
{
|
||||
maxFormContentSize = _context.getContextHandler().getMaxFormContentSize();
|
||||
maxFormKeys = _context.getContextHandler().getMaxFormKeys();
|
||||
}
|
||||
|
||||
if (maxFormContentSize < 0)
|
||||
{
|
||||
Object obj = _channel.getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
|
||||
if (obj == null)
|
||||
maxFormContentSize = 200000;
|
||||
else if (obj instanceof Number)
|
||||
{
|
||||
Number size = (Number)obj;
|
||||
maxFormContentSize = size.intValue();
|
||||
}
|
||||
else if (obj instanceof String)
|
||||
{
|
||||
maxFormContentSize = Integer.valueOf((String)obj);
|
||||
}
|
||||
}
|
||||
|
||||
if (maxFormKeys < 0)
|
||||
{
|
||||
Object obj = _channel.getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormKeys");
|
||||
if (obj == null)
|
||||
maxFormKeys = 1000;
|
||||
else if (obj instanceof Number)
|
||||
{
|
||||
Number keys = (Number)obj;
|
||||
maxFormKeys = keys.intValue();
|
||||
}
|
||||
else if (obj instanceof String)
|
||||
{
|
||||
maxFormKeys = Integer.valueOf((String)obj);
|
||||
}
|
||||
}
|
||||
|
||||
if (content_length > maxFormContentSize && maxFormContentSize > 0)
|
||||
{
|
||||
throw new IllegalStateException("Form too large " + content_length + ">" + maxFormContentSize);
|
||||
}
|
||||
InputStream in = getInputStream();
|
||||
if (_input.isAsync())
|
||||
throw new IllegalStateException("Cannot extract parameters with async IO");
|
||||
|
||||
// Add form params to query params
|
||||
UrlEncoded.decodeTo(in,_baseParameters,encoding,content_length < 0?maxFormContentSize:-1,maxFormKeys);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.warn(e);
|
||||
else
|
||||
LOG.warn(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (_parameters == null)
|
||||
_parameters = _baseParameters;
|
||||
else if (_parameters != _baseParameters)
|
||||
{
|
||||
// Merge parameters (needed if parameters extracted after a forward).
|
||||
_parameters.addAllValues(_baseParameters);
|
||||
}
|
||||
|
||||
if (content_type != null && content_type.length()>0 && content_type.startsWith("multipart/form-data") && getAttribute(__MULTIPART_CONFIG_ELEMENT)!=null)
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
getParts();
|
||||
_uri.decodeQueryTo(result, _queryEncoding);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.warn(e);
|
||||
else
|
||||
LOG.warn(e.toString());
|
||||
}
|
||||
catch (ServletException e)
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.warn(e);
|
||||
|
@ -387,11 +282,114 @@ public class Request implements HttpServletRequest
|
|||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
return result;
|
||||
}
|
||||
|
||||
private MultiMap<String> extractContentParameters()
|
||||
{
|
||||
MultiMap<String> result = new MultiMap<>();
|
||||
|
||||
String contentType = getContentType();
|
||||
if (contentType != null && !contentType.isEmpty())
|
||||
{
|
||||
// ensure params always set (even if empty) after extraction
|
||||
if (_parameters == null)
|
||||
_parameters = _baseParameters;
|
||||
contentType = HttpFields.valueParameters(contentType, null);
|
||||
int contentLength = getContentLength();
|
||||
if (contentLength != 0)
|
||||
{
|
||||
if (MimeTypes.Type.FORM_ENCODED.is(contentType) && _inputState == __NONE &&
|
||||
(HttpMethod.POST.is(getMethod()) || HttpMethod.PUT.is(getMethod())))
|
||||
{
|
||||
extractFormParameters(result);
|
||||
}
|
||||
else if (contentType.startsWith("multipart/form-data") &&
|
||||
getAttribute(__MULTIPART_CONFIG_ELEMENT) != null &&
|
||||
_multiPartInputStream == null)
|
||||
{
|
||||
extractMultipartParameters(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void extractFormParameters(MultiMap<String> params)
|
||||
{
|
||||
try
|
||||
{
|
||||
int maxFormContentSize = -1;
|
||||
int maxFormKeys = -1;
|
||||
|
||||
if (_context != null)
|
||||
{
|
||||
maxFormContentSize = _context.getContextHandler().getMaxFormContentSize();
|
||||
maxFormKeys = _context.getContextHandler().getMaxFormKeys();
|
||||
}
|
||||
|
||||
if (maxFormContentSize < 0)
|
||||
{
|
||||
Object obj = _channel.getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
|
||||
if (obj == null)
|
||||
maxFormContentSize = 200000;
|
||||
else if (obj instanceof Number)
|
||||
{
|
||||
Number size = (Number)obj;
|
||||
maxFormContentSize = size.intValue();
|
||||
}
|
||||
else if (obj instanceof String)
|
||||
{
|
||||
maxFormContentSize = Integer.valueOf((String)obj);
|
||||
}
|
||||
}
|
||||
|
||||
if (maxFormKeys < 0)
|
||||
{
|
||||
Object obj = _channel.getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormKeys");
|
||||
if (obj == null)
|
||||
maxFormKeys = 1000;
|
||||
else if (obj instanceof Number)
|
||||
{
|
||||
Number keys = (Number)obj;
|
||||
maxFormKeys = keys.intValue();
|
||||
}
|
||||
else if (obj instanceof String)
|
||||
{
|
||||
maxFormKeys = Integer.valueOf((String)obj);
|
||||
}
|
||||
}
|
||||
|
||||
int contentLength = getContentLength();
|
||||
if (contentLength > maxFormContentSize && maxFormContentSize > 0)
|
||||
{
|
||||
throw new IllegalStateException("Form too large: " + contentLength + " > " + maxFormContentSize);
|
||||
}
|
||||
InputStream in = getInputStream();
|
||||
if (_input.isAsync())
|
||||
throw new IllegalStateException("Cannot extract parameters with async IO");
|
||||
|
||||
UrlEncoded.decodeTo(in,params,getCharacterEncoding(),contentLength<0?maxFormContentSize:-1,maxFormKeys);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.warn(e);
|
||||
else
|
||||
LOG.warn(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void extractMultipartParameters(MultiMap<String> result)
|
||||
{
|
||||
try
|
||||
{
|
||||
getParts(result);
|
||||
}
|
||||
catch (IOException | ServletException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.warn(e);
|
||||
else
|
||||
LOG.warn(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -827,6 +825,8 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
if (!_paramsExtracted)
|
||||
extractParameters();
|
||||
if (_parameters == null)
|
||||
_parameters = restoreParameters();
|
||||
return _parameters.getValue(name,0);
|
||||
}
|
||||
|
||||
|
@ -839,7 +839,8 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
if (!_paramsExtracted)
|
||||
extractParameters();
|
||||
|
||||
if (_parameters == null)
|
||||
_parameters = restoreParameters();
|
||||
return Collections.unmodifiableMap(_parameters.toStringArrayMap());
|
||||
}
|
||||
|
||||
|
@ -852,18 +853,11 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
if (!_paramsExtracted)
|
||||
extractParameters();
|
||||
if (_parameters == null)
|
||||
_parameters = restoreParameters();
|
||||
return Collections.enumeration(_parameters.keySet());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return Returns the parameters.
|
||||
*/
|
||||
public MultiMap<String> getParameters()
|
||||
{
|
||||
return _parameters;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see javax.servlet.ServletRequest#getParameterValues(java.lang.String)
|
||||
|
@ -873,12 +867,44 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
if (!_paramsExtracted)
|
||||
extractParameters();
|
||||
if (_parameters == null)
|
||||
_parameters = restoreParameters();
|
||||
List<String> vals = _parameters.getValues(name);
|
||||
if (vals == null)
|
||||
return null;
|
||||
return vals.toArray(new String[vals.size()]);
|
||||
}
|
||||
|
||||
private MultiMap<String> restoreParameters()
|
||||
{
|
||||
MultiMap<String> result = new MultiMap<>();
|
||||
if (_queryParameters == null)
|
||||
_queryParameters = extractQueryParameters();
|
||||
result.addAllValues(_queryParameters);
|
||||
result.addAllValues(_contentParameters);
|
||||
return result;
|
||||
}
|
||||
|
||||
public MultiMap<String> getQueryParameters()
|
||||
{
|
||||
return _queryParameters;
|
||||
}
|
||||
|
||||
public void setQueryParameters(MultiMap<String> queryParameters)
|
||||
{
|
||||
_queryParameters = queryParameters;
|
||||
}
|
||||
|
||||
public void setContentParameters(MultiMap<String> contentParameters)
|
||||
{
|
||||
_contentParameters = contentParameters;
|
||||
}
|
||||
|
||||
public void resetParameters()
|
||||
{
|
||||
_parameters = null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see javax.servlet.http.HttpServletRequest#getPathInfo()
|
||||
|
@ -1620,8 +1646,8 @@ public class Request implements HttpServletRequest
|
|||
_servletPath = null;
|
||||
_timeStamp = 0;
|
||||
_uri = null;
|
||||
if (_baseParameters != null)
|
||||
_baseParameters.clear();
|
||||
_queryParameters = null;
|
||||
_contentParameters = null;
|
||||
_parameters = null;
|
||||
_paramsExtracted = false;
|
||||
_inputState = __NONE;
|
||||
|
@ -1858,18 +1884,6 @@ public class Request implements HttpServletRequest
|
|||
return HttpMethod.HEAD==_httpMethod;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param parameters
|
||||
* The parameters to set.
|
||||
*/
|
||||
public void setParameters(MultiMap<String> parameters)
|
||||
{
|
||||
_parameters = (parameters == null)?_baseParameters:parameters;
|
||||
if (_paramsExtracted && _parameters == null)
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param pathInfo
|
||||
|
@ -2103,10 +2117,14 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
if (getContentType() == null || !getContentType().startsWith("multipart/form-data"))
|
||||
throw new ServletException("Content-Type != multipart/form-data");
|
||||
return getParts(null);
|
||||
}
|
||||
|
||||
private Collection<Part> getParts(MultiMap<String> params) throws IOException, ServletException
|
||||
{
|
||||
if (_multiPartInputStream == null)
|
||||
_multiPartInputStream = (MultiPartInputStreamParser)getAttribute(__MULTIPART_INPUT_STREAM);
|
||||
|
||||
|
||||
if (_multiPartInputStream == null)
|
||||
{
|
||||
MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT);
|
||||
|
@ -2127,20 +2145,20 @@ public class Request implements HttpServletRequest
|
|||
MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p;
|
||||
if (mp.getContentDispositionFilename() == null)
|
||||
{
|
||||
//Servlet Spec 3.0 pg 23, parts without filenames must be put into init params
|
||||
// Servlet Spec 3.0 pg 23, parts without filename must be put into params.
|
||||
String charset = null;
|
||||
if (mp.getContentType() != null)
|
||||
charset = MimeTypes.getCharsetFromContentType(mp.getContentType());
|
||||
|
||||
//get the bytes regardless of being in memory or in temp file
|
||||
try (InputStream is = mp.getInputStream())
|
||||
{
|
||||
if (os == null)
|
||||
os = new ByteArrayOutputStream();
|
||||
IO.copy(is, os);
|
||||
String content=new String(os.toByteArray(),charset==null?StandardCharsets.UTF_8:Charset.forName(charset));
|
||||
getParameter(""); //cause params to be evaluated
|
||||
getParameters().add(mp.getName(), content);
|
||||
if (_contentParameters == null)
|
||||
_contentParameters = params == null ? new MultiMap<String>() : params;
|
||||
_contentParameters.add(mp.getName(), content);
|
||||
}
|
||||
os.reset();
|
||||
}
|
||||
|
@ -2175,72 +2193,57 @@ public class Request implements HttpServletRequest
|
|||
_authentication=Authentication.UNAUTHENTICATED;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Merge in a new query string. The query string is merged with the existing parameters and {@link #setParameters(MultiMap)} and
|
||||
* {@link #setQueryString(String)} are called with the result. The merge is according to the rules of the servlet dispatch forward method.
|
||||
*
|
||||
* @param query
|
||||
* The query string to merge into the request.
|
||||
*/
|
||||
public void mergeQueryString(String query)
|
||||
public void mergeQueryParameters(String newQuery, boolean updateQueryString)
|
||||
{
|
||||
// extract parameters from dispatch query
|
||||
MultiMap<String> parameters = new MultiMap<>();
|
||||
UrlEncoded.decodeTo(query,parameters, UrlEncoded.ENCODING,-1); //have to assume ENCODING because we can't know otherwise
|
||||
MultiMap<String> newQueryParams = new MultiMap<>();
|
||||
// Have to assume ENCODING because we can't know otherwise.
|
||||
UrlEncoded.decodeTo(newQuery, newQueryParams, UrlEncoded.ENCODING, -1);
|
||||
|
||||
boolean merge_old_query = false;
|
||||
|
||||
// Have we evaluated parameters
|
||||
if (!_paramsExtracted)
|
||||
extractParameters();
|
||||
|
||||
// Are there any existing parameters?
|
||||
if (_parameters != null && _parameters.size() > 0)
|
||||
MultiMap<String> oldQueryParams = _queryParameters;
|
||||
if (oldQueryParams == null && _queryString != null)
|
||||
{
|
||||
// Merge parameters; new parameters of the same name take precedence.
|
||||
merge_old_query = parameters.addAllValues(_parameters);
|
||||
oldQueryParams = new MultiMap<>();
|
||||
UrlEncoded.decodeTo(_queryString, oldQueryParams, getQueryEncoding(), -1);
|
||||
}
|
||||
|
||||
if (_queryString != null && _queryString.length() > 0)
|
||||
MultiMap<String> mergedQueryParams = new MultiMap<>(newQueryParams);
|
||||
boolean hasParamsInCommon = false;
|
||||
if (oldQueryParams != null)
|
||||
{
|
||||
if (merge_old_query)
|
||||
// Parameters in the newQuery replace parameters of the oldQuery.
|
||||
MultiMap<String> copy = new MultiMap<>(oldQueryParams);
|
||||
hasParamsInCommon = copy.keySet().removeAll(newQueryParams.keySet());
|
||||
mergedQueryParams.addAllValues(copy);
|
||||
}
|
||||
|
||||
setQueryParameters(mergedQueryParams);
|
||||
resetParameters();
|
||||
|
||||
if (updateQueryString)
|
||||
{
|
||||
// Build the new merged query string.
|
||||
StringBuilder mergedQuery = new StringBuilder(newQuery);
|
||||
if (hasParamsInCommon)
|
||||
{
|
||||
StringBuilder overridden_query_string = new StringBuilder();
|
||||
MultiMap<String> overridden_old_query = new MultiMap<>();
|
||||
UrlEncoded.decodeTo(_queryString,overridden_old_query,getQueryEncoding(),-1);//decode using any queryencoding set for the request
|
||||
|
||||
|
||||
MultiMap<String> overridden_new_query = new MultiMap<>();
|
||||
UrlEncoded.decodeTo(query,overridden_new_query,UrlEncoded.ENCODING,-1); //have to assume ENCODING as we cannot know otherwise
|
||||
|
||||
for(String name: overridden_old_query.keySet())
|
||||
for (Map.Entry<String, List<String>> entry : mergedQueryParams.entrySet())
|
||||
{
|
||||
if (!overridden_new_query.containsKey(name))
|
||||
{
|
||||
List<String> values = overridden_old_query.get(name);
|
||||
for(String v: values)
|
||||
{
|
||||
overridden_query_string.append("&").append(name).append("=").append(v);
|
||||
}
|
||||
}
|
||||
if (newQueryParams.containsKey(entry.getKey()))
|
||||
continue;
|
||||
for (String value : entry.getValue())
|
||||
mergedQuery.append("&").append(entry.getKey()).append("=").append(value);
|
||||
}
|
||||
|
||||
query = query + overridden_query_string;
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query + "&" + _queryString;
|
||||
if (_queryString != null)
|
||||
mergedQuery.append("&").append(_queryString);
|
||||
}
|
||||
}
|
||||
|
||||
setParameters(parameters);
|
||||
setQueryString(query);
|
||||
setQueryString(mergedQuery.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* @see javax.servlet.http.HttpServletRequest#upgrade(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
|
|
|
@ -32,7 +32,6 @@ import java.util.List;
|
|||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -502,7 +501,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
baseRequest.setRequestURI(null);
|
||||
baseRequest.setPathInfo(baseRequest.getRequestURI());
|
||||
if (uri.getQuery()!=null)
|
||||
baseRequest.mergeQueryString(uri.getQuery()); //we have to assume dispatch path and query are UTF8
|
||||
baseRequest.mergeQueryParameters(uri.getQuery(), true); //we have to assume dispatch path and query are UTF8
|
||||
}
|
||||
|
||||
final String target=baseRequest.getPathInfo();
|
||||
|
|
|
@ -0,0 +1,518 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DispatcherForwardTest
|
||||
{
|
||||
private Server server;
|
||||
private LocalConnector connector;
|
||||
private HttpServlet servlet1;
|
||||
private HttpServlet servlet2;
|
||||
private List<Exception> failures = new ArrayList<>();
|
||||
|
||||
public void prepare() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new LocalConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler(server, "/");
|
||||
context.addServlet(new ServletHolder(servlet1), "/one");
|
||||
context.addServlet(new ServletHolder(servlet2), "/two");
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void dispose() throws Exception
|
||||
{
|
||||
for (Exception failure : failures)
|
||||
throw failure;
|
||||
server.stop();
|
||||
}
|
||||
|
||||
// Replacement for Assert that allows to check failures after the response has been sent.
|
||||
private <S> void checkThat(S item, Matcher<S> matcher)
|
||||
{
|
||||
if (!matcher.matches(item))
|
||||
failures.add(new Exception());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryRetainedByForwardWithoutQuery() throws Exception
|
||||
{
|
||||
// 1. request /one?a=1
|
||||
// 1. forward /two
|
||||
// 2. assert query => a=1
|
||||
// 1. assert query => a=1
|
||||
|
||||
final String query1 = "a=1";
|
||||
servlet1 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
|
||||
req.getRequestDispatcher("/two").forward(req, resp);
|
||||
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat("1", Matchers.equalTo(req.getParameter("a")));
|
||||
}
|
||||
};
|
||||
servlet2 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat("1", Matchers.equalTo(req.getParameter("a")));
|
||||
}
|
||||
};
|
||||
|
||||
prepare();
|
||||
|
||||
String request = "" +
|
||||
"GET /one?" + query1 + " HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n";
|
||||
String response = connector.getResponses(request);
|
||||
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryReplacedByForwardWithQuery() throws Exception
|
||||
{
|
||||
// 1. request /one?a=1
|
||||
// 1. forward /two?a=2
|
||||
// 2. assert query => a=2
|
||||
// 1. assert query => a=1
|
||||
|
||||
final String query1 = "a=1&b=2";
|
||||
final String query2 = "a=3";
|
||||
final String query3 = "a=3&b=2";
|
||||
servlet1 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
|
||||
req.getRequestDispatcher("/two?" + query2).forward(req, resp);
|
||||
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat("1", Matchers.equalTo(req.getParameter("a")));
|
||||
checkThat("2", Matchers.equalTo(req.getParameter("b")));
|
||||
}
|
||||
};
|
||||
servlet2 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query3, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat("3", Matchers.equalTo(req.getParameter("a")));
|
||||
checkThat("2", Matchers.equalTo(req.getParameter("b")));
|
||||
}
|
||||
};
|
||||
|
||||
prepare();
|
||||
|
||||
String request = "" +
|
||||
"GET /one?" + query1 + " HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n";
|
||||
String response = connector.getResponses(request);
|
||||
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryMergedByForwardWithQuery() throws Exception
|
||||
{
|
||||
// 1. request /one?a=1
|
||||
// 1. forward /two?b=2
|
||||
// 2. assert query => a=1&b=2
|
||||
// 1. assert query => a=1
|
||||
|
||||
final String query1 = "a=1";
|
||||
final String query2 = "b=2";
|
||||
final String query3 = "b=2&a=1";
|
||||
servlet1 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
|
||||
req.getRequestDispatcher("/two?" + query2).forward(req, resp);
|
||||
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat("1", Matchers.equalTo(req.getParameter("a")));
|
||||
}
|
||||
};
|
||||
servlet2 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query3, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat("1", Matchers.equalTo(req.getParameter("a")));
|
||||
checkThat("2", Matchers.equalTo(req.getParameter("b")));
|
||||
}
|
||||
};
|
||||
|
||||
prepare();
|
||||
|
||||
String request = "" +
|
||||
"GET /one?" + query1 + " HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n";
|
||||
String response = connector.getResponses(request);
|
||||
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryAggregatesWithFormByForwardWithoutQuery() throws Exception
|
||||
{
|
||||
// 1. request /one?a=1 + content a=2
|
||||
// 1. forward /two
|
||||
// 2. assert query => a=1 + params => a=1,2
|
||||
// 1. assert query => a=1 + params => a=1,2
|
||||
|
||||
final String query1 = "a=1";
|
||||
final String form = "a=2";
|
||||
servlet1 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
|
||||
req.getRequestDispatcher("/two").forward(req, resp);
|
||||
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
String[] values = req.getParameterValues("a");
|
||||
checkThat(values, Matchers.notNullValue());
|
||||
checkThat(2, Matchers.equalTo(values.length));
|
||||
checkThat(values, Matchers.arrayContainingInAnyOrder("1", "2"));
|
||||
}
|
||||
};
|
||||
servlet2 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
String[] values = req.getParameterValues("a");
|
||||
checkThat(values, Matchers.notNullValue());
|
||||
checkThat(2, Matchers.equalTo(values.length));
|
||||
checkThat(values, Matchers.arrayContainingInAnyOrder("1", "2"));
|
||||
}
|
||||
};
|
||||
|
||||
prepare();
|
||||
|
||||
String request = "" +
|
||||
"POST /one?" + query1 + " HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: " + form.length() + "\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n" +
|
||||
form;
|
||||
String response = connector.getResponses(request);
|
||||
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryAggregatesWithFormReplacedByForwardWithQuery() throws Exception
|
||||
{
|
||||
// 1. request /one?a=1 + content a=2
|
||||
// 1. forward /two?a=3
|
||||
// 2. assert query => a=3 + params => a=3,2
|
||||
// 1. assert query => a=1 + params => a=1,2
|
||||
|
||||
final String query1 = "a=1";
|
||||
final String query2 = "a=3";
|
||||
final String form = "a=2";
|
||||
servlet1 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
|
||||
req.getRequestDispatcher("/two?" + query2).forward(req, resp);
|
||||
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
String[] values = req.getParameterValues("a");
|
||||
checkThat(values, Matchers.notNullValue());
|
||||
checkThat(2, Matchers.equalTo(values.length));
|
||||
checkThat(values, Matchers.arrayContainingInAnyOrder("1", "2"));
|
||||
}
|
||||
};
|
||||
servlet2 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query2, Matchers.equalTo(req.getQueryString()));
|
||||
String[] values = req.getParameterValues("a");
|
||||
checkThat(values, Matchers.notNullValue());
|
||||
checkThat(2, Matchers.equalTo(values.length));
|
||||
checkThat(values, Matchers.arrayContainingInAnyOrder("3", "2"));
|
||||
}
|
||||
};
|
||||
|
||||
prepare();
|
||||
|
||||
String request = "" +
|
||||
"POST /one?" + query1 + " HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: " + form.length() + "\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n" +
|
||||
form;
|
||||
String response = connector.getResponses(request);
|
||||
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryAggregatesWithFormMergedByForwardWithQuery() throws Exception
|
||||
{
|
||||
// 1. request /one?a=1 + content b=2
|
||||
// 1. forward /two?c=3
|
||||
// 2. assert query => a=1&c=3 + params => a=1&b=2&c=3
|
||||
// 1. assert query => a=1 + params => a=1&b=2
|
||||
|
||||
final String query1 = "a=1";
|
||||
final String query2 = "c=3";
|
||||
final String query3 = "c=3&a=1";
|
||||
final String form = "b=2";
|
||||
servlet1 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
|
||||
req.getRequestDispatcher("/two?" + query2).forward(req, resp);
|
||||
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat("1", Matchers.equalTo(req.getParameter("a")));
|
||||
checkThat("2", Matchers.equalTo(req.getParameter("b")));
|
||||
checkThat(req.getParameter("c"), Matchers.nullValue());
|
||||
}
|
||||
};
|
||||
servlet2 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query3, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat("1", Matchers.equalTo(req.getParameter("a")));
|
||||
checkThat("2", Matchers.equalTo(req.getParameter("b")));
|
||||
checkThat("3", Matchers.equalTo(req.getParameter("c")));
|
||||
}
|
||||
};
|
||||
|
||||
prepare();
|
||||
|
||||
String request = "" +
|
||||
"POST /one?" + query1 + " HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: " + form.length() + "\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n" +
|
||||
form;
|
||||
String response = connector.getResponses(request);
|
||||
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryAggregatesWithFormBeforeAndAfterForward() throws Exception
|
||||
{
|
||||
// 1. request /one?a=1 + content b=2
|
||||
// 1. assert params => a=1&b=2
|
||||
// 1. forward /two?c=3
|
||||
// 2. assert query => a=1&c=3 + params => a=1&b=2&c=3
|
||||
// 1. assert query => a=1 + params => a=1&b=2
|
||||
|
||||
final String query1 = "a=1";
|
||||
final String query2 = "c=3";
|
||||
final String query3 = "c=3&a=1";
|
||||
final String form = "b=2";
|
||||
servlet1 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat("1", Matchers.equalTo(req.getParameter("a")));
|
||||
checkThat("2", Matchers.equalTo(req.getParameter("b")));
|
||||
|
||||
req.getRequestDispatcher("/two?" + query2).forward(req, resp);
|
||||
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat("1", Matchers.equalTo(req.getParameter("a")));
|
||||
checkThat("2", Matchers.equalTo(req.getParameter("b")));
|
||||
checkThat(req.getParameter("c"), Matchers.nullValue());
|
||||
}
|
||||
};
|
||||
servlet2 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query3, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat("1", Matchers.equalTo(req.getParameter("a")));
|
||||
checkThat("2", Matchers.equalTo(req.getParameter("b")));
|
||||
checkThat("3", Matchers.equalTo(req.getParameter("c")));
|
||||
}
|
||||
};
|
||||
|
||||
prepare();
|
||||
|
||||
String request = "" +
|
||||
"POST /one?" + query1 + " HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: " + form.length() + "\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n" +
|
||||
form;
|
||||
String response = connector.getResponses(request);
|
||||
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContentCanBeReadViaInputStreamAfterForwardWithoutQuery() throws Exception
|
||||
{
|
||||
final String query1 = "a=1";
|
||||
final String form = "c=3";
|
||||
servlet1 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
|
||||
req.getRequestDispatcher("/two").forward(req, resp);
|
||||
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat(req.getParameter("c"), Matchers.nullValue());
|
||||
}
|
||||
};
|
||||
servlet2 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
ServletInputStream input = req.getInputStream();
|
||||
for (int i = 0; i < form.length(); ++i)
|
||||
checkThat(form.charAt(i) & 0xFFFF, Matchers.equalTo(input.read()));
|
||||
}
|
||||
};
|
||||
|
||||
prepare();
|
||||
|
||||
String request = "" +
|
||||
"POST /one?" + query1 + " HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: " + form.length() + "\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n" +
|
||||
form;
|
||||
String response = connector.getResponses(request);
|
||||
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContentCanBeReadViaInputStreamAfterForwardWithQuery() throws Exception
|
||||
{
|
||||
final String query1 = "a=1";
|
||||
final String query2 = "b=2";
|
||||
final String query3 = "b=2&a=1";
|
||||
final String form = "c=3";
|
||||
servlet1 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
|
||||
req.getRequestDispatcher("/two?" + query2).forward(req, resp);
|
||||
|
||||
checkThat(query1, Matchers.equalTo(req.getQueryString()));
|
||||
checkThat(req.getParameter("c"), Matchers.nullValue());
|
||||
}
|
||||
};
|
||||
servlet2 = new HttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
checkThat(query3, Matchers.equalTo(req.getQueryString()));
|
||||
ServletInputStream input = req.getInputStream();
|
||||
for (int i = 0; i < form.length(); ++i)
|
||||
checkThat(form.charAt(i) & 0xFFFF, Matchers.equalTo(input.read()));
|
||||
checkThat(-1, Matchers.equalTo(input.read()));
|
||||
}
|
||||
};
|
||||
|
||||
prepare();
|
||||
|
||||
String request = "" +
|
||||
"POST /one?" + query1 + " HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: " + form.length() + "\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n" +
|
||||
form;
|
||||
String response = connector.getResponses(request);
|
||||
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
// TODO: add multipart tests
|
||||
}
|
|
@ -18,18 +18,11 @@
|
|||
|
||||
package org.eclipse.jetty.servlet;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
|
@ -64,6 +57,12 @@ import org.junit.Assert;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class DispatcherTest
|
||||
{
|
||||
private Server _server;
|
||||
|
@ -349,7 +348,6 @@ public class DispatcherTest
|
|||
dispatcher = getServletContext().getRequestDispatcher("/IncludeServlet/includepath?do=assertforwardinclude");
|
||||
else if(request.getParameter("do").equals("assertincludeforward"))
|
||||
dispatcher = getServletContext().getRequestDispatcher("/AssertIncludeForwardServlet/assertpath?do=end");
|
||||
|
||||
else if(request.getParameter("do").equals("assertforward"))
|
||||
dispatcher = getServletContext().getRequestDispatcher("/AssertForwardServlet?do=end&do=the");
|
||||
else if(request.getParameter("do").equals("ctx.echo"))
|
||||
|
|
Loading…
Reference in New Issue