| // |
| // ======================================================================== |
| // Copyright (c) 1995-2016 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 static org.hamcrest.Matchers.containsString; |
| import static org.hamcrest.Matchers.notNullValue; |
| import static org.hamcrest.Matchers.nullValue; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertThat; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.util.List; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| import java.util.concurrent.atomic.AtomicInteger; |
| |
| import javax.servlet.Servlet; |
| import javax.servlet.ServletContextEvent; |
| import javax.servlet.ServletContextListener; |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServlet; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.eclipse.jetty.security.ConstraintSecurityHandler; |
| import org.eclipse.jetty.security.SecurityHandler; |
| import org.eclipse.jetty.server.LocalConnector; |
| import org.eclipse.jetty.server.Request; |
| import org.eclipse.jetty.server.Server; |
| import org.eclipse.jetty.server.handler.AbstractHandler; |
| import org.eclipse.jetty.server.handler.AbstractHandlerContainer; |
| import org.eclipse.jetty.server.handler.ContextHandler; |
| import org.eclipse.jetty.server.handler.ContextHandlerCollection; |
| import org.eclipse.jetty.server.handler.HandlerList; |
| import org.eclipse.jetty.server.handler.HandlerWrapper; |
| import org.eclipse.jetty.server.handler.ResourceHandler; |
| import org.eclipse.jetty.server.handler.gzip.GzipHandler; |
| import org.eclipse.jetty.server.session.SessionHandler; |
| import org.eclipse.jetty.util.DecoratedObjectFactory; |
| import org.eclipse.jetty.util.Decorator; |
| import org.hamcrest.Matchers; |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| public class ServletContextHandlerTest |
| { |
| private Server _server; |
| private LocalConnector _connector; |
| |
| private static final AtomicInteger __testServlets = new AtomicInteger(); |
| |
| @Before |
| public void createServer() |
| { |
| _server = new Server(); |
| |
| _connector = new LocalConnector(_server); |
| _server.addConnector(_connector); |
| __testServlets.set(0); |
| } |
| |
| @After |
| public void destroyServer() throws Exception |
| { |
| _server.stop(); |
| _server.join(); |
| } |
| |
| @Test |
| public void testFindContainer() throws Exception |
| { |
| ContextHandlerCollection contexts = new ContextHandlerCollection(); |
| _server.setHandler(contexts); |
| |
| ServletContextHandler root = new ServletContextHandler(contexts,"/",ServletContextHandler.SESSIONS); |
| |
| SessionHandler session = root.getSessionHandler(); |
| ServletHandler servlet = root.getServletHandler(); |
| SecurityHandler security = new ConstraintSecurityHandler(); |
| root.setSecurityHandler(security); |
| |
| _server.start(); |
| |
| assertEquals(root, AbstractHandlerContainer.findContainerOf(_server, ContextHandler.class, session)); |
| assertEquals(root, AbstractHandlerContainer.findContainerOf(_server, ContextHandler.class, security)); |
| assertEquals(root, AbstractHandlerContainer.findContainerOf(_server, ContextHandler.class, servlet)); |
| } |
| |
| @Test |
| public void testInitOrder() throws Exception |
| { |
| ServletContextHandler context = new ServletContextHandler(); |
| ServletHolder holder0 = context.addServlet(TestServlet.class,"/test0"); |
| ServletHolder holder1 = context.addServlet(TestServlet.class,"/test1"); |
| ServletHolder holder2 = context.addServlet(TestServlet.class,"/test2"); |
| |
| holder1.setInitOrder(1); |
| holder2.setInitOrder(2); |
| |
| context.setContextPath("/"); |
| _server.setHandler(context); |
| _server.start(); |
| |
| assertEquals(2,__testServlets.get()); |
| |
| String response =_connector.getResponses("GET /test1 HTTP/1.0\r\n\r\n"); |
| Assert.assertThat(response,Matchers.containsString("200 OK")); |
| |
| assertEquals(2,__testServlets.get()); |
| |
| response =_connector.getResponses("GET /test2 HTTP/1.0\r\n\r\n"); |
| Assert.assertThat(response,containsString("200 OK")); |
| |
| assertEquals(2,__testServlets.get()); |
| |
| assertThat(holder0.getServletInstance(),nullValue()); |
| response =_connector.getResponses("GET /test0 HTTP/1.0\r\n\r\n"); |
| assertThat(response,containsString("200 OK")); |
| assertEquals(3,__testServlets.get()); |
| assertThat(holder0.getServletInstance(),notNullValue(Servlet.class)); |
| |
| _server.stop(); |
| assertEquals(0,__testServlets.get()); |
| |
| holder0.setInitOrder(0); |
| _server.start(); |
| assertEquals(3,__testServlets.get()); |
| assertThat(holder0.getServletInstance(),notNullValue(Servlet.class)); |
| _server.stop(); |
| assertEquals(0,__testServlets.get()); |
| |
| } |
| |
| @Test |
| public void testAddServletAfterStart() throws Exception |
| { |
| ServletContextHandler context = new ServletContextHandler(); |
| context.addServlet(TestServlet.class,"/test"); |
| context.setContextPath("/"); |
| _server.setHandler(context); |
| _server.start(); |
| |
| StringBuffer request = new StringBuffer(); |
| request.append("GET /test HTTP/1.0\n"); |
| request.append("Host: localhost\n"); |
| request.append("\n"); |
| |
| String response = _connector.getResponses(request.toString()); |
| assertResponseContains("Test", response); |
| |
| context.addServlet(HelloServlet.class, "/hello"); |
| |
| request = new StringBuffer(); |
| request.append("GET /hello HTTP/1.0\n"); |
| request.append("Host: localhost\n"); |
| request.append("\n"); |
| |
| response = _connector.getResponses(request.toString()); |
| assertResponseContains("Hello World", response); |
| } |
| |
| @Test |
| public void testHandlerBeforeServletHandler() throws Exception |
| { |
| ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); |
| |
| HandlerWrapper extra = new HandlerWrapper(); |
| |
| context.getSessionHandler().insertHandler(extra); |
| |
| context.addServlet(TestServlet.class,"/test"); |
| context.setContextPath("/"); |
| _server.setHandler(context); |
| _server.start(); |
| |
| StringBuffer request = new StringBuffer(); |
| request.append("GET /test HTTP/1.0\n"); |
| request.append("Host: localhost\n"); |
| request.append("\n"); |
| |
| String response = _connector.getResponses(request.toString()); |
| assertResponseContains("Test", response); |
| |
| assertEquals(extra,context.getSessionHandler().getHandler()); |
| } |
| |
| @Test |
| public void testGzipHandlerOption() throws Exception |
| { |
| ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS|ServletContextHandler.GZIP); |
| GzipHandler gzip = context.getGzipHandler(); |
| _server.start(); |
| assertEquals(context.getSessionHandler(),context.getHandler()); |
| assertEquals(gzip,context.getSessionHandler().getHandler()); |
| assertEquals(context.getServletHandler(),gzip.getHandler()); |
| } |
| |
| @Test |
| public void testGzipHandlerSet() throws Exception |
| { |
| ServletContextHandler context = new ServletContextHandler(); |
| context.setSessionHandler(new SessionHandler()); |
| context.setGzipHandler(new GzipHandler()); |
| GzipHandler gzip = context.getGzipHandler(); |
| _server.start(); |
| assertEquals(context.getSessionHandler(),context.getHandler()); |
| assertEquals(gzip,context.getSessionHandler().getHandler()); |
| assertEquals(context.getServletHandler(),gzip.getHandler()); |
| } |
| |
| @Test |
| public void testReplaceServletHandlerWithServlet() throws Exception |
| { |
| ServletContextHandler context = new ServletContextHandler(); |
| context.addServlet(TestServlet.class,"/test"); |
| context.setContextPath("/"); |
| _server.setHandler(context); |
| _server.start(); |
| |
| StringBuffer request = new StringBuffer(); |
| request.append("GET /test HTTP/1.0\n"); |
| request.append("Host: localhost\n"); |
| request.append("\n"); |
| |
| String response = _connector.getResponses(request.toString()); |
| assertResponseContains("Test", response); |
| |
| context.stop(); |
| ServletHandler srvHnd = new ServletHandler(); |
| srvHnd.addServletWithMapping(HelloServlet.class,"/hello"); |
| context.setServletHandler(srvHnd); |
| context.start(); |
| |
| request = new StringBuffer(); |
| request.append("GET /hello HTTP/1.0\n"); |
| request.append("Host: localhost\n"); |
| request.append("\n"); |
| |
| response = _connector.getResponses(request.toString()); |
| assertResponseContains("Hello World", response); |
| } |
| |
| @Test |
| public void testReplaceServletHandlerWithoutServlet() throws Exception |
| { |
| ServletContextHandler context = new ServletContextHandler(); |
| context.addServlet(TestServlet.class,"/test"); |
| context.setContextPath("/"); |
| _server.setHandler(context); |
| _server.start(); |
| |
| StringBuffer request = new StringBuffer(); |
| request.append("GET /test HTTP/1.0\n"); |
| request.append("Host: localhost\n"); |
| request.append("\n"); |
| |
| String response = _connector.getResponses(request.toString()); |
| assertResponseContains("Test", response); |
| |
| context.stop(); |
| ServletHandler srvHnd = new ServletHandler(); |
| context.setServletHandler(srvHnd); |
| context.start(); |
| |
| context.addServlet(HelloServlet.class,"/hello"); |
| |
| request = new StringBuffer(); |
| request.append("GET /hello HTTP/1.0\n"); |
| request.append("Host: localhost\n"); |
| request.append("\n"); |
| |
| response = _connector.getResponses(request.toString()); |
| assertResponseContains("Hello World", response); |
| } |
| |
| @Test |
| public void testReplaceHandler () throws Exception |
| { |
| ServletContextHandler servletContextHandler = new ServletContextHandler(); |
| ServletHolder sh = new ServletHolder(new TestServlet()); |
| servletContextHandler.addServlet(sh, "/foo"); |
| final AtomicBoolean contextInit = new AtomicBoolean(false); |
| final AtomicBoolean contextDestroy = new AtomicBoolean(false); |
| |
| servletContextHandler.addEventListener(new ServletContextListener() { |
| |
| @Override |
| public void contextInitialized(ServletContextEvent sce) |
| { |
| if (sce.getServletContext() != null) |
| contextInit.set(true); |
| } |
| |
| @Override |
| public void contextDestroyed(ServletContextEvent sce) |
| { |
| if (sce.getServletContext() != null) |
| contextDestroy.set(true); |
| } |
| |
| }); |
| ServletHandler shandler = servletContextHandler.getServletHandler(); |
| |
| ResourceHandler rh = new ResourceHandler(); |
| |
| servletContextHandler.insertHandler(rh); |
| assertEquals(shandler, servletContextHandler.getServletHandler()); |
| assertEquals(rh, servletContextHandler.getHandler()); |
| assertEquals(rh.getHandler(), shandler); |
| _server.setHandler(servletContextHandler); |
| _server.start(); |
| assertTrue(contextInit.get()); |
| _server.stop(); |
| assertTrue(contextDestroy.get()); |
| } |
| |
| |
| @Test |
| public void testFallThrough() throws Exception |
| { |
| HandlerList list = new HandlerList(); |
| _server.setHandler(list); |
| |
| ServletContextHandler root = new ServletContextHandler(list,"/",ServletContextHandler.SESSIONS); |
| |
| ServletHandler servlet = root.getServletHandler(); |
| servlet.setEnsureDefaultServlet(false); |
| servlet.addServletWithMapping(HelloServlet.class, "/hello/*"); |
| |
| list.addHandler(new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException |
| { |
| response.sendError(404, "Fell Through"); |
| } |
| }); |
| |
| _server.start(); |
| |
| String response= _connector.getResponses("GET /hello HTTP/1.0\r\n\r\n"); |
| Assert.assertThat(response, Matchers.containsString("200 OK")); |
| |
| response= _connector.getResponses("GET /other HTTP/1.0\r\n\r\n"); |
| Assert.assertThat(response, Matchers.containsString("404 Fell Through")); |
| |
| } |
| |
| /** |
| * Test behavior of legacy ServletContextHandler.Decorator, with |
| * new DecoratedObjectFactory class |
| * @throws Exception on test failure |
| */ |
| @SuppressWarnings("deprecation") |
| @Test |
| public void testLegacyDecorator() throws Exception |
| { |
| ServletContextHandler context = new ServletContextHandler(); |
| context.addDecorator(new DummyLegacyDecorator()); |
| _server.setHandler(context); |
| |
| context.addServlet(DecoratedObjectFactoryServlet.class, "/objfactory/*"); |
| _server.start(); |
| |
| String response= _connector.getResponses("GET /objfactory/ HTTP/1.0\r\n\r\n"); |
| assertThat("Response status code", response, containsString("200 OK")); |
| |
| String expected = String.format("Attribute[%s] = %s", DecoratedObjectFactory.ATTR, DecoratedObjectFactory.class.getName()); |
| assertThat("Has context attribute", response, containsString(expected)); |
| |
| assertThat("Decorators size", response, containsString("Decorators.size = [2]")); |
| |
| expected = String.format("decorator[] = %s", DummyLegacyDecorator.class.getName()); |
| assertThat("Specific Legacy Decorator", response, containsString(expected)); |
| } |
| |
| /** |
| * Test behavior of new {@link org.eclipse.jetty.util.Decorator}, with |
| * new DecoratedObjectFactory class |
| * @throws Exception on test failure |
| */ |
| @Test |
| public void testUtilDecorator() throws Exception |
| { |
| ServletContextHandler context = new ServletContextHandler(); |
| context.getObjectFactory().addDecorator(new DummyUtilDecorator()); |
| _server.setHandler(context); |
| |
| context.addServlet(DecoratedObjectFactoryServlet.class, "/objfactory/*"); |
| _server.start(); |
| |
| String response= _connector.getResponses("GET /objfactory/ HTTP/1.0\r\n\r\n"); |
| assertThat("Response status code", response, containsString("200 OK")); |
| |
| String expected = String.format("Attribute[%s] = %s", DecoratedObjectFactory.ATTR, DecoratedObjectFactory.class.getName()); |
| assertThat("Has context attribute", response, containsString(expected)); |
| |
| assertThat("Decorators size", response, containsString("Decorators.size = [2]")); |
| |
| expected = String.format("decorator[] = %s", DummyUtilDecorator.class.getName()); |
| assertThat("Specific Legacy Decorator", response, containsString(expected)); |
| } |
| |
| private int assertResponseContains(String expected, String response) |
| { |
| int idx = response.indexOf(expected); |
| if (idx == (-1)) |
| { |
| // Not found |
| StringBuffer err = new StringBuffer(); |
| err.append("Response does not contain expected string \"").append(expected).append("\""); |
| err.append("\n").append(response); |
| |
| System.err.println(err); |
| Assert.fail(err.toString()); |
| } |
| return idx; |
| } |
| |
| public static class HelloServlet extends HttpServlet |
| { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected void doGet(HttpServletRequest req, HttpServletResponse resp) |
| throws ServletException, IOException |
| { |
| resp.setStatus(HttpServletResponse.SC_OK); |
| PrintWriter writer = resp.getWriter(); |
| writer.write("Hello World"); |
| } |
| } |
| |
| public static class DummyUtilDecorator implements org.eclipse.jetty.util.Decorator |
| { |
| @Override |
| public <T> T decorate(T o) |
| { |
| return o; |
| } |
| |
| @Override |
| public void destroy(Object o) |
| { |
| } |
| } |
| |
| public static class DummyLegacyDecorator implements org.eclipse.jetty.servlet.ServletContextHandler.Decorator |
| { |
| @Override |
| public <T> T decorate(T o) |
| { |
| return o; |
| } |
| |
| @Override |
| public void destroy(Object o) |
| { |
| } |
| } |
| |
| public static class DecoratedObjectFactoryServlet extends HttpServlet |
| { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException |
| { |
| resp.setContentType("text/plain"); |
| resp.setStatus(HttpServletResponse.SC_OK); |
| PrintWriter out = resp.getWriter(); |
| |
| Object obj = req.getServletContext().getAttribute(DecoratedObjectFactory.ATTR); |
| out.printf("Attribute[%s] = %s%n",DecoratedObjectFactory.ATTR,obj.getClass().getName()); |
| |
| if (obj instanceof DecoratedObjectFactory) |
| { |
| out.printf("Object is a DecoratedObjectFactory%n"); |
| DecoratedObjectFactory objFactory = (DecoratedObjectFactory)obj; |
| List<Decorator> decorators = objFactory.getDecorators(); |
| out.printf("Decorators.size = [%d]%n",decorators.size()); |
| for (Decorator decorator : decorators) |
| { |
| out.printf(" decorator[] = %s%n",decorator.getClass().getName()); |
| } |
| } |
| else |
| { |
| out.printf("Object is NOT a DecoratedObjectFactory%n"); |
| } |
| } |
| } |
| |
| public static class TestServlet extends HttpServlet |
| { |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public void destroy() |
| { |
| super.destroy(); |
| __testServlets.decrementAndGet(); |
| } |
| |
| @Override |
| public void init() throws ServletException |
| { |
| __testServlets.incrementAndGet(); |
| super.init(); |
| } |
| |
| @Override |
| protected void doGet(HttpServletRequest req, HttpServletResponse resp) |
| throws ServletException, IOException |
| { |
| resp.setStatus(HttpServletResponse.SC_OK); |
| PrintWriter writer = resp.getWriter(); |
| writer.write("Test"); |
| } |
| } |
| } |