001 // Copyright 2006, 2007, 2008, 2010 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry5.internal.services; 016 017 import java.io.IOException; 018 import java.net.URL; 019 020 import javax.servlet.http.HttpServletResponse; 021 022 import org.apache.tapestry5.TapestryConstants; 023 import org.apache.tapestry5.services.Context; 024 import org.apache.tapestry5.services.Request; 025 import org.apache.tapestry5.services.RequestFilter; 026 import org.apache.tapestry5.services.RequestHandler; 027 import org.apache.tapestry5.services.Response; 028 029 /** 030 * Identifies requests that are for actual resource files in the context. For those, Tapestry allows the servlet 031 * container to process the request. 032 */ 033 public class StaticFilesFilter implements RequestFilter 034 { 035 private final Context context; 036 037 public StaticFilesFilter(Context context) 038 { 039 this.context = context; 040 } 041 042 public boolean service(Request request, Response response, RequestHandler handler) 043 throws IOException 044 { 045 String path = request.getPath(); 046 047 // TAPESTRY-1322: Treat requests from the browser for a favorites icon via the normal 048 // servlet even if the file doesn't exist, to keep the request from looking like a 049 // component action request. 050 051 if (path.equals("/favicon.ico")) return false; 052 053 // TAPESTRY-2606: A colon in the path is frequently the case for Tapestry event URLs, 054 // but gives Windows fits. 055 056 if (!path.contains(":")) 057 { 058 // We are making the questionable assumption that all files to be vended out will contain 059 // an extension (with a dot separator). Without this, the filter tends to match against 060 // folder names when we don't want it to (especially for the root context path). 061 062 int dotx = path.lastIndexOf("."); 063 064 if (dotx > 0) 065 { 066 URL url = context.getResource(path); 067 068 if (url != null) 069 { 070 String suffix = path.substring(dotx + 1); 071 072 // We never allow access to Tapestry component templates, even if they exist. 073 // It is considered a security risk, like seeing a raw JSP. Earlier alpha versions 074 // of Tapestry required that the templates be stored in WEB-INF. 075 076 if (suffix.equalsIgnoreCase(TapestryConstants.TEMPLATE_EXTENSION)) 077 { 078 079 response.sendError(HttpServletResponse.SC_FORBIDDEN, ServicesMessages 080 .resourcesAccessForbidden(path)); 081 082 return true; 083 } 084 085 return false; 086 } 087 } 088 } 089 090 return handler.service(request, response); 091 } 092 }