/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.core;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.FilterChain;
import javax.servlet.GenericFilter;
import javax.servlet.HttpConstraintElement;
import javax.servlet.HttpMethodConstraintElement;
import javax.servlet.MultipartConfigElement;
import javax.servlet.Servlet;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletSecurityElement;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hamcrest.CoreMatchers;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Assert;
import org.junit.Test;
import org.apache.catalina.Context;
import org.apache.catalina.Host;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Wrapper;
import org.apache.catalina.authenticator.BasicAuthenticator;
import org.apache.catalina.loader.WebappLoader;
import org.apache.catalina.startup.SimpleHttpClient;
import org.apache.catalina.startup.TesterMapRealm;
import org.apache.catalina.startup.TesterServlet;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.jasper.servlet.JasperInitializer;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.apache.tomcat.util.descriptor.web.LoginConfig;
public class TestStandardContext extends TomcatBaseTest {
private static final String REQUEST =
"GET / HTTP/1.1\r\n" +
"Host: anything\r\n" +
"Connection: close\r\n" +
"\r\n";
@Test
public void testBug46243() throws Exception {
// This tests that if a Filter init() fails then the web application
// is not put into service. (BZ 46243)
// This also tests that if the cause of the failure is gone,
// the context can be started without a need to redeploy it.
// Set up a container
Tomcat tomcat = getTomcatInstance();
File docBase = new File(tomcat.getHost().getAppBaseFile(), "ROOT");
if (!docBase.mkdirs() && !docBase.isDirectory()) {
fail("Unable to create docBase");
}
Context root = tomcat.addContext("", "ROOT");
configureTest46243Context(root, true);
tomcat.start();
// Configure the client
Bug46243Client client =
new Bug46243Client(tomcat.getConnector().getLocalPort());
client.setRequest(new String[] { REQUEST });
client.connect();
client.processRequest();
assertTrue(client.isResponse404());
// Context failed to start. This checks that automatic transition
// from FAILED to STOPPED state was successful.
assertEquals(LifecycleState.STOPPED, root.getState());
// Prepare context for the second attempt
// Configuration was cleared on stop() thanks to
// StandardContext.resetContext(), so we need to configure it again
// from scratch.
configureTest46243Context(root, false);
root.start();
// The same request is processed successfully
client.connect();
client.processRequest();
assertTrue(client.isResponse200());
assertEquals(Bug46243Filter.class.getName()
+ HelloWorldServlet.RESPONSE_TEXT, client.getResponseBody());
}
private static void configureTest46243Context(Context context, boolean fail) {
// Add a test filter that fails
FilterDef filterDef = new FilterDef();
filterDef.setFilterClass(Bug46243Filter.class.getName());
filterDef.setFilterName("Bug46243");
filterDef.addInitParameter("fail", Boolean.toString(fail));
context.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap();
filterMap.setFilterName("Bug46243");
filterMap.addURLPatternDecoded("*");
context.addFilterMap(filterMap);
// Add a test servlet so there is something to generate a response if
// it works (although it shouldn't)
Tomcat.addServlet(context, "Bug46243", new HelloWorldServlet());
context.addServletMappingDecoded("/", "Bug46243");
}
private static final class Bug46243Client extends SimpleHttpClient {
public Bug46243Client(int port) {
setPort(port);
}
@Override
public boolean isResponseBodyOK() {
// Don't care about the body in this test
return true;
}
}
public static final class Bug46243Filter extends GenericFilter {
private static final long serialVersionUID = 1L;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
PrintWriter out = response.getWriter();
out.print(getClass().getName());
chain.doFilter(request, response);
}
@Override
public void init() throws ServletException {
boolean fail = getInitParameter("fail").equals("true");
if (fail) {
throw new ServletException("Init fail (test)", new ClassNotFoundException());
}
}
}
@Test
public void testWebappLoaderStartFail() throws Exception {
// Test that if WebappLoader start() fails and if the cause of
// the failure is gone, the context can be started without
// a need to redeploy it.
// Set up a container
Tomcat tomcat = getTomcatInstance();
tomcat.start();
// To not start Context automatically, as we have to configure it first
((ContainerBase) tomcat.getHost()).setStartChildren(false);
FailingWebappLoader loader = new FailingWebappLoader();
File root = new File("test/webapp");
Context context = tomcat.addWebapp("", root.getAbsolutePath());
context.setLoader(loader);
try {
context.start();
fail();
} catch (LifecycleException ex) {
// As expected
}
assertEquals(LifecycleState.FAILED, context.getState());
// The second attempt
loader.setFail(false);
context.start();
assertEquals(LifecycleState.STARTED, context.getState());
// Using a test from testBug49922() to check that the webapp is running
ByteChunk result = getUrl("http://localhost:" + getPort() +
"/bug49922/target");
assertEquals("Target", result.toString());
}
@Test
public void testWebappListenerConfigureFail() throws Exception {
// Test that if LifecycleListener on webapp fails during
// configure_start event and if the cause of the failure is gone,
// the context can be started without a need to redeploy it.
// Set up a container
Tomcat tomcat = getTomcatInstance();
tomcat.start();
// To not start Context automatically, as we have to configure it first
((ContainerBase) tomcat.getHost()).setStartChildren(false);
FailingLifecycleListener listener = new FailingLifecycleListener();
File root = new File("test/webapp");
Context context = tomcat.addWebapp("", root.getAbsolutePath());
context.addLifecycleListener(listener);
try {
context.start();
fail();
} catch (LifecycleException ex) {
// As expected
}
assertEquals(LifecycleState.FAILED, context.getState());
// The second attempt
listener.setFail(false);
context.start();
assertEquals(LifecycleState.STARTED, context.getState());
// Using a test from testBug49922() to check that the webapp is running
ByteChunk result = getUrl("http://localhost:" + getPort() +
"/bug49922/target");
assertEquals("Target", result.toString());
}
private static class FailingWebappLoader extends WebappLoader {
private boolean fail = true;
protected void setFail(boolean fail) {
this.fail = fail;
}
@Override
protected void startInternal() throws LifecycleException {
if (fail) {
throw new RuntimeException("Start fail (test)");
}
super.startInternal();
}
}
private static class FailingLifecycleListener implements LifecycleListener {
private final String failEvent = Lifecycle.CONFIGURE_START_EVENT;
private boolean fail = true;
protected void setFail(boolean fail) {
this.fail = fail;
}
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (fail && event.getType().equals(failEvent)) {
throw new RuntimeException(failEvent + " fail (test)");
}
}
}
@Test
public void testBug49922() throws Exception {
// Test that filter mapping works. Test that the same filter is
// called only once, even if is selected by several mapping
// url-patterns or by both a url-pattern and a servlet-name.
getTomcatInstanceTestWebapp(false, true);
ByteChunk result = new ByteChunk();
// Check filter and servlet aren't called
int rc = getUrl("http://localhost:" + getPort() +
"/test/bug49922/foo", result, null);
assertEquals(HttpServletResponse.SC_NOT_FOUND, rc);
assertTrue(result.getLength() > 0);
// Check extension mapping works
result = getUrl("http://localhost:" + getPort() + "/test/foo.do");
assertEquals("FilterServlet", result.toString());
// Check path mapping works
result = getUrl("http://localhost:" + getPort() + "/test/bug49922/servlet");
assertEquals("FilterServlet", result.toString());
// Check servlet name mapping works
result = getUrl("http://localhost:" + getPort() + "/test/foo.od");
assertEquals("FilterServlet", result.toString());
// Check filter is only called once
result = getUrl("http://localhost:" + getPort() +
"/test/bug49922/servlet/foo.do");
assertEquals("FilterServlet", result.toString());
result = getUrl("http://localhost:" + getPort() +
"/test/bug49922/servlet/foo.od");
assertEquals("FilterServlet", result.toString());
// Check dispatcher mapping
result = getUrl("http://localhost:" + getPort() +
"/test/bug49922/target");
assertEquals("Target", result.toString());
result = getUrl("http://localhost:" + getPort() +
"/test/bug49922/forward");
assertEquals("FilterTarget", result.toString());
result = getUrl("http://localhost:" + getPort() +
"/test/bug49922/include");
assertEquals("IncludeFilterTarget", result.toString());
}
public static final class Bug49922Filter extends GenericFilter {
private static final long serialVersionUID = 1L;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
response.setContentType("text/plain");
response.getWriter().print("Filter");
chain.doFilter(request, response);
}
}
public static final class Bug49922ForwardServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.getRequestDispatcher("/bug49922/target").forward(req, resp);
}
}
public static final class Bug49922IncludeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/plain");
resp.getWriter().print("Include");
req.getRequestDispatcher("/bug49922/target").include(req, resp);
}
}
public static final class Bug49922TargetServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/plain");
resp.getWriter().print("Target");
}
}
public static final class Bug49922Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/plain");
resp.getWriter().print("Servlet");
}
}
@Test
public void testBug50015() throws Exception {
// Test that configuring servlet security constraints programmatically
// does work.
// Set up a container
Tomcat tomcat = getTomcatInstance();
// No file system docBase required
Context ctx = tomcat.addContext("", null);
// Setup realm
TesterMapRealm realm = new TesterMapRealm();
realm.addUser("tomcat", "tomcat");
realm.addUserRole("tomcat", "tomcat");
ctx.setRealm(realm);
// Configure app for BASIC auth
LoginConfig lc = new LoginConfig();
lc.setAuthMethod("BASIC");
ctx.setLoginConfig(lc);
ctx.getPipeline().addValve(new BasicAuthenticator());
// Add ServletContainerInitializer
ServletContainerInitializer sci = new Bug50015SCI();
ctx.addServletContainerInitializer(sci, null);
// Start the context
tomcat.start();
// Request the first servlet
ByteChunk bc = new ByteChunk();
int rc = getUrl("http://localhost:" + getPort() + "/bug50015",
bc, null);
// Check for a 401
assertNotSame("OK", bc.toString());
assertEquals(401, rc);
}
public static final class Bug50015SCI
implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx)
throws ServletException {
// Register and map servlet
Servlet s = new TesterServlet();
ServletRegistration.Dynamic sr = ctx.addServlet("bug50015", s);
sr.addMapping("/bug50015");
// Limit access to users in the Tomcat role
HttpConstraintElement hce = new HttpConstraintElement(
TransportGuarantee.NONE, "tomcat");
ServletSecurityElement sse = new ServletSecurityElement(hce);
sr.setServletSecurity(sse);
}
}
@Test
public void testDenyUncoveredHttpMethodsSCITrue() throws Exception {
doTestDenyUncoveredHttpMethodsSCI(true);
}
@Test
public void testDenyUncoveredHttpMethodsSCIFalse() throws Exception {
doTestDenyUncoveredHttpMethodsSCI(false);
}
private void doTestDenyUncoveredHttpMethodsSCI(boolean enableDeny)
throws Exception {
// Test that denying uncovered HTTP methods when adding servlet security
// constraints programmatically does work.
// Set up a container
Tomcat tomcat = getTomcatInstance();
// No file system docBase required
Context ctx = tomcat.addContext("", null);
ctx.setDenyUncoveredHttpMethods(enableDeny);
// Setup realm
TesterMapRealm realm = new TesterMapRealm();
realm.addUser("tomcat", "tomcat");
realm.addUserRole("tomcat", "tomcat");
ctx.setRealm(realm);
// Configure app for BASIC auth
LoginConfig lc = new LoginConfig();
lc.setAuthMethod("BASIC");
ctx.setLoginConfig(lc);
ctx.getPipeline().addValve(new BasicAuthenticator());
// Add ServletContainerInitializer
ServletContainerInitializer sci = new DenyUncoveredHttpMethodsSCI();
ctx.addServletContainerInitializer(sci, null);
// Start the context
tomcat.start();
// Request the first servlet
ByteChunk bc = new ByteChunk();
int rc = getUrl("http://localhost:" + getPort() + "/test",
bc, null);
// Check for a 401
if (enableDeny) {
// Should be default error page
Assert.assertTrue(bc.toString().contains("403"));
Assert.assertEquals(403, rc);
} else {
Assert.assertEquals("OK", bc.toString());
Assert.assertEquals(200, rc);
}
}
public static final class DenyUncoveredHttpMethodsSCI
implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx)
throws ServletException {
// Register and map servlet
Servlet s = new TesterServlet();
ServletRegistration.Dynamic sr = ctx.addServlet("test", s);
sr.addMapping("/test");
// Add a constraint with uncovered methods
HttpConstraintElement hce = new HttpConstraintElement(
TransportGuarantee.NONE, "tomcat");
HttpMethodConstraintElement hmce =
new HttpMethodConstraintElement("POST", hce);
Set<HttpMethodConstraintElement> hmces = new HashSet<>();
hmces.add(hmce);
ServletSecurityElement sse = new ServletSecurityElement(hmces);
sr.setServletSecurity(sse);
}
}
@Test
public void testBug51376a() throws Exception {
doTestBug51376(false);
}
@Test
public void testBug51376b() throws Exception {
doTestBug51376(true);
}
private void doTestBug51376(boolean loadOnStartUp) throws Exception {
// Test that for a servlet that was added programmatically its
// loadOnStartup property is honored and its init() and destroy()
// methods are called.
// Set up a container
Tomcat tomcat = getTomcatInstance();
// No file system docBase required
Context ctx = tomcat.addContext("", null);
// Add ServletContainerInitializer
Bug51376SCI sci = new Bug51376SCI(loadOnStartUp);
ctx.addServletContainerInitializer(sci, null);
// Start the context
tomcat.start();
// Stop the context
ctx.stop();
// Make sure that init() and destroy() were called correctly
assertTrue(sci.getServlet().isOk());
assertTrue(loadOnStartUp == sci.getServlet().isInitCalled());
}
public static final class Bug51376SCI
implements ServletContainerInitializer {
private Bug51376Servlet s = null;
private boolean loadOnStartUp;
public Bug51376SCI(boolean loadOnStartUp) {
this.loadOnStartUp = loadOnStartUp;
}
private Bug51376Servlet getServlet() {
return s;
}
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx)
throws ServletException {
// Register and map servlet
s = new Bug51376Servlet();
ServletRegistration.Dynamic sr = ctx.addServlet("bug51376", s);
sr.addMapping("/bug51376");
if (loadOnStartUp) {
sr.setLoadOnStartup(1);
}
}
}
public static final class Bug51376Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private Boolean initOk = null;
private Boolean destroyOk = null;
@Override
public void init() {
if (initOk == null && destroyOk == null) {
initOk = Boolean.TRUE;
} else {
initOk = Boolean.FALSE;
}
}
@Override
public void destroy() {
if (initOk.booleanValue() && destroyOk == null) {
destroyOk = Boolean.TRUE;
} else {
destroyOk = Boolean.FALSE;
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/plain");
resp.getWriter().write("OK");
}
protected boolean isOk() {
if (initOk != null && initOk.booleanValue() && destroyOk != null &&
destroyOk.booleanValue()) {
return true;
} else if (initOk == null && destroyOk == null) {
return true;
} else {
return false;
}
}
protected boolean isInitCalled() {
return initOk != null && initOk.booleanValue();
}
}
/**
* Test case for bug 49711: HttpServletRequest.getParts does not work
* in a filter.
*/
@Test
public void testBug49711() {
Bug49711Client client = new Bug49711Client();
// Make sure non-multipart works properly
client.doRequest("/regular", false, false);
// Servlet attempts to read parts which will trigger an ISE
assertTrue(client.isResponse500());
client.reset();
// Make sure regular multipart works properly
client.doRequest("/multipart", false, true); // send multipart request
assertEquals("Regular multipart doesn't work",
"parts=1",
client.getResponseBody());
client.reset();
// Make casual multipart request to "regular" servlet w/o config
// We expect an error
client.doRequest("/regular", false, true); // send multipart request
// Servlet attempts to read parts which will trigger an ISE
assertTrue(client.isResponse500());
client.reset();
// Make casual multipart request to "regular" servlet w/config
// We expect that the server /will/ parse the parts, even though
// there is no @MultipartConfig
client.doRequest("/regular", true, true); // send multipart request
assertEquals("Incorrect response for configured casual multipart request",
"parts=1",
client.getResponseBody());
client.reset();
}
private static class Bug49711Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Just echo the parameters and values back as plain text
resp.setContentType("text/plain");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
out.println("parts=" + (null == req.getParts()
? "null"
: Integer.valueOf(req.getParts().size())));
}
}
@MultipartConfig
private static class Bug49711Servlet_multipart extends Bug49711Servlet {
private static final long serialVersionUID = 1L;
}
/**
* Bug 49711 test client: test for casual getParts calls.
*/
private class Bug49711Client extends SimpleHttpClient {
private boolean init;
private Context context;
private synchronized void init() throws Exception {
if (init) return;
Tomcat tomcat = getTomcatInstance();
context = tomcat.addContext("", TEMP_DIR);
Tomcat.addServlet(context, "regular", new Bug49711Servlet());
Wrapper w = Tomcat.addServlet(context, "multipart", new Bug49711Servlet_multipart());
// Tomcat.addServlet does not respect annotations, so we have
// to set our own MultipartConfigElement.
w.setMultipartConfigElement(new MultipartConfigElement(""));
context.addServletMappingDecoded("/regular", "regular");
context.addServletMappingDecoded("/multipart", "multipart");
tomcat.start();
setPort(tomcat.getConnector().getLocalPort());
init = true;
}
private Exception doRequest(String uri,
boolean allowCasualMultipart,
boolean makeMultipartRequest) {
try {
init();
context.setAllowCasualMultipartParsing(allowCasualMultipart);
// Open connection
connect();
// Send specified request body using method
String[] request;
if(makeMultipartRequest) {
String boundary = "--simpleboundary";
String content = "--" + boundary + CRLF
+ "Content-Disposition: form-data; name=\"name\"" + CRLF + CRLF
+ "value" + CRLF
+ "--" + boundary + "--" + CRLF;
// Re-encode the content so that bytes = characters
content = new String(content.getBytes("UTF-8"), "ASCII");
request = new String[] {
"POST http://localhost:" + getPort() + uri + " HTTP/1.1" + CRLF
+ "Host: localhost" + CRLF
+ "Connection: close" + CRLF
+ "Content-Type: multipart/form-data; boundary=" + boundary + CRLF
+ "Content-Length: " + content.length() + CRLF
+ CRLF
+ content
+ CRLF
};
}
else
{
request = new String[] {
"GET http://localhost:" + getPort() + uri + " HTTP/1.1" + CRLF
+ "Host: localhost" + CRLF
+ "Connection: close" + CRLF
+ CRLF
};
}
setRequest(request);
processRequest(); // blocks until response has been read
// Close the connection
disconnect();
} catch (Exception e) {
return e;
}
return null;
}
@Override
public boolean isResponseBodyOK() {
return false; // Don't care
}
}
@Test(expected = IllegalArgumentException.class)
public void testAddPostConstructMethodNullClassName() {
new StandardContext().addPostConstructMethod(null, "");
}
@Test(expected = IllegalArgumentException.class)
public void testAddPostConstructMethodNullMethodName() {
new StandardContext().addPostConstructMethod("", null);
}
@Test(expected = IllegalArgumentException.class)
public void testAddPostConstructMethodConflicts() {
StandardContext standardContext = new StandardContext();
standardContext.addPostConstructMethod("a", "a");
standardContext.addPostConstructMethod("a", "b");
}
@Test(expected = IllegalArgumentException.class)
public void testAddPreDestroyMethodNullClassName() {
new StandardContext().addPreDestroyMethod(null, "");
}
@Test(expected = IllegalArgumentException.class)
public void testAddPreDestroyMethodNullMethodName() {
new StandardContext().addPreDestroyMethod("", null);
}
@Test(expected = IllegalArgumentException.class)
public void testAddPreDestroyMethodConflicts() {
StandardContext standardContext = new StandardContext();
standardContext.addPreDestroyMethod("a", "a");
standardContext.addPreDestroyMethod("a", "b");
}
@Test
public void testTldListener() throws Exception {
// Set up a container
Tomcat tomcat = getTomcatInstance();
File docBase = new File("test/webapp-3.0");
Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
ctx.addServletContainerInitializer(new JasperInitializer(), null);
// Start the context
tomcat.start();
// Stop the context
ctx.stop();
String log = TesterTldListener.getLog();
Assert.assertTrue(log, log.contains("PASS-01"));
Assert.assertTrue(log, log.contains("PASS-02"));
Assert.assertFalse(log, log.contains("FAIL"));
}
@Test
public void testFlagFailCtxIfServletStartFails() throws Exception {
Tomcat tomcat = getTomcatInstance();
File docBase = new File(System.getProperty("java.io.tmpdir"));
StandardContext context = (StandardContext) tomcat.addContext("",
docBase.getAbsolutePath());
// first we test the flag itself, which can be set on the Host and
// Context
assertFalse(context.getComputedFailCtxIfServletStartFails());
StandardHost host = (StandardHost) tomcat.getHost();
host.setFailCtxIfServletStartFails(true);
assertTrue(context.getComputedFailCtxIfServletStartFails());
context.setFailCtxIfServletStartFails(Boolean.FALSE);
assertFalse("flag on Context should override Host config",
context.getComputedFailCtxIfServletStartFails());
// second, we test the actual effect of the flag on the startup
Wrapper servlet = Tomcat.addServlet(context, "myservlet",
new FailingStartupServlet());
servlet.setLoadOnStartup(1);
tomcat.start();
assertTrue("flag false should not fail deployment", context.getState()
.isAvailable());
tomcat.stop();
assertFalse(context.getState().isAvailable());
host.removeChild(context);
context = (StandardContext) tomcat.addContext("",
docBase.getAbsolutePath());
servlet = Tomcat.addServlet(context, "myservlet",
new FailingStartupServlet());
servlet.setLoadOnStartup(1);
tomcat.start();
assertFalse("flag true should fail deployment", context.getState()
.isAvailable());
}
private class FailingStartupServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void init() throws ServletException {
throw new ServletException("failing on purpose");
}
}
@Test
public void testBug56085() throws Exception {
Tomcat tomcat = getTomcatInstanceTestWebapp(false, true);
String realPath = ((Context) tomcat.getHost().findChildren()[0]).getRealPath("\\");
Assert.assertNull(realPath);
}
/*
* Check real path for directories ends with File.separator for consistency
* with previous major versions.
*/
@Test
public void testBug57556a() throws Exception {
Tomcat tomcat = getTomcatInstanceTestWebapp(false, true);
Context testContext = ((Context) tomcat.getHost().findChildren()[0]);
File f = new File(testContext.getDocBase());
if (!f.isAbsolute()) {
f = new File(((Host) testContext.getParent()).getAppBaseFile(), f.getPath());
}
String base = f.getCanonicalPath();
doTestBug57556(testContext, "", base + File.separatorChar);
doTestBug57556(testContext, "/", base + File.separatorChar);
doTestBug57556(testContext, "/jsp", base + File.separatorChar+ "jsp");
doTestBug57556(testContext, "/jsp/", base + File.separatorChar+ "jsp" + File.separatorChar);
doTestBug57556(testContext, "/index.html", base + File.separatorChar + "index.html");
doTestBug57556(testContext, "/foo", base + File.separatorChar + "foo");
doTestBug57556(testContext, "/foo/", base + File.separatorChar + "foo" + File.separatorChar);
}
@Test
public void testBug57556b() throws Exception {
Tomcat tomcat = getTomcatInstance();
File docBase = new File("/");
Context testContext = tomcat.addContext("", docBase.getAbsolutePath());
tomcat.start();
File f = new File(testContext.getDocBase());
if (!f.isAbsolute()) {
f = new File(((Host) testContext.getParent()).getAppBaseFile(), f.getPath());
}
String base = f.getCanonicalPath();
doTestBug57556(testContext, "", base);
doTestBug57556(testContext, "/", base);
}
private void doTestBug57556(Context testContext, String path, String expected) throws Exception {
String realPath = testContext.getRealPath(path);
Assert.assertNotNull(realPath);
Assert.assertEquals(expected, realPath);
}
@Test
public void testBug56903() {
Context context = new StandardContext();
context.setResourceOnlyServlets("a,b,c");
Assert.assertThat(Arrays.asList(context.getResourceOnlyServlets().split(",")),
CoreMatchers.hasItems("a", "b", "c"));
}
@Test
public void testSetPath() {
testSetPath("", "");
testSetPath("/foo", "/foo");
testSetPath("/foo/bar", "/foo/bar");
testSetPath(null, "");
testSetPath("/", "");
testSetPath("foo", "/foo");
testSetPath("/foo/bar/", "/foo/bar");
testSetPath("foo/bar/", "/foo/bar");
}
private void testSetPath(String value, String expectedValue) {
StandardContext context = new StandardContext();
context.setPath(value);
Assert.assertEquals(expectedValue, context.getPath());
}
}