blob: ee4af4420ee69c328d293d7e96257da356317bdc [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2015 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.server.handler;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.resource.Resource;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
public class ContextHandlerTest
{
@Test
public void testGetResourcePathsWhenSuppliedPathEndsInSlash() throws Exception
{
checkResourcePathsForExampleWebApp("/WEB-INF/");
}
@Test
public void testGetResourcePathsWhenSuppliedPathDoesNotEndInSlash() throws Exception
{
checkResourcePathsForExampleWebApp("/WEB-INF");
}
@Test
public void testVirtualHostNormalization() throws Exception
{
Server server = new Server();
LocalConnector connector = new LocalConnector(server);
server.setConnectors(new Connector[]
{ connector });
ContextHandler contextA = new ContextHandler("/");
contextA.setVirtualHosts(new String[]
{ "www.example.com" });
IsHandledHandler handlerA = new IsHandledHandler();
contextA.setHandler(handlerA);
ContextHandler contextB = new ContextHandler("/");
IsHandledHandler handlerB = new IsHandledHandler();
contextB.setHandler(handlerB);
contextB.setVirtualHosts(new String[]
{ "www.example2.com." });
ContextHandler contextC = new ContextHandler("/");
IsHandledHandler handlerC = new IsHandledHandler();
contextC.setHandler(handlerC);
HandlerCollection c = new HandlerCollection();
c.addHandler(contextA);
c.addHandler(contextB);
c.addHandler(contextC);
server.setHandler(c);
try
{
server.start();
connector.getResponses("GET / HTTP/1.0\n" + "Host: www.example.com.\n\n");
Assert.assertTrue(handlerA.isHandled());
Assert.assertFalse(handlerB.isHandled());
Assert.assertFalse(handlerC.isHandled());
handlerA.reset();
handlerB.reset();
handlerC.reset();
connector.getResponses("GET / HTTP/1.0\n" + "Host: www.example2.com\n\n");
Assert.assertFalse(handlerA.isHandled());
Assert.assertTrue(handlerB.isHandled());
Assert.assertFalse(handlerC.isHandled());
}
finally
{
server.stop();
}
}
@Test
public void testNamedConnector() throws Exception
{
Server server = new Server();
LocalConnector connector = new LocalConnector(server);
LocalConnector connectorN = new LocalConnector(server);
connectorN.setName("name");
server.setConnectors(new Connector[] { connector, connectorN });
ContextHandler contextA = new ContextHandler("/");
contextA.setVirtualHosts(new String[]{"www.example.com" });
IsHandledHandler handlerA = new IsHandledHandler();
contextA.setHandler(handlerA);
ContextHandler contextB = new ContextHandler("/");
IsHandledHandler handlerB = new IsHandledHandler();
contextB.setHandler(handlerB);
contextB.setVirtualHosts(new String[]{ "@name" });
ContextHandler contextC = new ContextHandler("/");
IsHandledHandler handlerC = new IsHandledHandler();
contextC.setHandler(handlerC);
HandlerCollection c = new HandlerCollection();
c.addHandler(contextA);
c.addHandler(contextB);
c.addHandler(contextC);
server.setHandler(c);
server.start();
try
{
connector.getResponses("GET / HTTP/1.0\n" + "Host: www.example.com.\n\n");
Assert.assertTrue(handlerA.isHandled());
Assert.assertFalse(handlerB.isHandled());
Assert.assertFalse(handlerC.isHandled());
handlerA.reset();
handlerB.reset();
handlerC.reset();
connector.getResponses("GET / HTTP/1.0\n" + "Host: localhost\n\n");
Assert.assertFalse(handlerA.isHandled());
Assert.assertFalse(handlerB.isHandled());
Assert.assertTrue(handlerC.isHandled());
handlerA.reset();
handlerB.reset();
handlerC.reset();
connectorN.getResponses("GET / HTTP/1.0\n" + "Host: www.example.com.\n\n");
Assert.assertTrue(handlerA.isHandled());
Assert.assertFalse(handlerB.isHandled());
Assert.assertFalse(handlerC.isHandled());
handlerA.reset();
handlerB.reset();
handlerC.reset();
connectorN.getResponses("GET / HTTP/1.0\n" + "Host: localhost\n\n");
Assert.assertFalse(handlerA.isHandled());
Assert.assertTrue(handlerB.isHandled());
Assert.assertFalse(handlerC.isHandled());
handlerA.reset();
handlerB.reset();
handlerC.reset();
}
finally
{
server.stop();
}
}
@Test
public void testContextGetContext() throws Exception
{
Server server = new Server();
LocalConnector connector = new LocalConnector(server);
server.setConnectors(new Connector[] { connector });
ContextHandlerCollection contexts = new ContextHandlerCollection();
server.setHandler(contexts);
ContextHandler rootA = new ContextHandler(contexts,"/");
ContextHandler fooA = new ContextHandler(contexts,"/foo");
ContextHandler foobarA = new ContextHandler(contexts,"/foo/bar");
server.start();
// System.err.println(server.dump());
Assert.assertEquals(rootA._scontext, rootA._scontext.getContext("/"));
Assert.assertEquals(fooA._scontext, rootA._scontext.getContext("/foo"));
Assert.assertEquals(foobarA._scontext, rootA._scontext.getContext("/foo/bar"));
Assert.assertEquals(foobarA._scontext, rootA._scontext.getContext("/foo/bar/bob.jsp"));
Assert.assertEquals(rootA._scontext, rootA._scontext.getContext("/other"));
Assert.assertEquals(fooA._scontext, rootA._scontext.getContext("/foo/other"));
Assert.assertEquals(rootA._scontext, foobarA._scontext.getContext("/"));
Assert.assertEquals(fooA._scontext, foobarA._scontext.getContext("/foo"));
Assert.assertEquals(foobarA._scontext, foobarA._scontext.getContext("/foo/bar"));
Assert.assertEquals(foobarA._scontext, foobarA._scontext.getContext("/foo/bar/bob.jsp"));
Assert.assertEquals(rootA._scontext, foobarA._scontext.getContext("/other"));
Assert.assertEquals(fooA._scontext, foobarA._scontext.getContext("/foo/other"));
}
@Test
public void testLifeCycle() throws Exception
{
Server server = new Server();
LocalConnector connector = new LocalConnector(server);
server.setConnectors(new Connector[] { connector });
ContextHandlerCollection contexts = new ContextHandlerCollection();
server.setHandler(contexts);
ContextHandler root = new ContextHandler(contexts,"/");
root.setHandler(new ContextPathHandler());
ContextHandler foo = new ContextHandler(contexts,"/foo");
foo.setHandler(new ContextPathHandler());
ContextHandler foobar = new ContextHandler(contexts,"/foo/bar");
foobar.setHandler(new ContextPathHandler());
// check that all contexts start normally
server.start();
Assert.assertThat(connector.getResponses("GET / HTTP/1.0\n\n"), Matchers.containsString("ctx=''"));
Assert.assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"), Matchers.containsString("ctx='/foo'"));
Assert.assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"), Matchers.containsString("ctx='/foo/bar'"));
// If we stop foobar, then requests will be handled by foo
foobar.stop();
Assert.assertThat(connector.getResponses("GET / HTTP/1.0\n\n"), Matchers.containsString("ctx=''"));
Assert.assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"), Matchers.containsString("ctx='/foo'"));
Assert.assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"), Matchers.containsString("ctx='/foo'"));
// If we shutdown foo then requests will be 503'd
foo.shutdown().get();
Assert.assertThat(connector.getResponses("GET / HTTP/1.0\n\n"), Matchers.containsString("ctx=''"));
Assert.assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"), Matchers.containsString("503"));
Assert.assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"), Matchers.containsString("503"));
// If we stop foo then requests will be handled by root
foo.stop();
Assert.assertThat(connector.getResponses("GET / HTTP/1.0\n\n"), Matchers.containsString("ctx=''"));
Assert.assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"), Matchers.containsString("ctx=''"));
Assert.assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"), Matchers.containsString("ctx=''"));
// If we start foo then foobar requests will be handled by foo
foo.start();
Assert.assertThat(connector.getResponses("GET / HTTP/1.0\n\n"), Matchers.containsString("ctx=''"));
Assert.assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"), Matchers.containsString("ctx='/foo'"));
Assert.assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"), Matchers.containsString("ctx='/foo'"));
// If we start foobar then foobar requests will be handled by foobar
foobar.start();
Assert.assertThat(connector.getResponses("GET / HTTP/1.0\n\n"), Matchers.containsString("ctx=''"));
Assert.assertThat(connector.getResponses("GET /foo/xxx HTTP/1.0\n\n"), Matchers.containsString("ctx='/foo'"));
Assert.assertThat(connector.getResponses("GET /foo/bar/xxx HTTP/1.0\n\n"), Matchers.containsString("ctx='/foo/bar'"));
}
@Test
public void testContextVirtualGetContext() throws Exception
{
Server server = new Server();
LocalConnector connector = new LocalConnector(server);
server.setConnectors(new Connector[] { connector });
ContextHandlerCollection contexts = new ContextHandlerCollection();
server.setHandler(contexts);
ContextHandler rootA = new ContextHandler(contexts,"/");
rootA.setVirtualHosts(new String[] {"a.com"});
ContextHandler rootB = new ContextHandler(contexts,"/");
rootB.setVirtualHosts(new String[] {"b.com"});
ContextHandler rootC = new ContextHandler(contexts,"/");
rootC.setVirtualHosts(new String[] {"c.com"});
ContextHandler fooA = new ContextHandler(contexts,"/foo");
fooA.setVirtualHosts(new String[] {"a.com"});
ContextHandler fooB = new ContextHandler(contexts,"/foo");
fooB.setVirtualHosts(new String[] {"b.com"});
ContextHandler foobarA = new ContextHandler(contexts,"/foo/bar");
foobarA.setVirtualHosts(new String[] {"a.com"});
server.start();
// System.err.println(server.dump());
Assert.assertEquals(rootA._scontext, rootA._scontext.getContext("/"));
Assert.assertEquals(fooA._scontext, rootA._scontext.getContext("/foo"));
Assert.assertEquals(foobarA._scontext, rootA._scontext.getContext("/foo/bar"));
Assert.assertEquals(foobarA._scontext, rootA._scontext.getContext("/foo/bar/bob"));
Assert.assertEquals(rootA._scontext, rootA._scontext.getContext("/other"));
Assert.assertEquals(rootB._scontext, rootB._scontext.getContext("/other"));
Assert.assertEquals(rootC._scontext, rootC._scontext.getContext("/other"));
Assert.assertEquals(fooB._scontext, rootB._scontext.getContext("/foo/other"));
Assert.assertEquals(rootC._scontext, rootC._scontext.getContext("/foo/other"));
}
@Test
public void testVirtualHostWildcard() throws Exception
{
Server server = new Server();
LocalConnector connector = new LocalConnector(server);
server.setConnectors(new Connector[] { connector });
ContextHandler context = new ContextHandler("/");
IsHandledHandler handler = new IsHandledHandler();
context.setHandler(handler);
server.setHandler(context);
try
{
server.start();
checkWildcardHost(true,server,null,new String[] {"example.com", ".example.com", "vhost.example.com"});
checkWildcardHost(false,server,new String[] {null},new String[] {"example.com", ".example.com", "vhost.example.com"});
checkWildcardHost(true,server,new String[] {"example.com", "*.example.com"}, new String[] {"example.com", ".example.com", "vhost.example.com"});
checkWildcardHost(false,server,new String[] {"example.com", "*.example.com"}, new String[] {"badexample.com", ".badexample.com", "vhost.badexample.com"});
checkWildcardHost(false,server,new String[] {"*."}, new String[] {"anything.anything"});
checkWildcardHost(true,server,new String[] {"*.example.com"}, new String[] {"vhost.example.com", ".example.com"});
checkWildcardHost(false,server,new String[] {"*.example.com"}, new String[] {"vhost.www.example.com", "example.com", "www.vhost.example.com"});
checkWildcardHost(true,server,new String[] {"*.sub.example.com"}, new String[] {"vhost.sub.example.com", ".sub.example.com"});
checkWildcardHost(false,server,new String[] {"*.sub.example.com"}, new String[] {".example.com", "sub.example.com", "vhost.example.com"});
checkWildcardHost(false,server,new String[] {"example.*.com","example.com.*"}, new String[] {"example.vhost.com", "example.com.vhost", "example.com"});
}
finally
{
server.stop();
}
}
@Test
public void testVirtualHostManagement() throws Exception
{
ContextHandler context = new ContextHandler("/");
// test singular
context.setVirtualHosts(new String[] { "www.example.com"} );
Assert.assertEquals(1, context.getVirtualHosts().length);
// test adding two more
context.addVirtualHosts(new String[] { "www.example2.com", "www.example3.com"});
Assert.assertEquals(3, context.getVirtualHosts().length);
// test adding existing context
context.addVirtualHosts(new String[] { "www.example.com" });
Assert.assertEquals(3, context.getVirtualHosts().length);
// test removing existing
context.removeVirtualHosts(new String[] { "www.example3.com" });
Assert.assertEquals(2, context.getVirtualHosts().length);
// test removing non-existent
context.removeVirtualHosts(new String[] { "www.example3.com" });
Assert.assertEquals(2, context.getVirtualHosts().length);
// test removing all remaining and resets to null
context.removeVirtualHosts(new String[] { "www.example.com", "www.example2.com" });
Assert.assertArrayEquals(null, context.getVirtualHosts());
}
@Test
public void testAttributes() throws Exception
{
ContextHandler handler = new ContextHandler();
handler.setServer(new Server());
handler.setAttribute("aaa","111");
Assert.assertEquals("111", handler.getServletContext().getAttribute("aaa"));
Assert.assertEquals(null, handler.getAttribute("bbb"));
handler.start();
handler.getServletContext().setAttribute("aaa","000");
handler.setAttribute("ccc","333");
handler.getServletContext().setAttribute("ddd","444");
Assert.assertEquals("111", handler.getServletContext().getAttribute("aaa"));
Assert.assertEquals(null, handler.getServletContext().getAttribute("bbb"));
handler.getServletContext().setAttribute("bbb","222");
Assert.assertEquals("333", handler.getServletContext().getAttribute("ccc"));
Assert.assertEquals("444", handler.getServletContext().getAttribute("ddd"));
Assert.assertEquals("111", handler.getAttribute("aaa"));
Assert.assertEquals(null, handler.getAttribute("bbb"));
Assert.assertEquals("333", handler.getAttribute("ccc"));
Assert.assertEquals(null, handler.getAttribute("ddd"));
handler.stop();
Assert.assertEquals("111", handler.getServletContext().getAttribute("aaa"));
Assert.assertEquals(null, handler.getServletContext().getAttribute("bbb"));
Assert.assertEquals("333", handler.getServletContext().getAttribute("ccc"));
Assert.assertEquals(null, handler.getServletContext().getAttribute("ddd"));
}
@Test
public void testProtected() throws Exception
{
ContextHandler handler = new ContextHandler();
String[] protectedTargets = {"/foo-inf", "/bar-inf"};
handler.setProtectedTargets(protectedTargets);
Assert.assertTrue(handler.isProtectedTarget("/foo-inf/x/y/z"));
Assert.assertFalse(handler.isProtectedTarget("/foo/x/y/z"));
Assert.assertTrue(handler.isProtectedTarget("/foo-inf?x=y&z=1"));
Assert.assertFalse(handler.isProtectedTarget("/foo-inf-bar"));
protectedTargets = new String[4];
System.arraycopy(handler.getProtectedTargets(), 0, protectedTargets, 0, 2);
protectedTargets[2] = "/abc";
protectedTargets[3] = "/def";
handler.setProtectedTargets(protectedTargets);
Assert.assertTrue(handler.isProtectedTarget("/foo-inf/x/y/z"));
Assert.assertFalse(handler.isProtectedTarget("/foo/x/y/z"));
Assert.assertTrue(handler.isProtectedTarget("/foo-inf?x=y&z=1"));
Assert.assertTrue(handler.isProtectedTarget("/abc/124"));
Assert.assertTrue(handler.isProtectedTarget("//def"));
Assert.assertTrue(handler.isProtectedTarget("/ABC/7777"));
}
private void checkResourcePathsForExampleWebApp(String root) throws IOException
{
File testDirectory = setupTestDirectory();
ContextHandler handler = new ContextHandler();
Assert.assertTrue("Not a directory " + testDirectory, testDirectory.isDirectory());
handler.setBaseResource(Resource.newResource(Resource.toURL(testDirectory)));
List<String> paths = new ArrayList<>(handler.getResourcePaths(root));
Assert.assertEquals(2, paths.size());
Collections.sort(paths);
Assert.assertEquals("/WEB-INF/jsp/", paths.get(0));
Assert.assertEquals("/WEB-INF/web.xml", paths.get(1));
}
private File setupTestDirectory() throws IOException
{
File tmpDir = new File( System.getProperty( "basedir",".") + "/target/tmp/ContextHandlerTest" );
tmpDir=tmpDir.getCanonicalFile();
if (!tmpDir.exists())
Assert.assertTrue(tmpDir.mkdirs());
File tmp = File.createTempFile("cht",null, tmpDir );
Assert.assertTrue(tmp.delete());
Assert.assertTrue(tmp.mkdir());
tmp.deleteOnExit();
File root = new File(tmp,getClass().getName());
Assert.assertTrue(root.mkdir());
File webInf = new File(root,"WEB-INF");
Assert.assertTrue(webInf.mkdir());
Assert.assertTrue(new File(webInf, "jsp").mkdir());
Assert.assertTrue(new File(webInf, "web.xml").createNewFile());
return root;
}
private void checkWildcardHost(boolean succeed, Server server, String[] contextHosts, String[] requestHosts) throws Exception
{
LocalConnector connector = (LocalConnector)server.getConnectors()[0];
ContextHandler context = (ContextHandler)server.getHandler();
context.setVirtualHosts(contextHosts);
IsHandledHandler handler = (IsHandledHandler)context.getHandler();
for(String host : requestHosts)
{
connector.getResponses("GET / HTTP/1.1\n" + "Host: "+host+"\nConnection:close\n\n");
if(succeed)
Assert.assertTrue("'" + host + "' should have been handled.", handler.isHandled());
else
Assert.assertFalse("'" + host + "' should not have been handled.", handler.isHandled());
handler.reset();
}
}
private static final class IsHandledHandler extends AbstractHandler
{
private boolean handled;
public boolean isHandled()
{
return handled;
}
@Override
public void handle(String s, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
this.handled = true;
}
public void reset()
{
handled = false;
}
}
private static final class ContextPathHandler extends AbstractHandler
{
@Override
public void handle(String s, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
response.setStatus(200);
response.setContentType("text/plain; charset=utf-8");
response.setHeader("Connection","close");
PrintWriter writer = response.getWriter();
writer.println("ctx='"+request.getContextPath()+"'");
}
}
}