Skip to content

Commit

Permalink
Issue #12683 Fix cross context dispatch to root context. (#12684)
Browse files Browse the repository at this point in the history
  • Loading branch information
janbartel authored Jan 9, 2025
1 parent 6b48a19 commit 9761d61
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public RequestDispatcher getRequestDispatcher(String uriInContext)
if (StringUtil.isEmpty(encodedPathInContext))
return null;

if (!StringUtil.isEmpty(contextPath))
if (!StringUtil.isEmpty(contextPath) && !contextPath.equals("/"))
{
uri.path(URIUtil.addPaths(contextPath, uri.getPath()));
encodedPathInContext = uri.getCanonicalPath().substring(contextPath.length());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ public class CrossContextDispatcherTest
private Server _server;
private LocalConnector _connector;
private ServletContextHandler _contextHandler;

private ServletContextHandler _targetServletContextHandler;
private ServletContextHandler _rootContextHandler;

@BeforeEach
public void init() throws Exception
Expand Down Expand Up @@ -145,6 +145,13 @@ public void init() throws Exception
resourceContextHandler.setHandler(resourceHandler);
resourceContextHandler.setCrossContextDispatchSupported(true);
contextCollection.addHandler(resourceContextHandler);

_rootContextHandler = new ServletContextHandler();
_rootContextHandler.setContextPath("/");
_rootContextHandler.setBaseResourceAsPath(MavenTestingUtils.getTestResourcePathDir("docroot"));
_rootContextHandler.setCrossContextDispatchSupported(true);
contextCollection.addHandler(_rootContextHandler);

_server.setHandler(contextCollection);
_server.addConnector(_connector);

Expand All @@ -158,6 +165,91 @@ public void destroy() throws Exception
_server.join();
}

@Test
public void testForwardToRoot() throws Exception
{
_rootContextHandler.addServlet(VerifyForwardServlet.class, "/verify/*");
_contextHandler.addServlet(CrossContextDispatchServlet.class, "/dispatch/*");

String rawResponse = _connector.getResponse("""
GET /context/dispatch/?forward=/verify&ctx=/ HTTP/1.1\r
Host: localhost\r
Connection: close\r
\r
""");

HttpTester.Response response = HttpTester.parseResponse(rawResponse);

String content = response.getContent();
String[] contentLines = content.split("\\n");

//verify forward attributes
assertThat(content, containsString("Verified!"));
assertThat(content, containsString("jakarta.servlet.forward.context_path=/context"));
assertThat(content, containsString("jakarta.servlet.forward.servlet_path=/dispatch"));
assertThat(content, containsString("jakarta.servlet.forward.path_info=/"));

String forwardMapping = extractLine(contentLines, "jakarta.servlet.forward.mapping=");
assertNotNull(forwardMapping);
assertThat(forwardMapping, containsString("CrossContextDispatchServlet"));
assertThat(content, containsString("jakarta.servlet.forward.query_string=forward=/verify&ctx=/"));
assertThat(content, containsString("jakarta.servlet.forward.request_uri=/context/dispatch/"));
//verify request values
assertThat(content, containsString("REQUEST_URL=http://localhost/"));
assertThat(content, containsString("CONTEXT_PATH="));
assertThat(content, containsString("SERVLET_PATH=/verify"));
assertThat(content, containsString("PATH_INFO=/pinfo"));
String mapping = extractLine(contentLines, "MAPPING=");
assertNotNull(mapping);
assertThat(mapping, containsString("VerifyForwardServlet"));
String params = extractLine(contentLines, "PARAMS=");
assertNotNull(params);
params = params.substring(params.indexOf("=") + 1);
params = params.substring(1, params.length() - 1); //dump leading, trailing [ ]
assertThat(Arrays.asList(StringUtil.csvSplit(params)), containsInAnyOrder("a", "forward", "ctx"));
assertThat(content, containsString("REQUEST_URI=/verify/pinfo"));
}

@Test
public void testIncludeToRoot() throws Exception
{
_rootContextHandler.addServlet(VerifyIncludeServlet.class, "/verify/*");
_contextHandler.addServlet(CrossContextDispatchServlet.class, "/dispatch/*");

String rawResponse = _connector.getResponse("""
GET /context/dispatch/?include=/verify&ctx=/ HTTP/1.1\r
Host: localhost\r
Connection: close\r
\r
""");

HttpTester.Response response = HttpTester.parseResponse(rawResponse);
String content = response.getContent();
String[] contentLines = content.split("\\n");

//verify include attributes
assertThat(content, containsString("Verified!"));
assertThat(content, containsString("jakarta.servlet.include.context_path=/"));
assertThat(content, containsString("jakarta.servlet.include.servlet_path=/verify"));
assertThat(content, containsString("jakarta.servlet.include.path_info=/pinfo"));
String includeMapping = extractLine(contentLines, "jakarta.servlet.include.mapping=");
assertThat(includeMapping, containsString("VerifyIncludeServlet"));
assertThat(content, containsString("jakarta.servlet.include.request_uri=/verify/pinfo"));
//verify request values
assertThat(content, containsString("CONTEXT_PATH=/context"));
assertThat(content, containsString("SERVLET_PATH=/dispatch"));
assertThat(content, containsString("PATH_INFO=/"));
String mapping = extractLine(contentLines, "MAPPING=");
assertThat(mapping, containsString("CrossContextDispatchServlet"));
assertThat(content, containsString("QUERY_STRING=include=/verify"));
assertThat(content, containsString("REQUEST_URI=/context/dispatch/"));
String params = extractLine(contentLines, "PARAMS=");
assertNotNull(params);
params = params.substring(params.indexOf("=") + 1);
params = params.substring(1, params.length() - 1); //dump leading, trailing [ ]
assertThat(Arrays.asList(StringUtil.csvSplit(params)), containsInAnyOrder("a", "include", "ctx"));
}

@Test
public void testSimpleCrossContextForward() throws Exception
{
Expand Down Expand Up @@ -732,10 +824,12 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
RequestDispatcher dispatcher;

String ctx = request.getParameter("ctx");
if (StringUtil.isBlank(ctx))
ctx = "/foreign";
if (request.getParameter("forward") != null)
{
ServletContext foreign = getServletContext().getContext("/foreign");
ServletContext foreign = getServletContext().getContext(ctx);
assertNotNull(foreign);
dispatcher = foreign.getRequestDispatcher(request.getParameter("forward") + "/pinfo?a=b");

Expand All @@ -746,7 +840,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
}
else if (request.getParameter("include") != null)
{
ServletContext foreign = getServletContext().getContext("/foreign");
ServletContext foreign = getServletContext().getContext(ctx);
assertNotNull(foreign);
dispatcher = foreign.getRequestDispatcher(request.getParameter("include") + "/pinfo?a=b");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public RequestDispatcher getRequestDispatcher(String uriInContext)
if (StringUtil.isEmpty(encodedPathInContext))
return null;

if (!StringUtil.isEmpty(contextPath))
if (!StringUtil.isEmpty(contextPath) && !contextPath.equals("/"))
{
uri.path(URIUtil.addPaths(contextPath, uri.getPath()));
encodedPathInContext = uri.getCanonicalPath().substring(contextPath.length());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ public class CrossContextDispatcherTest
private Server _server;
private LocalConnector _connector;
private ServletContextHandler _contextHandler;

private ServletContextHandler _targetServletContextHandler;
private ServletContextHandler _rootContextHandler;

@BeforeEach
public void init() throws Exception
Expand All @@ -140,6 +140,12 @@ public void init() throws Exception
_targetServletContextHandler.setCrossContextDispatchSupported(true);
contextCollection.addHandler(_targetServletContextHandler);

_rootContextHandler = new ServletContextHandler();
_rootContextHandler.setContextPath("/");
_rootContextHandler.setBaseResource(ResourceFactory.root().newResource(MavenPaths.findTestResourceDir("docroot")));
_rootContextHandler.setCrossContextDispatchSupported(true);
contextCollection.addHandler(_rootContextHandler);

ResourceHandler resourceHandler = new ResourceHandler();
resourceHandler.setBaseResource(ResourceFactory.root().newResource(MavenPaths.findTestResourceDir("dispatchResourceTest")));
ContextHandler resourceContextHandler = new ContextHandler("/resource");
Expand All @@ -159,6 +165,91 @@ public void destroy() throws Exception
_server.join();
}

@Test
public void testForwardToRoot() throws Exception
{
_rootContextHandler.addServlet(VerifyForwardServlet.class, "/verify/*");
_contextHandler.addServlet(CrossContextDispatchServlet.class, "/dispatch/*");

String rawResponse = _connector.getResponse("""
GET /context/dispatch/?forward=/verify&ctx=/ HTTP/1.1\r
Host: localhost\r
Connection: close\r
\r
""");

HttpTester.Response response = HttpTester.parseResponse(rawResponse);

String content = response.getContent();
String[] contentLines = content.split("\\n");

//verify forward attributes
assertThat(content, containsString("Verified!"));
assertThat(content, containsString("jakarta.servlet.forward.context_path=/context"));
assertThat(content, containsString("jakarta.servlet.forward.servlet_path=/dispatch"));
assertThat(content, containsString("jakarta.servlet.forward.path_info=/"));

String forwardMapping = extractLine(contentLines, "jakarta.servlet.forward.mapping=");
assertNotNull(forwardMapping);
assertThat(forwardMapping, containsString("CrossContextDispatchServlet"));
assertThat(content, containsString("jakarta.servlet.forward.query_string=forward=/verify&ctx=/"));
assertThat(content, containsString("jakarta.servlet.forward.request_uri=/context/dispatch/"));
//verify request values
assertThat(content, containsString("REQUEST_URL=http://localhost/"));
assertThat(content, containsString("CONTEXT_PATH="));
assertThat(content, containsString("SERVLET_PATH=/verify"));
assertThat(content, containsString("PATH_INFO=/pinfo"));
String mapping = extractLine(contentLines, "MAPPING=");
assertNotNull(mapping);
assertThat(mapping, containsString("VerifyForwardServlet"));
String params = extractLine(contentLines, "PARAMS=");
assertNotNull(params);
params = params.substring(params.indexOf("=") + 1);
params = params.substring(1, params.length() - 1); //dump leading, trailing [ ]
assertThat(Arrays.asList(StringUtil.csvSplit(params)), containsInAnyOrder("a", "forward", "ctx"));
assertThat(content, containsString("REQUEST_URI=/verify/pinfo"));
}

@Test
public void testIncludeToRoot() throws Exception
{
_rootContextHandler.addServlet(VerifyIncludeServlet.class, "/verify/*");
_contextHandler.addServlet(CrossContextDispatchServlet.class, "/dispatch/*");

String rawResponse = _connector.getResponse("""
GET /context/dispatch/?include=/verify&ctx=/ HTTP/1.1\r
Host: localhost\r
Connection: close\r
\r
""");

HttpTester.Response response = HttpTester.parseResponse(rawResponse);
String content = response.getContent();
String[] contentLines = content.split("\\n");

//verify include attributes
assertThat(content, containsString("Verified!"));
assertThat(content, containsString("jakarta.servlet.include.context_path="));
assertThat(content, containsString("jakarta.servlet.include.servlet_path=/verify"));
assertThat(content, containsString("jakarta.servlet.include.path_info=/pinfo"));
String includeMapping = extractLine(contentLines, "jakarta.servlet.include.mapping=");
assertThat(includeMapping, containsString("VerifyIncludeServlet"));
assertThat(content, containsString("jakarta.servlet.include.request_uri=/verify/pinfo"));
//verify request values
assertThat(content, containsString("CONTEXT_PATH=/context"));
assertThat(content, containsString("SERVLET_PATH=/dispatch"));
assertThat(content, containsString("PATH_INFO=/"));
String mapping = extractLine(contentLines, "MAPPING=");
assertThat(mapping, containsString("CrossContextDispatchServlet"));
assertThat(content, containsString("QUERY_STRING=include=/verify"));
assertThat(content, containsString("REQUEST_URI=/context/dispatch/"));
String params = extractLine(contentLines, "PARAMS=");
assertNotNull(params);
params = params.substring(params.indexOf("=") + 1);
params = params.substring(1, params.length() - 1); //dump leading, trailing [ ]
assertThat(Arrays.asList(StringUtil.csvSplit(params)), containsInAnyOrder("a", "include", "ctx"));
}

@Test
public void testSimpleCrossContextForward() throws Exception
{
Expand Down Expand Up @@ -749,10 +840,12 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
RequestDispatcher dispatcher;

String ctx = request.getParameter("ctx");
if (StringUtil.isBlank(ctx))
ctx = "/foreign";
if (request.getParameter("forward") != null)
{
ServletContext foreign = getServletContext().getContext("/foreign");
ServletContext foreign = getServletContext().getContext(ctx);
assertNotNull(foreign);
dispatcher = foreign.getRequestDispatcher(request.getParameter("forward") + "/pinfo?a=b");

Expand All @@ -768,7 +861,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
}
else if (request.getParameter("include") != null)
{
ServletContext foreign = getServletContext().getContext("/foreign");
ServletContext foreign = getServletContext().getContext(ctx);
assertNotNull(foreign);
dispatcher = foreign.getRequestDispatcher(request.getParameter("include") + "/pinfo?a=b");

Expand Down
Empty file.

0 comments on commit 9761d61

Please sign in to comment.