diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 98c35f63e54..09d2deea18e 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -2306,13 +2306,6 @@ Spring Boot includes support for embedded Tomcat, Jetty, and Undertow servers. M developers will simply use the appropriate '`Starter`' to obtain a fully configured instance. By default the embedded server will listen for HTTP requests on port `8080`. -WARNING: If you choose to use Tomcat on CentOS be aware that, by default, a temporary -directory is used to store compiled JSPs, file uploads etc. This directory may be -deleted by `tmpwatch` while your application is running leading to failures. To avoid -this, you may want to customize your `tmpwatch` configuration so that `tomcat.*` -directories are not deleted, or configure `server.tomcat.basedir` so that embedded Tomcat -uses a different location. - [[boot-features-embedded-container-servlets-filters-listeners]] diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java index 18c1acd71f4..40fa8a61c40 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java @@ -206,6 +206,12 @@ public class TomcatEmbeddedServletContainerFactory catch (NoSuchMethodError ex) { // Tomcat is < 8.0.30. Continue } + try { + context.setCreateUploadTargets(true); + } + catch (NoSuchMethodError ex) { + // Tomcat is < 8.5.39. Continue. + } SkipPatternJarScanner.apply(context, this.tldSkipPatterns); WebappLoader loader = new WebappLoader(context.getParentClassLoader()); loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName()); diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java index c65253735d5..a2e5b6ce85c 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.context.embedded.tomcat; import java.io.File; import java.io.IOException; +import java.net.URISyntaxException; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Locale; @@ -30,10 +31,15 @@ import javax.naming.NamingException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; +import javax.servlet.MultipartConfigElement; import javax.servlet.ServletContext; import javax.servlet.ServletException; +import javax.servlet.ServletRegistration.Dynamic; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Container; import org.apache.catalina.Context; @@ -63,8 +69,18 @@ import org.springframework.boot.context.embedded.EmbeddedServletContainerExcepti import org.springframework.boot.context.embedded.Ssl; import org.springframework.boot.testutil.InternalOutputCapture; import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.util.FileSystemUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.util.SocketUtils; +import org.springframework.web.client.RestTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; @@ -539,6 +555,49 @@ public class TomcatEmbeddedServletContainerFactoryTests } } + @Test + public void nonExistentUploadDirectoryIsCreatedUponMultipartUpload() + throws IOException, URISyntaxException { + TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory( + 0); + AtomicReference servletContextReference = new AtomicReference<>(); + factory.addInitializers(new ServletContextInitializer() { + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + servletContextReference.set(servletContext); + Dynamic servlet = servletContext.addServlet("upload", new HttpServlet() { + + @Override + protected void doPost(HttpServletRequest req, + HttpServletResponse resp) + throws ServletException, IOException { + req.getParts(); + } + + }); + servlet.addMapping("/upload"); + servlet.setMultipartConfig(new MultipartConfigElement((String) null)); + } + + }); + this.container = factory.getEmbeddedServletContainer(); + this.container.start(); + File temp = (File) servletContextReference.get() + .getAttribute(ServletContext.TEMPDIR); + FileSystemUtils.deleteRecursively(temp); + RestTemplate restTemplate = new RestTemplate(); + HttpHeaders headers = new HttpHeaders(); + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("file", new ByteArrayResource(new byte[1024 * 1024])); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + HttpEntity> requestEntity = new HttpEntity<>(body, + headers); + ResponseEntity response = restTemplate + .postForEntity(getLocalUrl("/upload"), requestEntity, String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + } + @Override protected JspServlet getJspServlet() throws ServletException { Container context = ((TomcatEmbeddedServletContainer) this.container).getTomcat()