in runtime/runtime_impl_jetty9/src/main/java/com/google/apphosting/runtime/jetty9/ResourceFileServlet.java [91:191]
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String servletPath;
String pathInfo;
boolean included = request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI) != null;
if (included) {
servletPath = (String) request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH);
pathInfo = (String) request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO);
if (servletPath == null) {
servletPath = request.getServletPath();
pathInfo = request.getPathInfo();
}
} else {
included = Boolean.FALSE;
servletPath = request.getServletPath();
pathInfo = request.getPathInfo();
}
boolean forwarded = request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI) != null;
String pathInContext = URIUtil.addPaths(servletPath, pathInfo);
// The servlet spec says "No file contained in the WEB-INF
// directory may be served directly a client by the container.
// However, ... may be exposed using the RequestDispatcher calls."
// Thus, we only allow these requests for includes and forwards.
//
// TODO: I suspect we should allow error handlers here somehow.
if (isProtectedPath(pathInContext) && !included && !forwarded) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (maybeServeWelcomeFile(pathInContext, included, request, response)) {
// We served a welcome file (either via redirecting, forwarding, or including).
return;
}
if (pathInContext.endsWith(URIUtil.SLASH)) {
// N.B.: Resource.addPath() trims off trailing
// slashes, which may result in us serving files for strange
// paths (e.g. "/index.html/"). Since we already took care of
// welcome files above, we just return a 404 now if the path
// ends with a slash.
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// RFC 2396 specifies which characters are allowed in URIs:
//
// http://tools.ietf.org/html/rfc2396#section-2.4.3
//
// See also RFC 3986, which specifically mentions handling %00,
// which would allow security checks to be bypassed.
for (int i = 0; i < pathInContext.length(); i++) {
int c = pathInContext.charAt(i);
if (c < 0x20 || c == 0x7F) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
logger.atWarning().log(
"Attempted to access file containing control character, returning 400.");
return;
}
}
// Find the resource
Resource resource = null;
try {
resource = getResource(pathInContext);
if (resource == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
if (StringUtil.endsWithIgnoreCase(resource.getName(), ".jsp")) {
// General paranoia: don't ever serve raw .jsp files.
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// Handle resource
if (resource.isDirectory()) {
if (included || !fSender.checkIfUnmodified(request, response, resource)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
} else {
if (resource == null || !resource.exists()) {
logger.atWarning().log("Non existent resource: %s = %s", pathInContext, resource);
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} else {
if (included || !fSender.checkIfUnmodified(request, response, resource)) {
fSender.sendData(context, response, included, resource, request.getRequestURI());
}
}
}
} finally {
if (resource != null) {
resource.release();
}
}
}