Merge pull request #8341 from eclipse/jetty-12.0.x-dispatcher-fixes

fix some tests for Jetty 12 ee10 servlets
This commit is contained in:
Lachlan 2022-07-28 18:57:19 +10:00 committed by GitHub
commit 0f35590ab4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 229 additions and 169 deletions

View File

@ -195,6 +195,7 @@ public class ServletPathSpec extends AbstractPathSpec
servletPathSpec = "";
if (servletPathSpec.startsWith("servlet|"))
servletPathSpec = servletPathSpec.substring("servlet|".length());
servletPathSpec = URIUtil.canonicalPath(servletPathSpec);
assertValidServletPathSpec(servletPathSpec);
// The Root Path Spec

View File

@ -44,6 +44,7 @@ import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.component.ClassLoaderDump;
import org.eclipse.jetty.util.component.Dumpable;
@ -669,7 +670,7 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
{
if (isStarted())
throw new IllegalStateException(getState());
_contextPath = contextPath;
_contextPath = URIUtil.canonicalPath(contextPath);
}
/**

View File

@ -15,13 +15,11 @@ package org.eclipse.jetty.ee10.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.RequestDispatcher;
@ -36,6 +34,7 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;
import org.eclipse.jetty.ee10.servlet.util.ServletOutputStreamWrapper;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.UrlEncoded;
@ -125,8 +124,16 @@ public class Dispatcher implements RequestDispatcher
{
HttpServletRequest httpRequest = (request instanceof HttpServletRequest) ? (HttpServletRequest)request : new ServletRequestHttpWrapper(request);
HttpServletResponse httpResponse = (response instanceof HttpServletResponse) ? (HttpServletResponse)response : new ServletResponseHttpWrapper(response);
ServletContextResponse baseResponse = ServletContextResponse.getBaseResponse(response);
_mappedServlet.handle(_servletHandler, _pathInContext, new IncludeRequest(httpRequest), new IncludeResponse(httpResponse));
try
{
_mappedServlet.handle(_servletHandler, _pathInContext, new IncludeRequest(httpRequest), new IncludeResponse(httpResponse));
}
finally
{
baseResponse.included();
}
}
public void async(ServletRequest request, ServletResponse response) throws ServletException, IOException
@ -139,85 +146,81 @@ public class Dispatcher implements RequestDispatcher
public class ParameterRequestWrapper extends HttpServletRequestWrapper
{
private Map<String, String[]> params;
private final MultiMap<String> _params = new MultiMap<>();
private boolean decodedParams = false;
private final HttpServletRequest _httpServletRequest;
private final ServletContextRequest _baseRequest;
public ParameterRequestWrapper(HttpServletRequest request)
{
super(request);
_httpServletRequest = request;
// Have to assume ENCODING because we can't know otherwise.
String targetQuery = (_uri == null) ? null : _uri.getQuery();
if (targetQuery != null)
UrlEncoded.decodeTo(targetQuery, _params, UrlEncoded.ENCODING);
_baseRequest = ServletContextRequest.getBaseRequest(_httpServletRequest);
if (_baseRequest == null)
throw new IllegalStateException();
Fields queryParams = _baseRequest.getServletApiRequest().getQueryParams();
for (Fields.Field field : queryParams)
{
_params.addValues(field.getName(), field.getValues());
}
}
private MultiMap<String> getParams()
{
if (decodedParams)
return _params;
decodedParams = true;
Fields contentParams = _baseRequest.getServletApiRequest().getContentParams();
for (Fields.Field field : contentParams)
{
_params.addValues(field.getName(), field.getValues());
}
return _params;
}
@Override
public String getParameter(String name)
{
String[] strings = getParameterMap().get(name);
if (strings == null || strings.length == 0)
return null;
return strings[0];
return getParams().getValue(name);
}
@Override
public Map<String, String[]> getParameterMap()
{
if (params != null)
return params;
Map<String, String[]> oldParams = super.getParameterMap();
if (_uri == null || _uri.getQuery() == null)
{
params = oldParams;
return oldParams;
}
MultiMap<String> newParams = new MultiMap<>();
UrlEncoded.decodeTo(_uri.getQuery(), newParams, UrlEncoded.ENCODING);
for (Map.Entry<String, String[]> entry : oldParams.entrySet())
{
newParams.addValues(entry.getKey(), entry.getValue());
}
params = newParams.toStringArrayMap();
return params;
return Collections.unmodifiableMap(getParams().toStringArrayMap());
}
@Override
public Enumeration<String> getParameterNames()
{
return Collections.enumeration(getParameterMap().entrySet().stream()
.flatMap(o -> Arrays.stream(o.getValue()))
.collect(Collectors.toList()));
return Collections.enumeration(getParams().keySet());
}
@Override
public String[] getParameterValues(String name)
{
return getParameterMap().get(name);
List<String> vals = getParams().getValues(name);
if (vals == null)
return null;
return vals.toArray(new String[0]);
}
}
private class ForwardRequest extends ParameterRequestWrapper
{
private final HttpServletRequest _httpServletRequest;
private final MultiMap<String> _params = new MultiMap<>();
public ForwardRequest(HttpServletRequest httpRequest)
{
super(httpRequest);
String targetQuery = (_uri == null) ? null : _uri.getQuery();
if (targetQuery != null)
{
// Have to assume ENCODING because we can't know otherwise.
UrlEncoded.decodeTo(targetQuery, _params, UrlEncoded.ENCODING);
}
Enumeration<String> parameterNames = httpRequest.getParameterNames();
while (parameterNames.hasMoreElements())
{
String name = parameterNames.nextElement();
String[] parameterValues = httpRequest.getParameterValues(name);
if (parameterValues != null)
_params.addValues(name, parameterValues);
}
_httpServletRequest = httpRequest;
}
@ -261,33 +264,6 @@ public class Dispatcher implements RequestDispatcher
return _httpServletRequest.getQueryString();
}
@Override
public String getParameter(String name)
{
return _params.getValue(name);
}
@Override
public Map<String, String[]> getParameterMap()
{
return Collections.unmodifiableMap(_params.toStringArrayMap());
}
@Override
public Enumeration<String> getParameterNames()
{
return Collections.enumeration(_params.keySet());
}
@Override
public String[] getParameterValues(String name)
{
List<String> vals = _params.getValues(name);
if (vals == null)
return null;
return vals.toArray(new String[0]);
}
@Override
public String getRequestURI()
{
@ -501,6 +477,7 @@ public class Dispatcher implements RequestDispatcher
{
super(httpRequest);
_httpServletRequest = httpRequest;
Objects.requireNonNull(_servletPathMapping);
}
@Override
@ -512,13 +489,22 @@ public class Dispatcher implements RequestDispatcher
@Override
public String getPathInfo()
{
return _mappedServlet.getServletPathMapping(_pathInContext).getPathInfo();
// TODO what about a 404 dispatch?
return Objects.requireNonNull(_servletPathMapping).getPathInfo();
}
@Override
public String getServletPath()
{
return _mappedServlet.getServletPathMapping(_pathInContext).getServletPath();
// TODO what about a 404 dispatch?
return Objects.requireNonNull(_servletPathMapping).getServletPath();
}
@Override
public HttpServletMapping getHttpServletMapping()
{
// TODO what about a 404 dispatch?
return Objects.requireNonNull(_servletPathMapping);
}
@Override

View File

@ -419,7 +419,7 @@ public class ServletChannel implements Runnable
}
Dispatcher dispatcher = new Dispatcher(getContextHandler(), uri, pathInContext);
dispatcher.async(_request.getHttpServletRequest(), getResponse().getHttpServletResponse());
dispatcher.async(asyncContextEvent.getSuppliedRequest(), asyncContextEvent.getSuppliedResponse());
});
break;
}
@ -607,6 +607,7 @@ public class ServletChannel implements Runnable
{
try
{
_request.getResponse().getHttpOutput().reopen();
_servletContextApi.getContext().getServletContextHandler().requestInitialized(_request, _request.getHttpServletRequest());
getHttpOutput().reopen();
_combinedListener.onBeforeDispatch(_request);

View File

@ -702,7 +702,7 @@ public class ServletContextHandler extends ContextHandler implements Graceful
}
super.setContextPath(contextPath);
_contextPathEncoded = URIUtil.encodePath(contextPath);
_contextPathEncoded = URIUtil.canonicalPath(contextPath);
if (getServer() != null && (getServer().isStarting() || getServer().isStarted()))
{

View File

@ -183,8 +183,7 @@ public class ServletContextRequest extends ContextRequest implements Runnable
public void errorClose()
{
// TODO Actually make the response status and headers immutable temporarily
// TODO: This soft close breaks ErrorPageTest, AsyncContextTest
// _response.getHttpOutput().softClose();
_response.getHttpOutput().softClose();
}
public boolean isHead()
@ -205,6 +204,11 @@ public class ServletContextRequest extends ContextRequest implements Runnable
_queryEncoding = Charset.forName(queryEncoding);
}
public Charset getQueryEncoding()
{
return _queryEncoding;
}
@Override
public Object getAttribute(String name)
{
@ -335,6 +339,18 @@ public class ServletContextRequest extends ContextRequest implements Runnable
return apiSession.getCoreSession();
return null;
}
public Fields getQueryParams()
{
extractQueryParameters();
return _queryParameters;
}
public Fields getContentParams()
{
extractContentParameters();
return _contentParameters;
}
public void setAuthentication(Authentication authentication)
{
@ -949,33 +965,8 @@ public class ServletContextRequest extends ContextRequest implements Runnable
private Fields getParameters()
{
if (!_contentParamsExtracted)
{
// content parameters need boolean protection as they can only be read
// once, but may be reset to null by a reset
_contentParamsExtracted = true;
// 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)
{
try
{
extractContentParameters();
}
catch (IllegalStateException | IllegalArgumentException | ExecutionException | InterruptedException e)
{
LOG.warn(e.toString());
throw new BadMessageException("Unable to parse form content", e);
}
}
}
// Extract query string parameters; these may be replaced by a forward()
// and may have already been extracted by mergeQueryParameters().
if (_queryParameters == null)
extractQueryParameters();
extractContentParameters();
extractQueryParameters();
// Do parameters need to be combined?
if (isNoParams(_queryParameters) || _queryParameters.getSize() == 0)
@ -994,28 +985,54 @@ public class ServletContextRequest extends ContextRequest implements Runnable
return parameters == null ? NO_PARAMS : parameters;
}
private void extractContentParameters() throws ExecutionException, InterruptedException
private void extractContentParameters() throws BadMessageException
{
_contentParameters = FutureFormFields.forRequest(getRequest()).get();
if (_contentParameters == null || _contentParameters.isEmpty())
_contentParameters = NO_PARAMS;
if (!_contentParamsExtracted)
{
// content parameters need boolean protection as they can only be read
// once, but may be reset to null by a reset
_contentParamsExtracted = true;
// 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)
{
try
{
_contentParameters = FutureFormFields.forRequest(getRequest()).get();
if (_contentParameters == null || _contentParameters.isEmpty())
_contentParameters = NO_PARAMS;
}
catch (IllegalStateException | IllegalArgumentException | ExecutionException | InterruptedException e)
{
LOG.warn(e.toString());
throw new BadMessageException("Unable to parse form content", e);
}
}
}
}
private void extractQueryParameters()
private void extractQueryParameters() throws BadMessageException
{
HttpURI httpURI = ServletContextRequest.this.getHttpURI();
if (httpURI == null || StringUtil.isEmpty(httpURI.getQuery()))
_queryParameters = NO_PARAMS;
else
// Extract query string parameters; these may be replaced by a forward()
// and may have already been extracted by mergeQueryParameters().
if (_queryParameters == null)
{
try
HttpURI httpURI = ServletContextRequest.this.getHttpURI();
if (httpURI == null || StringUtil.isEmpty(httpURI.getQuery()))
_queryParameters = NO_PARAMS;
else
{
_queryParameters = Request.extractQueryParameters(ServletContextRequest.this, _queryEncoding);
}
catch (IllegalStateException | IllegalArgumentException e)
{
_queryParameters = BAD_PARAMS;
throw new BadMessageException("Unable to parse URI query", e);
try
{
_queryParameters = Request.extractQueryParameters(ServletContextRequest.this, _queryEncoding);
}
catch (IllegalStateException | IllegalArgumentException e)
{
_queryParameters = BAD_PARAMS;
throw new BadMessageException("Unable to parse URI query", e);
}
}
}
}

View File

@ -134,11 +134,17 @@ public class ServletContextResponse extends ContextResponse
public void resetForForward()
{
_httpOutput.resetBuffer();
_httpOutput.reopen();
_httpServletResponse.resetBuffer();
_outputType = OutputType.NONE;
}
public void included()
{
if (_outputType == OutputType.WRITER)
_writer.reopen();
_httpOutput.reopen();
}
public void completeOutput(Callback callback)
{
if (_outputType == OutputType.WRITER)
@ -218,7 +224,7 @@ public class ServletContextResponse extends ContextResponse
{
super.reset();
_httpOutput.resetBuffer();
_httpServletResponse.resetBuffer();
_outputType = OutputType.NONE;
_contentLength = -1;
_contentType = null;
@ -695,6 +701,7 @@ public class ServletContextResponse extends ContextResponse
*/
public void sendRedirect(int code, String location) throws IOException
{
resetBuffer();
FutureCallback callback = new FutureCallback();
Response.sendRedirect(_request, ServletContextResponse.this, callback, code, location, false);
callback.block();

View File

@ -38,7 +38,6 @@ import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.util.StringUtil;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -274,7 +273,6 @@ public class AsyncContextTest
assertThat("servlet request uri async", responseBody, containsString("doGet.ASYNC.requestURI:/ctx/self/hello%20there"));
}
@Disabled
@Test
public void testDispatchAsyncContextEncodedPathAndQueryString() throws Exception
{
@ -290,13 +288,13 @@ public class AsyncContextTest
assertThat("servlet gets right path", responseBody, containsString("doGet:getServletPath:/servletPath2"));
assertThat("async context gets right path in get", responseBody, containsString("doGet:async:getServletPath:/servletPath2"));
assertThat("servlet path attr is original", responseBody, containsString("async:run:attr:servletPath:/path with spaces/servletPath"));
assertThat("servlet path attr is original", responseBody, containsString("async:run:attr:servletPath:/path%20with%20spaces/servletPath"));
assertThat("path info attr is correct", responseBody, containsString("async:run:attr:pathInfo:null"));
assertThat("query string attr is correct", responseBody, containsString("async:run:attr:queryString:dispatch=true&queryStringWithEncoding=space%20space"));
assertThat("context path attr is correct", responseBody, containsString("async:run:attr:contextPath:/ctx"));
assertThat("request uri attr is correct", responseBody, containsString("async:run:attr:requestURI:/ctx/path%20with%20spaces/servletPath"));
assertThat("http servlet mapping matchValue is correct", responseBody, containsString("async:run:attr:mapping:matchValue:path with spaces/servletPath"));
assertThat("http servlet mapping pattern is correct", responseBody, containsString("async:run:attr:mapping:pattern:/path with spaces/servletPath"));
assertThat("http servlet mapping matchValue is correct", responseBody, containsString("async:run:attr:mapping:matchValue:path%20with%20spaces/servletPath"));
assertThat("http servlet mapping pattern is correct", responseBody, containsString("async:run:attr:mapping:pattern:/path%20with%20spaces/servletPath"));
assertThat("http servlet mapping servletName is correct", responseBody, containsString("async:run:attr:mapping:servletName:"));
assertThat("http servlet mapping mappingMatch is correct", responseBody, containsString("async:run:attr:mapping:mappingMatch:EXACT"));
}

View File

@ -51,7 +51,6 @@ import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -60,7 +59,6 @@ import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@Disabled("A lot of the test expectations are now broken because of the request wrapping done by Jetty 12 implementation.")
public class AsyncServletTest
{
protected AsyncServlet _servlet = new AsyncServlet();
@ -244,6 +242,7 @@ public class AsyncServletTest
"onTimeout",
"dispatch",
"ASYNC /ctx/path/info?start=200&timeout=dispatch",
"wrapped REQ",
"!initial",
"onComplete"));
@ -263,6 +262,7 @@ public class AsyncServletTest
"onTimeout",
"error",
"ERROR /ctx/error/custom?start=200&timeout=error",
"wrapped REQ",
"!initial",
"onComplete"));
@ -296,6 +296,7 @@ public class AsyncServletTest
"start",
"dispatch",
"ASYNC /ctx/path/info?start=200&dispatch=10",
"wrapped REQ",
"!initial",
"onComplete"));
assertFalse(__history.contains("onTimeout"));
@ -312,6 +313,7 @@ public class AsyncServletTest
"start",
"dispatch",
"ASYNC /ctx/path/info?start=200&dispatch=0",
"wrapped REQ",
"!initial",
"onComplete"));
}
@ -328,6 +330,7 @@ public class AsyncServletTest
"start",
"onError",
"ERROR /ctx/error/custom?start=200&throw=1",
"wrapped REQ",
"!initial",
"onComplete"));
assertContains("ERROR DISPATCH: /ctx/error/custom", response);
@ -376,11 +379,13 @@ public class AsyncServletTest
"start",
"dispatch",
"ASYNC /ctx/path/info?start=1000&dispatch=10&start2=1000&dispatch2=10",
"wrapped REQ",
"!initial",
"onStartAsync",
"start",
"dispatch",
"ASYNC /ctx/path/info?start=1000&dispatch=10&start2=1000&dispatch2=10",
"wrapped REQ",
"!initial",
"onComplete"));
assertContains("DISPATCHED", response);
@ -397,6 +402,7 @@ public class AsyncServletTest
"start",
"dispatch",
"ASYNC /ctx/path/info?start=1000&dispatch=10&start2=1000&complete2=10",
"wrapped REQ",
"!initial",
"onStartAsync",
"start",
@ -417,11 +423,13 @@ public class AsyncServletTest
"start",
"dispatch",
"ASYNC /ctx/path/info?start=1000&dispatch=10&start2=10",
"wrapped REQ",
"!initial",
"onStartAsync",
"start",
"onTimeout",
"ERROR /ctx/error/custom?start=1000&dispatch=10&start2=10",
"wrapped REQ",
"!initial",
"onComplete"));
assertContains("ERROR DISPATCH: /ctx/error/custom", response);
@ -438,11 +446,13 @@ public class AsyncServletTest
"start",
"onTimeout",
"ERROR /ctx/error/custom?start=10&start2=1000&dispatch2=10",
"wrapped REQ",
"!initial",
"onStartAsync",
"start",
"dispatch",
"ASYNC /ctx/path/info?start=10&start2=1000&dispatch2=10",
"wrapped REQ",
"!initial",
"onComplete"));
assertContains("DISPATCHED", response);
@ -459,6 +469,7 @@ public class AsyncServletTest
"start",
"onTimeout",
"ERROR /ctx/error/custom?start=10&start2=1000&complete2=10",
"wrapped REQ",
"!initial",
"onStartAsync",
"start",
@ -480,11 +491,13 @@ public class AsyncServletTest
"start",
"onTimeout",
"ERROR /ctx/path/error?start=10&start2=10",
"wrapped REQ",
"!initial",
"onStartAsync",
"start",
"onTimeout",
"ERROR /ctx/path/error?start=10&start2=10",
"wrapped REQ",
"!initial",
"onComplete")); // Error Page Loop!
assertContains("AsyncContext timeout", response);
@ -518,6 +531,7 @@ public class AsyncServletTest
"start",
"dispatch",
"ASYNC /ctx/p%20th3?start=200&dispatch=20&path=/p%20th3",
"wrapped REQ",
"!initial",
"onComplete"));
assertContains("DISPATCHED", response);
@ -531,11 +545,14 @@ public class AsyncServletTest
assertThat(__history, contains(
"FWD REQUEST /ctx/fwd/info?start=200&dispatch=20",
"FORWARD /ctx/path1?forward=true",
"wrapped REQ",
"initial",
"start",
"dispatch",
"FWD ASYNC /ctx/fwd/info?start=200&dispatch=20",
"wrapped REQ",
"FORWARD /ctx/path1?forward=true",
"wrapped REQ",
"!initial",
"onComplete"));
assertContains("DISPATCHED", response);
@ -549,10 +566,12 @@ public class AsyncServletTest
assertThat(__history, contains(
"FWD REQUEST /ctx/fwd/info?start=200&dispatch=20&path=/path2",
"FORWARD /ctx/path1?forward=true",
"wrapped REQ",
"initial",
"start",
"dispatch",
"ASYNC /ctx/path2?start=200&dispatch=20&path=/path2",
"wrapped REQ",
"!initial",
"onComplete"));
assertContains("DISPATCHED", response);
@ -566,6 +585,7 @@ public class AsyncServletTest
assertThat(__history, contains(
"FWD REQUEST /ctx/fwd/info?wrap=true&start=200&dispatch=20",
"FORWARD /ctx/path1?forward=true",
"wrapped REQ",
"initial",
"start",
"dispatch",
@ -584,6 +604,7 @@ public class AsyncServletTest
assertThat(__history, contains(
"FWD REQUEST /ctx/fwd/info?wrap=true&start=200&dispatch=20&path=/path2",
"FORWARD /ctx/path1?forward=true",
"wrapped REQ",
"initial",
"start",
"dispatch",
@ -622,6 +643,7 @@ public class AsyncServletTest
"async-read=10",
"dispatch",
"ASYNC /ctx/path/info?start=2000&dispatch=1500",
"wrapped REQ",
"!initial",
"onComplete"));
}

View File

@ -1327,7 +1327,6 @@ public class DefaultServletTest
}
@Test
@Disabled("TODO: sendError not working (yet)")
public void testWelcomeServlet() throws Exception
{
Path inde = docRoot.resolve("index.htm");
@ -1353,7 +1352,7 @@ public class DefaultServletTest
""");
response = HttpTester.parseResponse(rawResponse);
assertThat(response.toString(), response.getStatus(), is(HttpStatus.INTERNAL_SERVER_ERROR_500));
// TODO: sendError not working (yet) assertThat(response.getContent(), containsString("JSP support not configured"));
assertThat(response.getContent(), containsString("JSP support not configured"));
Files.writeString(index, "<h1>Hello Index</h1>", UTF_8);
rawResponse = connector.getResponse("""

View File

@ -29,7 +29,6 @@ import org.eclipse.jetty.server.Server;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -451,7 +450,6 @@ public class DispatcherForwardTest
}
@Test
@Disabled // TODO
public void testContentCanBeReadViaInputStreamAfterForwardWithoutQuery() throws Exception
{
CountDownLatch latch = new CountDownLatch(1);
@ -501,7 +499,6 @@ public class DispatcherForwardTest
}
@Test
@Disabled // TODO
public void testContentCanBeReadViaInputStreamAfterForwardWithQuery() throws Exception
{
CountDownLatch latch = new CountDownLatch(1);

View File

@ -330,7 +330,6 @@ public class DispatcherTest
}
@Test
@Disabled("See ServletContextRequest.errorClose and softClose hack")
public void testForwardSendError() throws Exception
{
_contextHandler.addServlet(ForwardServlet.class, "/forward/*");
@ -549,7 +548,7 @@ public class DispatcherTest
}
@Test
@Disabled("References to ResourceHandler, a jetty-core ContextHandler cannot be referenced for a ServletContext")
@Disabled("Cross context dispatch not yet supported in jetty-12")
public void testIncludeToResourceHandler() throws Exception
{
_contextHandler.addServlet(DispatchToResourceServlet.class, "/resourceServlet/*");
@ -568,7 +567,7 @@ public class DispatcherTest
}
@Test
@Disabled("References to ResourceHandler, a jetty-core ContextHandler cannot be referenced for a ServletContext")
@Disabled("Cross context dispatch not yet supported in jetty-12")
public void testForwardToResourceHandler() throws Exception
{
_contextHandler.addServlet(DispatchToResourceServlet.class, "/resourceServlet/*");
@ -587,7 +586,7 @@ public class DispatcherTest
}
@Test
@Disabled("References to ResourceHandler, a jetty-core ContextHandler cannot be referenced for a ServletContext")
@Disabled("Cross context dispatch not yet supported in jetty-12")
public void testWrappedIncludeToResourceHandler() throws Exception
{
_contextHandler.addServlet(DispatchToResourceServlet.class, "/resourceServlet/*");
@ -606,7 +605,7 @@ public class DispatcherTest
}
@Test
@Disabled("References to ResourceHandler, a jetty-core ContextHandler cannot be referenced for a ServletContext")
@Disabled("Cross context dispatch not yet supported in jetty-12")
public void testWrappedForwardToResourceHandler() throws Exception
{
_contextHandler.addServlet(DispatchToResourceServlet.class, "/resourceServlet/*");
@ -675,17 +674,14 @@ public class DispatcherTest
}
@Test
@Disabled // TODO
public void testDispatchMapping() throws Exception
{
_contextHandler.addServlet(new ServletHolder("TestServlet", MappingServlet.class), "/TestServlet");
_contextHandler.addServlet(new ServletHolder("DispatchServlet", AsyncDispatch2TestServlet.class), "/DispatchServlet");
_contextHandler.addServlet(new ServletHolder("DispatchServlet2", AsyncDispatch2TestServlet.class), "/DispatchServlet2");
_contextHandler.addServlet(new ServletHolder("DispatchServlet", AsyncDispatchTestServlet.class), "/DispatchServlet");
HttpTester.Response response;
String rawResponse;
// TODO Test TCK hack for https://github.com/eclipse-ee4j/jakartaee-tck/issues/585
rawResponse = _connector.getResponse("""
GET /context/DispatchServlet HTTP/1.1\r
Host: local\r
@ -693,17 +689,31 @@ public class DispatcherTest
\r
""");
response = HttpTester.parseResponse(rawResponse);
assertThat(response.getContent(), containsString("matchValue=DispatchServlet, pattern=/DispatchServlet, servletName=DispatchServlet, mappingMatch=EXACT"));
assertThat(response.getContent(), containsString("matchValue=TestServlet, pattern=/TestServlet, servletName=TestServlet, mappingMatch=EXACT"));
}
// TODO Test how it should work after fix for https://github.com/eclipse-ee4j/jakartaee-tck/issues/585
@Test
public void testDispatchMapping404() throws Exception
{
_contextHandler.addServlet(new ServletHolder("TestServlet", MappingServlet.class), "/TestServlet");
_contextHandler.addServlet(new ServletHolder("DispatchServlet", AsyncDispatchTestServlet.class), "/DispatchServlet");
ErrorPageErrorHandler errorPageErrorHandler = new ErrorPageErrorHandler();
_contextHandler.setErrorProcessor(errorPageErrorHandler);
errorPageErrorHandler.addErrorPage(404, "/TestServlet");
HttpTester.Response response;
String rawResponse;
// Test not found
rawResponse = _connector.getResponse("""
GET /context/DispatchServlet2 HTTP/1.1\r
GET /context/DispatchServlet?target=/DoesNotExist HTTP/1.1\r
Host: local\r
Connection: close\r
\r
""");
response = HttpTester.parseResponse(rawResponse);
assertThat(response.getContent(), containsString("matchValue=TestServlet, pattern=/TestServlet, servletName=TestServlet, mappingMatch=EXACT"));
assertThat(response.getContent(), containsString("matchValue=DispatchServlet, pattern=/DispatchServlet, servletName=DispatchServlet, mappingMatch=EXACT"));
}
public static class WrappingFilter implements Filter
@ -1335,14 +1345,16 @@ public class DispatcherTest
}
}
public static class AsyncDispatch2TestServlet extends HttpServlet
public static class AsyncDispatchTestServlet extends HttpServlet
{
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException
{
AsyncContext asyncContext = req.startAsync();
asyncContext.setTimeout(0);
asyncContext.dispatch("/TestServlet");
String target = req.getParameter("target");
target = StringUtil.isBlank(target) ? "/TestServlet" : target;
asyncContext.dispatch(target);
}
}
}

View File

@ -35,13 +35,13 @@ import org.eclipse.jetty.util.URIUtil;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.startsWith;
@Disabled
public class EncodedURITest
{
private Server _server;
@ -90,8 +90,8 @@ public class EncodedURITest
assertThat(response, startsWith("HTTP/1.1 200 "));
assertThat(response, Matchers.containsString("requestURI=/c%6Fntext%20path/test%20servlet/path%20info"));
assertThat(response, Matchers.containsString("contextPath=/context%20path"));
assertThat(response, Matchers.containsString("servletPath=/test servlet"));
assertThat(response, Matchers.containsString("pathInfo=/path info"));
assertThat(response, Matchers.containsString("servletPath=/test%20servlet"));
assertThat(response, Matchers.containsString("pathInfo=/path%20info"));
}
@Test
@ -101,8 +101,8 @@ public class EncodedURITest
assertThat(response, startsWith("HTTP/1.1 200 "));
assertThat(response, Matchers.containsString("requestURI=/context%20path/test%20servlet/path%20info"));
assertThat(response, Matchers.containsString("contextPath=/context%20path"));
assertThat(response, Matchers.containsString("servletPath=/test servlet"));
assertThat(response, Matchers.containsString("pathInfo=/path info"));
assertThat(response, Matchers.containsString("servletPath=/test%20servlet"));
assertThat(response, Matchers.containsString("pathInfo=/path%20info"));
}
@Test
@ -112,8 +112,8 @@ public class EncodedURITest
assertThat(response, startsWith("HTTP/1.1 200 "));
assertThat(response, Matchers.containsString("requestURI=/context%20path/test%20servlet/path%20info"));
assertThat(response, Matchers.containsString("contextPath=/context%20path"));
assertThat(response, Matchers.containsString("servletPath=/test servlet"));
assertThat(response, Matchers.containsString("pathInfo=/path info"));
assertThat(response, Matchers.containsString("servletPath=/test%20servlet"));
assertThat(response, Matchers.containsString("pathInfo=/path%20info"));
}
@Test
@ -121,10 +121,10 @@ public class EncodedURITest
{
String response = _connector.getResponse("GET /context%20path/async%20servlet/path%20info HTTP/1.0\n\n");
assertThat(response, startsWith("HTTP/1.1 200 "));
assertThat(response, Matchers.containsString("requestURI=/context%20path/test servlet/path info"));
assertThat(response, Matchers.containsString("requestURI=/context%20path/test%20servlet/path%20info"));
assertThat(response, Matchers.containsString("contextPath=/context%20path"));
assertThat(response, Matchers.containsString("servletPath=/test servlet"));
assertThat(response, Matchers.containsString("pathInfo=/path info"));
assertThat(response, Matchers.containsString("servletPath=/test%20servlet"));
assertThat(response, Matchers.containsString("pathInfo=/path%20info"));
}
@Test
@ -132,10 +132,29 @@ public class EncodedURITest
{
String response = _connector.getResponse("GET /context%20path/async%20servlet/path%20info?encode=true HTTP/1.0\n\n");
assertThat(response, startsWith("HTTP/1.1 200 "));
assertThat(response, Matchers.containsString("requestURI=/context%20path/test%20servlet/path%20info"));
assertThat(response, Matchers.containsString("requestURI=/context%20path/test%20servlet/path%2520info"));
assertThat(response, Matchers.containsString("contextPath=/context%20path"));
assertThat(response, Matchers.containsString("servletPath=/test servlet"));
assertThat(response, Matchers.containsString("pathInfo=/path info"));
assertThat(response, Matchers.containsString("servletPath=/test%20servlet"));
assertThat(response, Matchers.containsString("pathInfo=/path%2520info"));
}
@ParameterizedTest
@ValueSource(strings = {"%2F", "%3F"})
public void testCanonicallyEncodedUris(String separator) throws Exception
{
_server.stop();
ServletContextHandler context2 = new ServletContextHandler();
context2.setContextPath("/context_path".replace("_", separator));
_contextCollection.addHandler(context2);
context2.addServlet(TestServlet.class, "/test_servlet/*".replace("_", separator));
_server.start();
String response = _connector.getResponse("GET /context_path/test_servlet/path_info HTTP/1.0\n\n".replace("_", separator));
assertThat(response, startsWith("HTTP/1.1 200 "));
assertThat(response, Matchers.containsString("requestURI=/context_path/test_servlet/path_info".replace("_", separator)));
assertThat(response, Matchers.containsString("contextPath=/context_path".replace("_", separator)));
assertThat(response, Matchers.containsString("servletPath=/test_servlet".replace("_", separator)));
assertThat(response, Matchers.containsString("pathInfo=/path_info".replace("_", separator)));
}
public static class TestServlet extends HttpServlet