diff --git a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/JettyServletEngineAdapter.java b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/JettyServletEngineAdapter.java index a40cf4f7..95c4ae12 100644 --- a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/JettyServletEngineAdapter.java +++ b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/JettyServletEngineAdapter.java @@ -35,6 +35,8 @@ import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.VirtualThreads; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.resource.ResourceFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import java.io.File; @@ -104,12 +106,21 @@ public void start(String serverInfo, ServletEngineAdapter.Config runtimeOptions) threadPool.setVirtualThreadsExecutor(VirtualThreads.getDefaultVirtualThreadsExecutor()); logger.atInfo().log("Configuring Appengine web server virtual threads."); } + + // The server.getDefaultStyleSheet() returns is returning null because of some classloading issue, + // so we get the StyleSheet here to ensure it returns the correct value. + Resource styleSheet = ResourceFactory.root().newResource(getClass().getClassLoader().getResource("jetty-dir.css")); server = new Server(threadPool) { @Override public InvocationType getInvocationType() { return InvocationType.BLOCKING; } + + @Override + public Resource getDefaultStyleSheet() { + return styleSheet; + } }; rpcConnector = new DelegateConnector(server, "RPC") { diff --git a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee10/AppEngineWebAppContext.java b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee10/AppEngineWebAppContext.java index ed78169f..7da590cd 100644 --- a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee10/AppEngineWebAppContext.java +++ b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee10/AppEngineWebAppContext.java @@ -16,9 +16,6 @@ package com.google.apphosting.runtime.jetty.ee10; -import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR; -import static java.nio.charset.StandardCharsets.UTF_8; - import com.google.apphosting.api.ApiProxy; import com.google.apphosting.api.ApiProxy.LogRecord; import com.google.apphosting.runtime.jetty.EE10AppEngineAuthentication; @@ -31,21 +28,6 @@ import jakarta.servlet.DispatcherType; import jakarta.servlet.Filter; import jakarta.servlet.Servlet; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.EventListener; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Objects; -import java.util.Scanner; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.jetty.ee10.servlet.FilterHolder; import org.eclipse.jetty.ee10.servlet.FilterMapping; import org.eclipse.jetty.ee10.servlet.Holder; @@ -63,6 +45,25 @@ import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceFactory; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.EventListener; +import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Objects; +import java.util.Scanner; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; + +import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * {@code AppEngineWebAppContext} is a customization of Jetty's {@link WebAppContext} that is aware * of the {@link ApiProxy} and can provide custom logging and authentication. @@ -235,52 +236,59 @@ public void doStart() throws Exception { @Override protected void startContext() throws Exception { - // startWebapp is called after the web.xml metadata has been resolved, so we can - // clean configuration here: - // - Removed deprecated filters and servlets - // - Ensure known runtime filters/servlets are instantiated from this classloader - // - Ensure known runtime mappings exist. - ServletHandler servletHandler = getServletHandler(); - TrimmedFilters trimmedFilters = - new TrimmedFilters( - servletHandler.getFilters(), - servletHandler.getFilterMappings(), - DEPRECATED_SERVLETS_FILTERS); - trimmedFilters.ensure( - "CloudSqlConnectionCleanupFilter", JdbcMySqlConnectionCleanupFilter.class, "/*"); - - TrimmedServlets trimmedServlets = - new TrimmedServlets( - servletHandler.getServlets(), - servletHandler.getServletMappings(), - DEPRECATED_SERVLETS_FILTERS); - trimmedServlets.ensure("_ah_warmup", WarmupServlet.class, "/_ah/warmup"); - trimmedServlets.ensure( - "_ah_sessioncleanup", SessionCleanupServlet.class, "/_ah/sessioncleanup"); - trimmedServlets.ensure( - "_ah_queue_deferred", DeferredTaskServlet.class, "/_ah/queue/__deferred__"); - trimmedServlets.ensure("_ah_snapshot", SnapshotServlet.class, "/_ah/snapshot"); - trimmedServlets.ensure("_ah_default", ResourceFileServlet.class, "/"); - trimmedServlets.ensure("default", NamedDefaultServlet.class); - trimmedServlets.ensure("jsp", NamedJspServlet.class); - - trimmedServlets.instantiateJettyServlets(); - trimmedFilters.instantiateJettyFilters(); - instantiateJettyListeners(); - - servletHandler.setFilters(trimmedFilters.getHolders()); - servletHandler.setFilterMappings(trimmedFilters.getMappings()); - servletHandler.setServlets(trimmedServlets.getHolders()); - servletHandler.setServletMappings(trimmedServlets.getMappings()); - servletHandler.setAllowDuplicateMappings(true); - - // Protect deferred task queue with constraint - ConstraintSecurityHandler security = (ConstraintSecurityHandler) getSecurityHandler(); - ConstraintMapping cm = new ConstraintMapping(); - cm.setConstraint( - Constraint.from("deferred_queue", Constraint.Authorization.SPECIFIC_ROLE, "admin")); - cm.setPathSpec("/_ah/queue/__deferred__"); - security.addConstraintMapping(cm); + ServletHandler servletHandler = getServletHandler(); + getServletHandler().addListener(new ListenerHolder() { + @Override + public void doStart() throws Exception { + // This Listener doStart is called after the web.xml metadata has been resolved, so we can + // clean configuration here: + // - Removed deprecated filters and servlets + // - Ensure known runtime filters/servlets are instantiated from this classloader + // - Ensure known runtime mappings exist. + setListener(new EventListener() {}); + + TrimmedFilters trimmedFilters = + new TrimmedFilters( + servletHandler.getFilters(), + servletHandler.getFilterMappings(), + DEPRECATED_SERVLETS_FILTERS); + trimmedFilters.ensure( + "CloudSqlConnectionCleanupFilter", JdbcMySqlConnectionCleanupFilter.class, "/*"); + + TrimmedServlets trimmedServlets = + new TrimmedServlets( + servletHandler.getServlets(), + servletHandler.getServletMappings(), + DEPRECATED_SERVLETS_FILTERS); + trimmedServlets.ensure("_ah_warmup", WarmupServlet.class, "/_ah/warmup"); + trimmedServlets.ensure( + "_ah_sessioncleanup", SessionCleanupServlet.class, "/_ah/sessioncleanup"); + trimmedServlets.ensure( + "_ah_queue_deferred", DeferredTaskServlet.class, "/_ah/queue/__deferred__"); + trimmedServlets.ensure("_ah_snapshot", SnapshotServlet.class, "/_ah/snapshot"); + trimmedServlets.ensure("_ah_default", ResourceFileServlet.class, "/"); + trimmedServlets.ensure("default", NamedDefaultServlet.class); + trimmedServlets.ensure("jsp", NamedJspServlet.class); + + trimmedServlets.instantiateJettyServlets(); + trimmedFilters.instantiateJettyFilters(); + instantiateJettyListeners(); + + servletHandler.setFilters(trimmedFilters.getHolders()); + servletHandler.setFilterMappings(trimmedFilters.getMappings()); + servletHandler.setServlets(trimmedServlets.getHolders()); + servletHandler.setServletMappings(trimmedServlets.getMappings()); + servletHandler.setAllowDuplicateMappings(true); + + // Protect deferred task queue with constraint + ConstraintSecurityHandler security = (ConstraintSecurityHandler) getSecurityHandler(); + ConstraintMapping cm = new ConstraintMapping(); + cm.setConstraint( + Constraint.from("deferred_queue", Constraint.Authorization.SPECIFIC_ROLE, "admin")); + cm.setPathSpec("/_ah/queue/__deferred__"); + security.addConstraintMapping(cm); + } + }); // continue starting the webapp super.startContext(); diff --git a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee8/AppEngineWebAppContext.java b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee8/AppEngineWebAppContext.java index de663ce6..3441e2e5 100644 --- a/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee8/AppEngineWebAppContext.java +++ b/runtime/runtime_impl_jetty12/src/main/java/com/google/apphosting/runtime/jetty/ee8/AppEngineWebAppContext.java @@ -16,9 +16,6 @@ package com.google.apphosting.runtime.jetty.ee8; -import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR; -import static java.nio.charset.StandardCharsets.UTF_8; - import com.google.apphosting.api.ApiProxy; import com.google.apphosting.api.ApiProxy.LogRecord; import com.google.apphosting.runtime.jetty.AppEngineAuthentication; @@ -28,6 +25,25 @@ import com.google.apphosting.utils.servlet.SnapshotServlet; import com.google.apphosting.utils.servlet.WarmupServlet; import com.google.common.collect.ImmutableSet; +import org.eclipse.jetty.ee8.nested.ServletConstraint; +import org.eclipse.jetty.ee8.security.ConstraintMapping; +import org.eclipse.jetty.ee8.security.ConstraintSecurityHandler; +import org.eclipse.jetty.ee8.servlet.FilterHolder; +import org.eclipse.jetty.ee8.servlet.FilterMapping; +import org.eclipse.jetty.ee8.servlet.Holder; +import org.eclipse.jetty.ee8.servlet.ListenerHolder; +import org.eclipse.jetty.ee8.servlet.ServletHandler; +import org.eclipse.jetty.ee8.servlet.ServletHolder; +import org.eclipse.jetty.ee8.servlet.ServletMapping; +import org.eclipse.jetty.ee8.webapp.WebAppContext; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.resource.ResourceFactory; + +import javax.servlet.Filter; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -43,24 +59,9 @@ import java.util.Scanner; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; -import javax.servlet.Filter; -import javax.servlet.Servlet; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.ee8.nested.ServletConstraint; -import org.eclipse.jetty.ee8.security.ConstraintMapping; -import org.eclipse.jetty.ee8.security.ConstraintSecurityHandler; -import org.eclipse.jetty.ee8.servlet.FilterHolder; -import org.eclipse.jetty.ee8.servlet.FilterMapping; -import org.eclipse.jetty.ee8.servlet.Holder; -import org.eclipse.jetty.ee8.servlet.ListenerHolder; -import org.eclipse.jetty.ee8.servlet.ServletHandler; -import org.eclipse.jetty.ee8.servlet.ServletHolder; -import org.eclipse.jetty.ee8.servlet.ServletMapping; -import org.eclipse.jetty.ee8.webapp.WebAppContext; -import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.util.resource.ResourceFactory; + +import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR; +import static java.nio.charset.StandardCharsets.UTF_8; /** * {@code AppEngineWebAppContext} is a customization of Jetty's {@link WebAppContext} that is aware @@ -239,53 +240,61 @@ public void doStart() throws Exception { @Override protected void startContext() throws Exception { - // startWebapp is called after the web.xml metadata has been resolved, so we can - // clean configuration here: - // - Removed deprecated filters and servlets - // - Ensure known runtime filters/servlets are instantiated from this classloader - // - Ensure known runtime mappings exist. ServletHandler servletHandler = getServletHandler(); - TrimmedFilters trimmedFilters = - new TrimmedFilters( - servletHandler.getFilters(), - servletHandler.getFilterMappings(), - DEPRECATED_SERVLETS_FILTERS); - trimmedFilters.ensure( - "CloudSqlConnectionCleanupFilter", JdbcMySqlConnectionCleanupFilter.class, "/*"); - - TrimmedServlets trimmedServlets = - new TrimmedServlets( - servletHandler.getServlets(), - servletHandler.getServletMappings(), - DEPRECATED_SERVLETS_FILTERS); - trimmedServlets.ensure("_ah_warmup", WarmupServlet.class, "/_ah/warmup"); - trimmedServlets.ensure( - "_ah_sessioncleanup", SessionCleanupServlet.class, "/_ah/sessioncleanup"); - trimmedServlets.ensure( - "_ah_queue_deferred", DeferredTaskServlet.class, "/_ah/queue/__deferred__"); - trimmedServlets.ensure("_ah_snapshot", SnapshotServlet.class, "/_ah/snapshot"); - trimmedServlets.ensure("_ah_default", ResourceFileServlet.class, "/"); - trimmedServlets.ensure("default", NamedDefaultServlet.class); - trimmedServlets.ensure("jsp", NamedJspServlet.class); - - trimmedServlets.instantiateJettyServlets(); - trimmedFilters.instantiateJettyFilters(); - instantiateJettyListeners(); - - servletHandler.setFilters(trimmedFilters.getHolders()); - servletHandler.setFilterMappings(trimmedFilters.getMappings()); - servletHandler.setServlets(trimmedServlets.getHolders()); - servletHandler.setServletMappings(trimmedServlets.getMappings()); - servletHandler.setAllowDuplicateMappings(true); - - // Protect deferred task queue with constraint - ConstraintSecurityHandler security = getChildHandlerByClass(ConstraintSecurityHandler.class); - ConstraintMapping cm = new ConstraintMapping(); - cm.setConstraint(new ServletConstraint("deferred_queue", "admin")); - cm.setPathSpec("/_ah/queue/__deferred__"); - security.addConstraintMapping(cm); - - // continue starting the webapp + getServletHandler().addListener(new ListenerHolder() { + @Override + public void doStart() throws Exception { + + // This Listener doStart is called after the web.xml metadata has been resolved, so we can + // clean configuration here: + // - Removed deprecated filters and servlets + // - Ensure known runtime filters/servlets are instantiated from this classloader + // - Ensure known runtime mappings exist. + setListener(new EventListener() {}); + + TrimmedFilters trimmedFilters = + new TrimmedFilters( + servletHandler.getFilters(), + servletHandler.getFilterMappings(), + DEPRECATED_SERVLETS_FILTERS); + trimmedFilters.ensure( + "CloudSqlConnectionCleanupFilter", JdbcMySqlConnectionCleanupFilter.class, "/*"); + + TrimmedServlets trimmedServlets = + new TrimmedServlets( + servletHandler.getServlets(), + servletHandler.getServletMappings(), + DEPRECATED_SERVLETS_FILTERS); + trimmedServlets.ensure("_ah_warmup", WarmupServlet.class, "/_ah/warmup"); + trimmedServlets.ensure( + "_ah_sessioncleanup", SessionCleanupServlet.class, "/_ah/sessioncleanup"); + trimmedServlets.ensure( + "_ah_queue_deferred", DeferredTaskServlet.class, "/_ah/queue/__deferred__"); + trimmedServlets.ensure("_ah_snapshot", SnapshotServlet.class, "/_ah/snapshot"); + trimmedServlets.ensure("_ah_default", ResourceFileServlet.class, "/"); + trimmedServlets.ensure("default", NamedDefaultServlet.class); + trimmedServlets.ensure("jsp", NamedJspServlet.class); + + trimmedServlets.instantiateJettyServlets(); + trimmedFilters.instantiateJettyFilters(); + instantiateJettyListeners(); + + servletHandler.setFilters(trimmedFilters.getHolders()); + servletHandler.setFilterMappings(trimmedFilters.getMappings()); + servletHandler.setServlets(trimmedServlets.getHolders()); + servletHandler.setServletMappings(trimmedServlets.getMappings()); + servletHandler.setAllowDuplicateMappings(true); + + // Protect deferred task queue with constraint + ConstraintSecurityHandler security = getChildHandlerByClass(ConstraintSecurityHandler.class); + ConstraintMapping cm = new ConstraintMapping(); + cm.setConstraint(new ServletConstraint("deferred_queue", "admin")); + cm.setPathSpec("/_ah/queue/__deferred__"); + security.addConstraintMapping(cm); + } + }); + + // continue starting the webapp super.startContext(); }