From ae83379f14693faf3f1f9f673e0d37496d54b69a Mon Sep 17 00:00:00 2001 From: Andrea Ceccanti Date: Thu, 1 Oct 2020 17:44:23 +0200 Subject: [PATCH] Workaround for Spring Boot HEAD error handling bug Due to this Spring Boot issue: https://github.com/spring-projects/spring-boot/issues/23551 StoRM WebDAV was returning body for head requests that resulted in error. Until Spring Boot 2.2.11 is released here there's a workaround (that basically incorporates the upstream code fix here). --- .../webdav/server/JettyWebServerFactory.java | 42 +++++++++++++++---- .../server/util/JettyErrorPageHandler.java | 33 +++++++++++++++ 2 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/italiangrid/storm/webdav/server/util/JettyErrorPageHandler.java diff --git a/src/main/java/org/italiangrid/storm/webdav/server/JettyWebServerFactory.java b/src/main/java/org/italiangrid/storm/webdav/server/JettyWebServerFactory.java index 3be952e8..28e298d4 100644 --- a/src/main/java/org/italiangrid/storm/webdav/server/JettyWebServerFactory.java +++ b/src/main/java/org/italiangrid/storm/webdav/server/JettyWebServerFactory.java @@ -16,6 +16,7 @@ package org.italiangrid.storm.webdav.server; import static com.google.common.base.Strings.isNullOrEmpty; +import static com.google.common.collect.Lists.newArrayList; import java.io.File; import java.io.IOException; @@ -23,7 +24,9 @@ import java.nio.file.Paths; import java.security.KeyStoreException; import java.security.cert.CertificateException; +import java.util.Arrays; import java.util.Collection; +import java.util.List; import javax.annotation.PostConstruct; @@ -36,11 +39,14 @@ import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.servlet.ErrorPageErrorHandler; import org.eclipse.jetty.util.thread.ThreadPool; +import org.eclipse.jetty.webapp.AbstractConfiguration; +import org.eclipse.jetty.webapp.Configuration; import org.eclipse.jetty.webapp.WebAppContext; import org.italiangrid.storm.webdav.config.ConfigurationLogger; import org.italiangrid.storm.webdav.config.ServiceConfiguration; import org.italiangrid.storm.webdav.config.StorageAreaConfiguration; import org.italiangrid.storm.webdav.error.StoRMWebDAVError; +import org.italiangrid.storm.webdav.server.util.JettyErrorPageHandler; import org.italiangrid.utils.jetty.TLSServerConnectorBuilder; import org.italiangrid.utils.jetty.ThreadPoolBuilder; import org.slf4j.Logger; @@ -50,6 +56,7 @@ import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.server.ErrorPage; +import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.stereotype.Component; import com.codahale.metrics.MetricRegistry; @@ -88,7 +95,7 @@ public class JettyWebServerFactory extends JettyServletWebServerFactory private void configureTLSConnector(Server server) throws KeyStoreException, CertificateException, IOException { - + TLSServerConnectorBuilder connectorBuilder = TLSServerConnectorBuilder.instance(server, certChainValidator); @@ -227,13 +234,6 @@ private void addJettyErrorPages(ErrorHandler errorHandler, Collection @Override protected void postProcessWebAppContext(WebAppContext context) { context.setCompactPath(true); - - ErrorPageErrorHandler eh = new ErrorPageErrorHandler(); - - eh.setShowStacks(false); - addJettyErrorPages(eh, getErrorPages()); - context.setErrorHandler(eh); - } @Override @@ -252,10 +252,36 @@ public void customize(Server server) { server.setDumpBeforeStop(false); server.setStopAtShutdown(true); + } + + @Override + protected Configuration[] getWebAppContextConfigurations(WebAppContext webAppContext, + ServletContextInitializer... initializers) { + + List configurations = newArrayList( + Arrays.asList(super.getWebAppContextConfigurations(webAppContext, initializers))); + configurations.add(getStormErrorPageConfiguration()); + return configurations.toArray(new Configuration[0]); } + + private Configuration getStormErrorPageConfiguration() { + return new AbstractConfiguration() { + + @Override + public void configure(WebAppContext context) throws Exception { + JettyErrorPageHandler errorHandler = new JettyErrorPageHandler(); + context.setErrorHandler(errorHandler); + addJettyErrorPages(errorHandler, getErrorPages()); + errorHandler.setShowStacks(false); + } + + }; + } + + @PostConstruct protected void after() { confLogger.logConfiguration(LOG); diff --git a/src/main/java/org/italiangrid/storm/webdav/server/util/JettyErrorPageHandler.java b/src/main/java/org/italiangrid/storm/webdav/server/util/JettyErrorPageHandler.java new file mode 100644 index 00000000..f84098c0 --- /dev/null +++ b/src/main/java/org/italiangrid/storm/webdav/server/util/JettyErrorPageHandler.java @@ -0,0 +1,33 @@ +package org.italiangrid.storm.webdav.server.util; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.servlet.ErrorPageErrorHandler; + +public class JettyErrorPageHandler extends ErrorPageErrorHandler { + + private static final Set HANDLED_HTTP_METHODS = + new HashSet<>(Arrays.asList("GET", "POST", "HEAD")); + + @Override + public boolean errorPageForMethod(String method) { + return true; + } + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, + HttpServletResponse response) throws IOException { + if (!HANDLED_HTTP_METHODS.contains(baseRequest.getMethod())) { + baseRequest.setMethod("GET"); + } + super.doError(target, baseRequest, request, response); + } + +}