App Engine Java SDK version 1.7.0
[gae.git] / java / src / main / com / google / appengine / tools / development / StaticFileFilter.java
blob19bd8a346109f8569cff6ec5a87f6aead9427c11
1 // Copyright 2009 Google Inc. All rights reserved.
3 package com.google.appengine.tools.development;
5 import com.google.apphosting.utils.config.AppEngineWebXml;
7 import org.mortbay.jetty.handler.ContextHandler;
8 import org.mortbay.jetty.servlet.Dispatcher;
9 import org.mortbay.resource.Resource;
10 import org.mortbay.util.URIUtil;
12 import java.io.IOException;
13 import java.net.MalformedURLException;
14 import java.util.logging.Level;
15 import java.util.logging.Logger;
17 import javax.servlet.Filter;
18 import javax.servlet.FilterChain;
19 import javax.servlet.FilterConfig;
20 import javax.servlet.RequestDispatcher;
21 import javax.servlet.ServletException;
22 import javax.servlet.ServletRequest;
23 import javax.servlet.ServletResponse;
24 import javax.servlet.http.HttpServletRequest;
25 import javax.servlet.http.HttpServletRequestWrapper;
26 import javax.servlet.http.HttpServletResponse;
28 /**
29 * {@code StaticFileFilter} is a {@link Filter} that replicates the
30 * static file serving logic that is present in the PFE and AppServer.
31 * This logic was originally implemented in {@link
32 * LocalResourceFileServlet} but static file serving needs to take
33 * precedence over all other servlets and filters.
36 public class StaticFileFilter implements Filter {
37 private static final Logger logger =
38 Logger.getLogger(StaticFileFilter.class.getName());
40 private StaticFileUtils staticFileUtils;
41 private AppEngineWebXml appEngineWebXml;
42 private Resource resourceBase;
43 private String[] welcomeFiles;
44 private String resourceRoot;
45 private ContextHandler.SContext servletContext;
47 @Override
48 public void init(FilterConfig filterConfig) throws ServletException {
49 servletContext = (ContextHandler.SContext) filterConfig.getServletContext();
50 staticFileUtils = new StaticFileUtils(servletContext);
52 welcomeFiles = servletContext.getContextHandler().getWelcomeFiles();
54 appEngineWebXml = (AppEngineWebXml) servletContext.getAttribute(
55 "com.google.appengine.tools.development.appEngineWebXml");
56 resourceRoot = appEngineWebXml.getPublicRoot();
58 try {
59 resourceBase = servletContext.getContextHandler().getResource(URIUtil.SLASH + resourceRoot);
60 } catch (MalformedURLException ex) {
61 logger.log(Level.WARNING, "Could not initialize:", ex);
62 throw new ServletException(ex);
66 @Override
67 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
68 throws ServletException, IOException {
69 Boolean forwarded = (Boolean) request.getAttribute(Dispatcher.__FORWARD_JETTY);
70 if (forwarded == null) {
71 forwarded = Boolean.FALSE;
74 Boolean included = (Boolean) request.getAttribute(Dispatcher.__INCLUDE_JETTY);
75 if (included == null) {
76 included = Boolean.FALSE;
79 if (forwarded || included) {
80 chain.doFilter(request, response);
81 return;
84 HttpServletRequest httpRequest = (HttpServletRequest) request;
85 HttpServletResponse httpResponse = (HttpServletResponse) response;
86 String servletPath = httpRequest.getServletPath();
87 String pathInfo = httpRequest.getPathInfo();
88 String pathInContext = URIUtil.addPaths(servletPath, pathInfo);
90 if (maybeServeWelcomeFile(pathInContext, httpRequest, httpResponse)) {
91 return;
94 Resource resource = null;
95 try {
96 resource = getResource(pathInContext);
98 if (resource != null && resource.exists() && !resource.isDirectory()) {
99 if (appEngineWebXml.includesStatic(resourceRoot + pathInContext)) {
100 if (staticFileUtils.passConditionalHeaders(httpRequest, httpResponse, resource)) {
101 staticFileUtils.sendData(httpRequest, httpResponse, false, resource);
103 return;
106 } finally {
107 if (resource != null) {
108 resource.release();
111 chain.doFilter(request, response);
115 * Get Resource to serve.
116 * @param pathInContext The path to find a resource for.
117 * @return The resource to serve.
119 private Resource getResource(String pathInContext) {
120 try {
121 if (resourceBase != null) {
122 return resourceBase.addPath(pathInContext);
124 } catch (IOException ex) {
125 logger.log(Level.WARNING, "Could not find: " + pathInContext, ex);
127 return null;
131 * Finds a matching welcome file for the supplied path and, if
132 * found, serves it to the user. This will be the first entry in
133 * the list of configured {@link #welcomeFiles welcome files} that
134 * exists within the directory referenced by the path.
135 * @param path
136 * @param request
137 * @param response
138 * @return true if a welcome file was served, false otherwise
139 * @throws IOException
140 * @throws MalformedURLException
142 private boolean maybeServeWelcomeFile(String path,
143 HttpServletRequest request,
144 HttpServletResponse response)
145 throws IOException, ServletException {
146 if (welcomeFiles == null) {
147 return false;
150 if (!path.endsWith(URIUtil.SLASH)) {
151 path += URIUtil.SLASH;
154 for (String welcomeName : welcomeFiles) {
155 final String welcomePath = path + welcomeName;
157 Resource welcomeFile = getResource(path + welcomeName);
158 if (welcomeFile != null && welcomeFile.exists()) {
159 if (appEngineWebXml.includesStatic(resourceRoot + welcomePath)) {
160 RequestDispatcher dispatcher = servletContext.getNamedDispatcher("_ah_default");
161 request = new HttpServletRequestWrapper(request) {
162 @Override
163 public String getServletPath() {
164 return welcomePath;
167 @Override
168 public String getPathInfo() {
169 return "";
172 return staticFileUtils.serveWelcomeFileAsForward(dispatcher, false, request, response);
177 return false;
180 @Override
181 public void destroy() {