Skip to content

Commit

Permalink
Issue #10141 and #10142 - Reintroduce context init-param `org.eclipse…
Browse files Browse the repository at this point in the history
….jetty.servlet.Default.` prefix for ee10

+ Fix named servlet lookup NPE in ee10 ServletHandler.getMappedServlet
  • Loading branch information
joakime committed Jul 25, 2023
1 parent e587af9 commit fc872ba
Show file tree
Hide file tree
Showing 4 changed files with 368 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@
public class DefaultServlet extends HttpServlet
{
private static final Logger LOG = LoggerFactory.getLogger(DefaultServlet.class);
public static final String CONTEXT_INIT = "org.eclipse.jetty.servlet.Default.";

private ServletContextHandler _contextHandler;
private ServletResourceService _resourceService;
Expand Down Expand Up @@ -395,6 +396,15 @@ else if (gzip == Boolean.TRUE)
return ret;
}

@Override
public String getInitParameter(String name)
{
String value = getServletContext().getInitParameter(CONTEXT_INIT + name);
if (value == null)
value = super.getInitParameter(name);
return value;
}

private Boolean getInitBoolean(String name)
{
String value = getInitParameter(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,8 @@ public MatchedResource<MappedServlet> getMatchedServlet(String target)
public MappedServlet getMappedServlet(String target)
{
MatchedResource<MappedServlet> matchedResource = getMatchedServlet(target);
if (matchedResource == null) // named servlet
return null;
return matchedResource.getResource();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
//
// ========================================================================
// 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.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
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.HttpTester;
import org.eclipse.jetty.server.LocalConnector;
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.eclipse.jetty.util.resource.ResourceFactory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;

@ExtendWith(WorkDirExtension.class)
public class DefaultServletInitTest
{
private Server server;
private LocalConnector localConnector;

@AfterEach
public void stopServer()
{
LifeCycle.stop(server);
}

public void startServer(ServletContextHandler contextHandler) throws Exception
{
server = new Server();
localConnector = new LocalConnector(server);
server.addConnector(localConnector);
server.setHandler(contextHandler);
server.start();
}

public static class ContextInit implements Consumer<ServletContextHandler>
{
private final String key;
private final String value;

public ContextInit(String key, String value)
{
this.key = key;
this.value = value;
}

@Override
public void accept(ServletContextHandler servletContextHandler)
{
servletContextHandler.setInitParameter(key, value);
}

@Override
public String toString()
{
return "ContextInit[%s=%s]".formatted(key, value);
}
}

public static class HolderInit implements Consumer<ServletHolder>
{
private final String key;
private final String value;

public HolderInit(String key, String value)
{
this.key = key;
this.value = value;
}

@Override
public void accept(ServletHolder servletHolder)
{
servletHolder.setInitParameter(key, value);
}

@Override
public String toString()
{
return "HolderInit[%s=%s]".formatted(key, value);
}
}

public record Config(ContextInit contextInit,
HolderInit holderInit)
{}

public static Stream<Config> welcomeServletsInitSource()
{
List<Config> configs = new ArrayList<>();

configs.add(new Config(null, new HolderInit("welcomeServlets", "true")));
configs.add(new Config(null, new HolderInit("welcomeServlets", "exact")));
configs.add(new Config(new ContextInit("org.eclipse.jetty.servlet.Default.welcomeServlets", "true"), null));
configs.add(new Config(new ContextInit("org.eclipse.jetty.servlet.Default.welcomeServlets", "exact"), null));

return configs.stream();
}

@ParameterizedTest
@MethodSource("welcomeServletsInitSource")
public void testInitWelcomeServlets(Config config, WorkDir workDir) throws Exception
{
HttpServlet testServlet = new HttpServlet()
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setCharacterEncoding("utf-8");
response.setContentType("text/plain");
String pathInfo = request.getPathInfo() == null ? "" : request.getPathInfo();
response.getWriter().println("Content from testServlet with pathInfo[" + pathInfo + "]");
}
};

Path docroot = workDir.getEmptyPathDir();
FS.ensureDirExists(docroot.resolve("foo"));

ServletContextHandler contextHandler = new ServletContextHandler();
ResourceFactory resourceFactory = ResourceFactory.of(contextHandler);
contextHandler.setBaseResource(resourceFactory.newResource(docroot));
contextHandler.setContextPath("/");
contextHandler.setWelcomeFiles(new String[]{"testServlet"});

ServletHolder myHolder = new ServletHolder("testServlet", testServlet);
contextHandler.addServlet(myHolder, "/testServlet");

ServletHolder defaultHolder = new ServletHolder("default", DefaultServlet.class);
contextHandler.addServlet(defaultHolder, "/");

if (config.contextInit != null)
config.contextInit.accept(contextHandler);
if (config.holderInit != null)
config.holderInit.accept(defaultHolder);

startServer(contextHandler);

String rawRequest = """
GET / HTTP/1.1
Host: test
Connection: close
""";

HttpTester.Response response = HttpTester.parseResponse(localConnector.getResponse(rawRequest));
assertThat(response.getStatus(), is(200));
assertThat(response.getContent(), containsString("Content from testServlet with pathInfo[]"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
//
// ========================================================================
// 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.ee9.servlet;

import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
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.HttpTester;
import org.eclipse.jetty.server.LocalConnector;
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.eclipse.jetty.util.resource.ResourceFactory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;

@ExtendWith(WorkDirExtension.class)
public class DefaultServletInitTest
{
private Server server;
private LocalConnector localConnector;

@AfterEach
public void stopServer()
{
LifeCycle.stop(server);
}

public void startServer(ServletContextHandler contextHandler) throws Exception
{
server = new Server();
localConnector = new LocalConnector(server);
server.addConnector(localConnector);
server.setHandler(contextHandler);
server.start();
}

public static class ContextInit implements Consumer<ServletContextHandler>
{
private final String key;
private final String value;

public ContextInit(String key, String value)
{
this.key = key;
this.value = value;
}

@Override
public void accept(ServletContextHandler servletContextHandler)
{
servletContextHandler.setInitParameter(key, value);
}

@Override
public String toString()
{
return "ContextInit[%s=%s]".formatted(key, value);
}
}

public static class HolderInit implements Consumer<ServletHolder>
{
private final String key;
private final String value;

public HolderInit(String key, String value)
{
this.key = key;
this.value = value;
}

@Override
public void accept(ServletHolder servletHolder)
{
servletHolder.setInitParameter(key, value);
}

@Override
public String toString()
{
return "HolderInit[%s=%s]".formatted(key, value);
}
}

public record Config(ContextInit contextInit,
HolderInit holderInit)
{}

public static Stream<Config> welcomeServletsInitSource()
{
List<Config> configs = new ArrayList<>();

configs.add(new Config(null, new HolderInit("welcomeServlets", "true")));
configs.add(new Config(null, new HolderInit("welcomeServlets", "exact")));
configs.add(new Config(new ContextInit("org.eclipse.jetty.servlet.Default.welcomeServlets", "true"), null));
configs.add(new Config(new ContextInit("org.eclipse.jetty.servlet.Default.welcomeServlets", "exact"), null));

return configs.stream();
}

@ParameterizedTest
@MethodSource("welcomeServletsInitSource")
public void testInitWelcomeServlets(Config config, WorkDir workDir) throws Exception
{
HttpServlet testServlet = new HttpServlet()
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setCharacterEncoding("utf-8");
response.setContentType("text/plain");
String pathInfo = request.getPathInfo() == null ? "" : request.getPathInfo();
response.getWriter().println("Content from testServlet with pathInfo[" + pathInfo + "]");
}
};

Path docroot = workDir.getEmptyPathDir();
FS.ensureDirExists(docroot.resolve("foo"));

ServletContextHandler contextHandler = new ServletContextHandler();
ResourceFactory resourceFactory = ResourceFactory.of(contextHandler);
contextHandler.setBaseResource(resourceFactory.newResource(docroot));
contextHandler.setContextPath("/");
contextHandler.setWelcomeFiles(new String[]{"testServlet"});

ServletHolder myHolder = new ServletHolder("testServlet", testServlet);
contextHandler.addServlet(myHolder, "/testServlet");

ServletHolder defaultHolder = new ServletHolder("default", DefaultServlet.class);
contextHandler.addServlet(defaultHolder, "/");

if (config.contextInit != null)
config.contextInit.accept(contextHandler);
if (config.holderInit != null)
config.holderInit.accept(defaultHolder);

startServer(contextHandler);

String rawRequest = """
GET / HTTP/1.1
Host: test
Connection: close
""";

HttpTester.Response response = HttpTester.parseResponse(localConnector.getResponse(rawRequest));
assertThat(response.getStatus(), is(200));
assertThat(response.getContent(), containsString("Content from testServlet with pathInfo[]"));
}
}

0 comments on commit fc872ba

Please sign in to comment.