Sitelet https://github.com/GoogleCloudPlatform/appengine-java-standard/pull/188/files
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.common.base.Preconditions;
import com.google.common.html.HtmlEscapers;
import com.google.common.net.HttpHeaders;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
Expand Down Expand Up @@ -728,7 +729,7 @@ public void sendError(int sc, String msg) throws IOException {
checkNotCommitted();
// This has to be re-implemented to avoid committing the response.
setStatus(sc, msg);
setErrorBody(sc + " " + HtmlEscapers.htmlEscaper().escape(msg));
setErrorBody(sc + " " + (msg == null ? "" : HtmlEscapers.htmlEscaper().escape(msg)));
}

/** Sets the response body to an HTML page with an error message.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
Expand Down Expand Up @@ -728,8 +729,8 @@ public void sendError(int sc) throws IOException {
public void sendError(int sc, String msg) throws IOException {
checkNotCommitted();
// This has to be re-implemented to avoid committing the response.
super.sendError(sc, msg);
setErrorBody(sc + " " + HtmlEscapers.htmlEscaper().escape(msg));
setStatus(sc);
setErrorBody(sc + " " + (msg == null ? "" : HtmlEscapers.htmlEscaper().escape(msg)));
}

/** Sets the response body to an HTML page with an error message.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.appengine.tools.info;

import com.google.common.base.Joiner;

import java.io.File;
import java.io.FileFilter;
import java.net.URL;
Expand Down Expand Up @@ -191,6 +192,24 @@ public List<URL> getSharedJspLibs() {
return Collections.unmodifiableList(toURLs(getSharedJspLibFiles()));
}

private File getJetty12Jar(String fileNamePattern) {
File path = new File(sdkRoot, JETTY12_HOME_LIB_PATH + File.separator);

if (!path.exists()) {
throw new IllegalArgumentException("Unable to find " + path.getAbsolutePath());
}
for (File f : listFiles(path)) {
if (f.getName().endsWith(".jar")) {
// All but CDI jar. All the tests are still passing without CDI that should not be exposed
// in our runtime (private Jetty dependency we do not want to expose to the customer).
if (f.getName().contains(fileNamePattern)) {
return f;
}
}
}
throw new IllegalArgumentException("Unable to find " + fileNamePattern + " at " + path.getAbsolutePath());
}

private List<File> getJetty12Jars(String subDir) {
File path = new File(sdkRoot, JETTY12_HOME_LIB_PATH + File.separator + subDir);

Expand Down Expand Up @@ -219,10 +238,12 @@ List<File> getJetty12JspJars() {
if (Boolean.getBoolean("appengine.use.EE10")) {
List<File> lf = getJetty12Jars("ee10-apache-jsp");
lf.addAll(getJetty12Jars("ee10-glassfish-jstl"));
lf.add(getJetty12Jar("ee10-servlet-"));
return lf;
}
List<File> lf = getJetty12Jars("ee8-apache-jsp");
lf.addAll(getJetty12Jars("ee8-glassfish-jstl"));
lf.add(getJetty12Jar("ee8-servlet-"));
return lf;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import java.util.logging.Logger;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletHandler;
import org.eclipse.jetty.http.pathmap.MatchedResource;
import org.eclipse.jetty.ee10.servlet.ServletMapping;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
Expand All @@ -57,6 +57,7 @@ public class LocalResourceFileServlet extends HttpServlet {
private Resource resourceBase;
private String[] welcomeFiles;
private String resourceRoot;
private String defaultServletName;

/**
* Initialize the servlet by extracting some useful configuration
Expand All @@ -73,6 +74,12 @@ public void init() throws ServletException {
ServletContextHandler.getServletContextHandler(servletContext);
welcomeFiles = contextHandler.getWelcomeFiles();

ServletMapping servletMapping = contextHandler.getServletHandler().getServletMapping("/");
if (servletMapping == null) {
throw new ServletException("No servlet mapping found");
}
defaultServletName = servletMapping.getServletName();

AppEngineWebXml appEngineWebXml =
(AppEngineWebXml)
servletContext.getAttribute("com.google.appengine.tools.development.appEngineWebXml");
Expand Down Expand Up @@ -254,24 +261,23 @@ private boolean maybeServeWelcomeFile(
ServletContext context = getServletContext();
ServletContextHandler contextHandler = ServletContextHandler.getServletContextHandler(context);
ServletHandler handler = contextHandler.getServletHandler();
MatchedResource<ServletHandler.MappedServlet> defaultEntry = handler.getMatchedServlet("/");
MatchedResource<ServletHandler.MappedServlet> jspEntry = handler.getMatchedServlet("/foo.jsp");
ServletHandler.MappedServlet jspEntry = handler.getMappedServlet("/foo.jsp");

// Search for dynamic welcome files.
for (String welcomeName : welcomeFiles) {
String welcomePath = path + welcomeName;
String relativePath = welcomePath.substring(1);

MatchedResource<ServletHandler.MappedServlet> entry = handler.getMatchedServlet(welcomePath);
if (!Objects.equals(entry, defaultEntry) && !Objects.equals(entry, jspEntry)) {
ServletHandler.MappedServlet mappedServlet = handler.getMappedServlet(welcomePath);
if (!Objects.equals(mappedServlet.getServletHolder().getName(), defaultServletName) && !Objects.equals(mappedServlet, jspEntry)) {
// It's a path mapped to a servlet. Forward to it.
RequestDispatcher dispatcher = request.getRequestDispatcher(path + welcomeName);
return staticFileUtils.serveWelcomeFileAsForward(dispatcher, included, request, response);
}

Resource welcomeFile = getResource(path + welcomeName);
if (welcomeFile != null && welcomeFile.exists()) {
if (!Objects.equals(entry, defaultEntry)) {
if (!Objects.equals(mappedServlet.getServletHolder().getName(), defaultServletName)) {
RequestDispatcher dispatcher = request.getRequestDispatcher(path + welcomeName);
return staticFileUtils.serveWelcomeFileAsForward(dispatcher, included, request, response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,6 @@ protected void startWebapp() throws Exception {
// - 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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,63 +239,56 @@ public void doStart() throws Exception {
}

@Override
protected void startContext() throws Exception {
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 = 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();
protected void startWebapp() 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.
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
super.startWebapp();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,8 @@ public static void populateErrorResponse(Response resp, String errMsg, Callback
try (OutputStream outstr = Content.Sink.asOutputStream(resp)) {
PrintWriter writer = new PrintWriter(outstr);
writer.print("<html><head><title>Server Error</title></head>");
writer.print("<body>" + HtmlEscapers.htmlEscaper().escape(errMsg) + "</body></html>");
String escapedMessage = (errMsg == null) ? "" : HtmlEscapers.htmlEscaper().escape(errMsg);
writer.print("<body>" + escapedMessage + "</body></html>");
writer.close();
callback.succeeded();
} catch (Throwable t) {
Expand Down