Fixes #9910 - Inconsistent handling of welcome files

* Added DefaultServlet combinations tests.
* Removed pathInfoOnly handling present in Jetty 11, because it is always true for mapping to "/", and always false for other mappings.

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2023-07-14 11:58:21 +02:00 committed by GitHub
parent a317a1892d
commit 248354f64a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 305 additions and 59 deletions

View File

@ -104,8 +104,6 @@
* servlet context root. Useful for only serving static content out * servlet context root. Useful for only serving static content out
* of only specific subdirectories. * of only specific subdirectories.
* *
* pathInfoOnly If true, only the path info will be applied to the baseResource
*
* stylesheet Set with the location of an optional stylesheet that will be used * stylesheet Set with the location of an optional stylesheet that will be used
* to decorate the directory listing html. * to decorate the directory listing html.
* *

View File

@ -104,8 +104,6 @@
* servlet context root. Useful for only serving static content out * servlet context root. Useful for only serving static content out
* of only specific subdirectories. * of only specific subdirectories.
* *
* pathInfoOnly If true, only the path info will be applied to the baseResource
*
* stylesheet Set with the location of an optional stylesheet that will be used * stylesheet Set with the location of an optional stylesheet that will be used
* to decorate the directory listing html. * to decorate the directory listing html.
* *

View File

@ -104,8 +104,6 @@
* servlet context root. Useful for only serving static content out * servlet context root. Useful for only serving static content out
* of only specific subdirectories. * of only specific subdirectories.
* *
* pathInfoOnly If true, only the path info will be applied to the baseResource
*
* stylesheet Set with the location of an optional stylesheet that will be used * stylesheet Set with the location of an optional stylesheet that will be used
* to decorate the directory listing html. * to decorate the directory listing html.
* *

View File

@ -44,6 +44,7 @@ import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper; import jakarta.servlet.http.HttpServletResponseWrapper;
import jakarta.servlet.http.MappingMatch;
import org.eclipse.jetty.http.CompressedContentFormat; import org.eclipse.jetty.http.CompressedContentFormat;
import org.eclipse.jetty.http.HttpException; import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
@ -140,12 +141,6 @@ import org.slf4j.LoggerFactory;
* gzipped. * gzipped.
* Defaults to {@code .svgz}. * Defaults to {@code .svgz}.
* </dd> * </dd>
* <dt>pathInfoOnly</dt>
* <dd>
* Use {@code true} to use only the request {@code pathInfo} to look for
* static resources.
* Defaults to {@code false}.
* </dd>
* <dt>precompressed</dt> * <dt>precompressed</dt>
* <dd> * <dd>
* Omitted by default, so that no pre-compressed content will be served. * Omitted by default, so that no pre-compressed content will be served.
@ -190,7 +185,6 @@ public class DefaultServlet extends HttpServlet
private ServletResourceService _resourceService; private ServletResourceService _resourceService;
private WelcomeServletMode _welcomeServletMode; private WelcomeServletMode _welcomeServletMode;
private Resource _baseResource; private Resource _baseResource;
private boolean _isPathInfoOnly;
public ResourceService getResourceService() public ResourceService getResourceService()
{ {
@ -289,8 +283,6 @@ public class DefaultServlet extends HttpServlet
_resourceService.setPrecompressedFormats(precompressedFormats); _resourceService.setPrecompressedFormats(precompressedFormats);
_resourceService.setEtags(getInitBoolean("etags", _resourceService.isEtags())); _resourceService.setEtags(getInitBoolean("etags", _resourceService.isEtags()));
_isPathInfoOnly = getInitBoolean("pathInfoOnly", _isPathInfoOnly);
_welcomeServletMode = WelcomeServletMode.NONE; _welcomeServletMode = WelcomeServletMode.NONE;
String welcomeServlets = getInitParameter("welcomeServlets"); String welcomeServlets = getInitParameter("welcomeServlets");
if (welcomeServlets != null) if (welcomeServlets != null)
@ -335,7 +327,6 @@ public class DefaultServlet extends HttpServlet
{ {
LOG.debug(" .baseResource = {}", _baseResource); LOG.debug(" .baseResource = {}", _baseResource);
LOG.debug(" .resourceService = {}", _resourceService); LOG.debug(" .resourceService = {}", _resourceService);
LOG.debug(" .isPathInfoOnly = {}", _isPathInfoOnly);
LOG.debug(" .welcomeServletMode = {}", _welcomeServletMode); LOG.debug(" .welcomeServletMode = {}", _welcomeServletMode);
} }
} }
@ -442,25 +433,12 @@ public class DefaultServlet extends HttpServlet
servletContext.getClass().getName() + " is not " + ContextHandler.ScopedContext.class.getName()); servletContext.getClass().getName() + " is not " + ContextHandler.ScopedContext.class.getName());
} }
protected boolean isPathInfoOnly()
{
return _isPathInfoOnly;
}
@Override @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{ {
String includedServletPath = (String)req.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH); String includedServletPath = (String)req.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH);
String encodedPathInContext = getEncodedPathInContext(req, includedServletPath);
boolean included = includedServletPath != null; boolean included = includedServletPath != null;
String encodedPathInContext;
if (included)
encodedPathInContext = URIUtil.encodePath(getIncludedPathInContext(req, includedServletPath, isPathInfoOnly()));
else if (isPathInfoOnly())
encodedPathInContext = URIUtil.encodePath(req.getPathInfo());
else if (req instanceof ServletApiRequest apiRequest)
encodedPathInContext = Context.getPathInContext(req.getContextPath(), apiRequest.getRequest().getHttpURI().getCanonicalPath());
else
encodedPathInContext = Context.getPathInContext(req.getContextPath(), URIUtil.canonicalPath(req.getRequestURI()));
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("doGet(req={}, resp={}) pathInContext={}, included={}", req, resp, encodedPathInContext, included); LOG.debug("doGet(req={}, resp={}) pathInContext={}, included={}", req, resp, encodedPathInContext, included);
@ -536,6 +514,18 @@ public class DefaultServlet extends HttpServlet
} }
} }
protected String getEncodedPathInContext(HttpServletRequest req, String includedServletPath)
{
if (includedServletPath != null)
return URIUtil.encodePath(getIncludedPathInContext(req, includedServletPath, !isDefaultMapping(req)));
else if (!isDefaultMapping(req))
return URIUtil.encodePath(req.getPathInfo());
else if (req instanceof ServletApiRequest apiRequest)
return Context.getPathInContext(req.getContextPath(), apiRequest.getRequest().getHttpURI().getCanonicalPath());
else
return Context.getPathInContext(req.getContextPath(), URIUtil.canonicalPath(req.getRequestURI()));
}
@Override @Override
protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{ {
@ -1064,7 +1054,7 @@ public class DefaultServlet extends HttpServlet
// Check whether a Servlet may serve the welcome resource. // Check whether a Servlet may serve the welcome resource.
if (_welcomeServletMode != WelcomeServletMode.NONE && welcomeTarget == null) if (_welcomeServletMode != WelcomeServletMode.NONE && welcomeTarget == null)
{ {
if (isPathInfoOnly() && !isIncluded(getServletRequest(coreRequest))) if (!isDefaultMapping(getServletRequest(coreRequest)) && !isIncluded(getServletRequest(coreRequest)))
welcomeTarget = URIUtil.addPaths(getServletRequest(coreRequest).getPathInfo(), welcome); welcomeTarget = URIUtil.addPaths(getServletRequest(coreRequest).getPathInfo(), welcome);
ServletHandler.MappedServlet entry = _servletContextHandler.getServletHandler().getMappedServlet(welcomeInContext); ServletHandler.MappedServlet entry = _servletContextHandler.getServletHandler().getMappedServlet(welcomeInContext);
@ -1084,24 +1074,6 @@ public class DefaultServlet extends HttpServlet
return welcomeTarget; return welcomeTarget;
} }
@Override
protected void redirectWelcome(Request request, Response response, Callback callback, String welcomeTarget) throws IOException
{
HttpServletRequest servletRequest = getServletRequest(request);
HttpServletResponse servletResponse = getServletResponse(response);
boolean included = isIncluded(servletRequest);
String servletPath = included ? (String)servletRequest.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH)
: servletRequest.getServletPath();
if (isPathInfoOnly())
welcomeTarget = URIUtil.addPaths(servletPath, welcomeTarget);
servletResponse.setContentLength(0);
Response.sendRedirect(request, response, callback, welcomeTarget);
}
@Override @Override
protected void serveWelcome(Request request, Response response, Callback callback, String welcomeTarget) throws IOException protected void serveWelcome(Request request, Response response, Callback callback, String welcomeTarget) throws IOException
{ {
@ -1227,6 +1199,11 @@ public class DefaultServlet extends HttpServlet
return request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI) != null; return request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI) != null;
} }
private static boolean isDefaultMapping(HttpServletRequest req)
{
return req.getHttpServletMapping().getMappingMatch() == MappingMatch.DEFAULT;
}
/** /**
* Wrap an existing HttpContent with one that takes has an unknown/unspecified length. * Wrap an existing HttpContent with one that takes has an unknown/unspecified length.
*/ */

View File

@ -0,0 +1,285 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.ee10.servlet;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.ResourceService;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
import org.eclipse.jetty.util.component.LifeCycle;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jetty.server.ResourceService.WelcomeMode.REDIRECT;
import static org.eclipse.jetty.server.ResourceService.WelcomeMode.REHANDLE;
import static org.eclipse.jetty.server.ResourceService.WelcomeMode.SERVE;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@ExtendWith(WorkDirExtension.class)
public class DefaultServletCombinationsTest
{
public WorkDir workDir;
public Path docRoot;
private Server server;
private LocalConnector connector;
private ServletContextHandler context;
@BeforeEach
public void init() throws Exception
{
docRoot = workDir.getEmptyPathDir().resolve("docroot");
FS.ensureDirExists(docRoot);
Files.writeString(docRoot.resolve("index.html"), "Static index.html at root", UTF_8);
Files.writeString(docRoot.resolve("foo.welcome"), "Static foo.welcome at root", UTF_8);
Path subdirPath = docRoot.resolve("subdir");
FS.ensureDirExists(subdirPath);
Files.writeString(subdirPath.resolve("index.html"), "Static index.html at root subdir", UTF_8);
Files.writeString(subdirPath.resolve("foo.welcome"), "Static foo.welcome at root subdir", UTF_8);
Path emptyPath = docRoot.resolve("empty");
FS.ensureDirExists(emptyPath);
Path staticPath = docRoot.resolve("static");
FS.ensureDirExists(staticPath);
Files.writeString(staticPath.resolve("index.html"), "Static index.html at static", UTF_8);
Files.writeString(staticPath.resolve("foo.welcome"), "Static foo.welcome at static", UTF_8);
Path staticsubdirPath = staticPath.resolve("subdir");
FS.ensureDirExists(staticsubdirPath);
Files.writeString(staticsubdirPath.resolve("index.html"), "Static index.html at static subdir", UTF_8);
Files.writeString(staticsubdirPath.resolve("foo.welcome"), "Static foo.welcome at static subdir", UTF_8);
Path subdirHtmlPath = docRoot.resolve("subdirHtml");
FS.ensureDirExists(subdirHtmlPath);
Files.writeString(subdirHtmlPath.resolve("index.html"), "Static index.html at root subdirHtml", UTF_8);
Path staticSubdirHtmlPath = staticPath.resolve("subdirHtml");
FS.ensureDirExists(staticSubdirHtmlPath);
Files.writeString(staticSubdirHtmlPath.resolve("index.html"), "Static index.html at static subdirHtml", UTF_8);
Path subdirWelcomePath = docRoot.resolve("subdirWelcome");
FS.ensureDirExists(subdirWelcomePath);
Files.writeString(subdirWelcomePath.resolve("foo.welcome"), "Static foo.welcome at root subdirWelcome", UTF_8);
Path staticSubdirWelcomePath = staticPath.resolve("subdirWelcome");
FS.ensureDirExists(staticSubdirWelcomePath);
Files.writeString(staticSubdirWelcomePath.resolve("foo.welcome"), "Static foo.welcome at static subdirWelcome", UTF_8);
Path subdirEmptyPath = staticPath.resolve("empty");
FS.ensureDirExists(subdirEmptyPath);
server = new Server();
connector = new LocalConnector(server);
connector.getConnectionFactory(HttpConfiguration.ConnectionFactory.class).getHttpConfiguration().setSendServerVersion(false);
context = new ServletContextHandler();
context.setBaseResourceAsPath(docRoot);
context.setContextPath("/ctx");
context.setWelcomeFiles(new String[]{"index.html", "index.welcome"});
ServletHolder welcomeExtHolder = context.addServlet(WelcomeServlet.class, "*.welcome");
welcomeExtHolder.setInitParameter("mapping", "welcome extension");
}
private void startServer(boolean pathInfoOnly, ResourceService.WelcomeMode welcomeMode) throws Exception
{
ServletHolder defaultHolder;
if (pathInfoOnly)
{
defaultHolder = context.addServlet(DefaultServlet.class, "/static/*");
context.addServlet(TeapotServlet.class, "/");
}
else
{
defaultHolder = context.addServlet(DefaultServlet.class, "/");
}
defaultHolder.setInitParameter("dirAllowed", "false");
server.setHandler(context);
server.addConnector(connector);
server.start();
// Must happen after start.
((DefaultServlet)defaultHolder.getServlet()).getResourceService().setWelcomeMode(welcomeMode);
}
@AfterEach
public void destroy() throws Exception
{
LifeCycle.stop(server);
}
public static class WelcomeServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setStatus(HttpStatus.OK_200);
String mapping = getInitParameter("mapping");
resp.getWriter().print("Servlet at " + mapping);
}
}
public static class TeapotServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setStatus(HttpStatus.IM_A_TEAPOT_418);
}
}
record Data(boolean pathInfoOnly, ResourceService.WelcomeMode welcomeMode, String requestPath, int expectedStatus, String expected)
{
}
public static Stream<Data> data()
{
List<Data> datas = new ArrayList<>();
for (String requestPath : List.of("/", "/foo.welcome", "/subdirHtml/",
"/subdirWelcome/", "/empty/", "/nothing/index.welcome", "/nothing/"))
{
for (ResourceService.WelcomeMode welcomeMode : List.of(SERVE, REDIRECT, REHANDLE))
{
for (boolean pathInfoOnly : List.of(false, true))
{
int expectedStatus;
String expected;
switch (requestPath)
{
case "/" ->
{
switch (welcomeMode)
{
case SERVE ->
{
expectedStatus = HttpStatus.OK_200;
expected = "Static index.html at root";
}
case REDIRECT ->
{
expectedStatus = HttpStatus.FOUND_302;
expected = pathInfoOnly ? "http://local/ctx/static/index.html" : "http://local/ctx/index.html";
}
case REHANDLE ->
{
expectedStatus = pathInfoOnly ? HttpStatus.IM_A_TEAPOT_418 : HttpStatus.NOT_FOUND_404;
expected = null;
}
default -> throw new AssertionError();
}
}
case "/foo.welcome" ->
{
expectedStatus = HttpStatus.OK_200;
expected = pathInfoOnly ? "Static foo.welcome at root" : "Servlet at welcome extension";
}
case "/subdirHtml/" ->
{
switch (welcomeMode)
{
case SERVE ->
{
expectedStatus = HttpStatus.OK_200;
expected = "Static index.html at root subdirHtml";
}
case REDIRECT ->
{
expectedStatus = HttpStatus.FOUND_302;
expected = pathInfoOnly ? "http://local/ctx/static/subdirHtml/index.html" : "http://local/ctx/subdirHtml/index.html";
}
case REHANDLE ->
{
expectedStatus = pathInfoOnly ? HttpStatus.IM_A_TEAPOT_418 : HttpStatus.NOT_FOUND_404;
expected = null;
}
default -> throw new AssertionError();
}
}
case "/subdirWelcome/" ->
{
expectedStatus = HttpStatus.FORBIDDEN_403;
expected = null;
}
case "/empty/" ->
{
expectedStatus = HttpStatus.FORBIDDEN_403;
expected = null;
}
case "/nothing/index.welcome" ->
{
expectedStatus = pathInfoOnly ? HttpStatus.NOT_FOUND_404 : HttpStatus.OK_200;
expected = pathInfoOnly ? null : "Servlet at welcome extension";
}
case "/nothing/" ->
{
expectedStatus = HttpStatus.NOT_FOUND_404;
expected = null;
}
default -> throw new AssertionError();
}
datas.add(new Data(pathInfoOnly, welcomeMode, requestPath, expectedStatus, expected));
}
}
}
return datas.stream();
}
@ParameterizedTest
@MethodSource("data")
public void testDefaultPathCombinations(Data data) throws Exception
{
startServer(data.pathInfoOnly(), data.welcomeMode());
String requestPath = context.getContextPath() + (data.pathInfoOnly() ? "/static" : "") + data.requestPath();
String rawResponse = connector.getResponse(String.format("""
GET %s HTTP/1.1\r
Host: local\r
Connection: close\r
\r
""", requestPath));
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
int status = response.getStatus();
assertThat(response.toString(), status, is(data.expectedStatus()));
if (status > 299 && status < 400)
assertThat(response.get(HttpHeader.LOCATION), is(data.expected));
else if (data.expected != null)
assertThat(response.getContent(), is(data.expected));
}
}

View File

@ -531,7 +531,6 @@ public class DefaultServletTest
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/extra/*"); ServletHolder defholder = context.addServlet(DefaultServlet.class, "/extra/*");
defholder.setInitParameter("resourceBase", extraResourceBaseString); defholder.setInitParameter("resourceBase", extraResourceBaseString);
defholder.setInitParameter("pathInfoOnly", "true");
defholder.setInitParameter("dirAllowed", "true"); defholder.setInitParameter("dirAllowed", "true");
defholder.setInitParameter("redirectWelcome", "false"); defholder.setInitParameter("redirectWelcome", "false");
defholder.setInitParameter("gzip", "false"); defholder.setInitParameter("gzip", "false");
@ -1056,7 +1055,6 @@ public class DefaultServletTest
ServletHolder altholder = context.addServlet(DefaultServlet.class, "/alt/*"); ServletHolder altholder = context.addServlet(DefaultServlet.class, "/alt/*");
altholder.setInitParameter("resourceBase", altRoot.toUri().toASCIIString()); altholder.setInitParameter("resourceBase", altRoot.toUri().toASCIIString());
altholder.setInitParameter("pathInfoOnly", "true");
altholder.setInitParameter("dirAllowed", "false"); altholder.setInitParameter("dirAllowed", "false");
altholder.setInitParameter("redirectWelcome", "false"); altholder.setInitParameter("redirectWelcome", "false");
altholder.setInitParameter("welcomeServlets", "false"); altholder.setInitParameter("welcomeServlets", "false");
@ -1064,7 +1062,6 @@ public class DefaultServletTest
ServletHolder otherholder = context.addServlet(DefaultServlet.class, "/other/*"); ServletHolder otherholder = context.addServlet(DefaultServlet.class, "/other/*");
otherholder.setInitParameter("resourceBase", altRoot.toUri().toASCIIString()); otherholder.setInitParameter("resourceBase", altRoot.toUri().toASCIIString());
otherholder.setInitParameter("pathInfoOnly", "true");
otherholder.setInitParameter("dirAllowed", "true"); otherholder.setInitParameter("dirAllowed", "true");
otherholder.setInitParameter("redirectWelcome", "false"); otherholder.setInitParameter("redirectWelcome", "false");
otherholder.setInitParameter("welcomeServlets", "false"); otherholder.setInitParameter("welcomeServlets", "false");
@ -1242,7 +1239,6 @@ public class DefaultServletTest
defholder.setInitParameter("dirAllowed", "false"); defholder.setInitParameter("dirAllowed", "false");
defholder.setInitParameter("redirectWelcome", "false"); defholder.setInitParameter("redirectWelcome", "false");
defholder.setInitParameter("welcomeServlets", "true"); defholder.setInitParameter("welcomeServlets", "true");
defholder.setInitParameter("pathInfoOnly", "true");
ServletHolder gwholder = new ServletHolder("gateway", new HttpServlet() ServletHolder gwholder = new ServletHolder("gateway", new HttpServlet()
{ {
@ -3317,7 +3313,6 @@ public class DefaultServletTest
ServletHolder slashHolder = new ServletHolder("default", new DefaultServlet()); ServletHolder slashHolder = new ServletHolder("default", new DefaultServlet());
slashHolder.setInitParameter("redirectWelcome", "false"); slashHolder.setInitParameter("redirectWelcome", "false");
slashHolder.setInitParameter("welcomeServlets", "true"); slashHolder.setInitParameter("welcomeServlets", "true");
slashHolder.setInitParameter("pathInfoOnly", "false");
slashHolder.setInitParameter("baseResource", defaultDir.toAbsolutePath().toString()); slashHolder.setInitParameter("baseResource", defaultDir.toAbsolutePath().toString());
context.addServlet(slashHolder, "/"); context.addServlet(slashHolder, "/");
@ -3325,7 +3320,6 @@ public class DefaultServletTest
ServletHolder rHolder = new ServletHolder("rdefault", new DefaultServlet()); ServletHolder rHolder = new ServletHolder("rdefault", new DefaultServlet());
rHolder.setInitParameter("redirectWelcome", "false"); rHolder.setInitParameter("redirectWelcome", "false");
rHolder.setInitParameter("welcomeServlets", "true"); rHolder.setInitParameter("welcomeServlets", "true");
rHolder.setInitParameter("pathInfoOnly", "true");
rHolder.setInitParameter("baseResource", rDir.toAbsolutePath().toString()); rHolder.setInitParameter("baseResource", rDir.toAbsolutePath().toString());
context.addServlet(rHolder, "/r/*"); context.addServlet(rHolder, "/r/*");

View File

@ -96,8 +96,6 @@
* servlet context root. Useful for only serving static content out * servlet context root. Useful for only serving static content out
* of only specific subdirectories. * of only specific subdirectories.
* *
* pathInfoOnly If true, only the path info will be applied to the baseResource
*
* stylesheet Set with the location of an optional stylesheet that will be used * stylesheet Set with the location of an optional stylesheet that will be used
* to decorate the directory listing html. * to decorate the directory listing html.
* *

View File

@ -104,8 +104,6 @@
* servlet context root. Useful for only serving static content out * servlet context root. Useful for only serving static content out
* of only specific subdirectories. * of only specific subdirectories.
* *
* pathInfoOnly If true, only the path info will be applied to the baseResource
*
* stylesheet Set with the location of an optional stylesheet that will be used * stylesheet Set with the location of an optional stylesheet that will be used
* to decorate the directory listing html. * to decorate the directory listing html.
* *