001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.resource; 018 019import java.io.IOException; 020 021import javax.servlet.RequestDispatcher; 022import javax.servlet.ServletContext; 023import javax.servlet.ServletException; 024import javax.servlet.http.HttpServletRequest; 025import javax.servlet.http.HttpServletResponse; 026 027import org.springframework.lang.Nullable; 028import org.springframework.util.Assert; 029import org.springframework.util.StringUtils; 030import org.springframework.web.HttpRequestHandler; 031import org.springframework.web.context.ServletContextAware; 032 033/** 034 * An {@link HttpRequestHandler} for serving static files using the Servlet container's "default" Servlet. 035 * 036 * <p>This handler is intended to be used with a "/*" mapping when the 037 * {@link org.springframework.web.servlet.DispatcherServlet DispatcherServlet} 038 * is mapped to "/", thus overriding the Servlet container's default handling of static resources. 039 * The mapping to this handler should generally be ordered as the last in the chain so that it will 040 * only execute when no other more specific mappings (i.e., to controllers) can be matched. 041 * 042 * <p>Requests are handled by forwarding through the {@link RequestDispatcher} obtained via the 043 * name specified through the {@link #setDefaultServletName "defaultServletName" property}. 044 * In most cases, the {@code defaultServletName} does not need to be set explicitly, as the 045 * handler checks at initialization time for the presence of the default Servlet of well-known 046 * containers such as Tomcat, Jetty, Resin, WebLogic and WebSphere. However, when running in a 047 * container where the default Servlet's name is not known, or where it has been customized 048 * via server configuration, the {@code defaultServletName} will need to be set explicitly. 049 * 050 * @author Jeremy Grelle 051 * @author Juergen Hoeller 052 * @since 3.0.4 053 */ 054public class DefaultServletHttpRequestHandler implements HttpRequestHandler, ServletContextAware { 055 056 /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish. */ 057 private static final String COMMON_DEFAULT_SERVLET_NAME = "default"; 058 059 /** Default Servlet name used by Google App Engine. */ 060 private static final String GAE_DEFAULT_SERVLET_NAME = "_ah_default"; 061 062 /** Default Servlet name used by Resin. */ 063 private static final String RESIN_DEFAULT_SERVLET_NAME = "resin-file"; 064 065 /** Default Servlet name used by WebLogic. */ 066 private static final String WEBLOGIC_DEFAULT_SERVLET_NAME = "FileServlet"; 067 068 /** Default Servlet name used by WebSphere. */ 069 private static final String WEBSPHERE_DEFAULT_SERVLET_NAME = "SimpleFileServlet"; 070 071 072 @Nullable 073 private String defaultServletName; 074 075 @Nullable 076 private ServletContext servletContext; 077 078 079 /** 080 * Set the name of the default Servlet to be forwarded to for static resource requests. 081 */ 082 public void setDefaultServletName(String defaultServletName) { 083 this.defaultServletName = defaultServletName; 084 } 085 086 /** 087 * If the {@code defaultServletName} property has not been explicitly set, 088 * attempts to locate the default Servlet using the known common 089 * container-specific names. 090 */ 091 @Override 092 public void setServletContext(ServletContext servletContext) { 093 this.servletContext = servletContext; 094 if (!StringUtils.hasText(this.defaultServletName)) { 095 if (this.servletContext.getNamedDispatcher(COMMON_DEFAULT_SERVLET_NAME) != null) { 096 this.defaultServletName = COMMON_DEFAULT_SERVLET_NAME; 097 } 098 else if (this.servletContext.getNamedDispatcher(GAE_DEFAULT_SERVLET_NAME) != null) { 099 this.defaultServletName = GAE_DEFAULT_SERVLET_NAME; 100 } 101 else if (this.servletContext.getNamedDispatcher(RESIN_DEFAULT_SERVLET_NAME) != null) { 102 this.defaultServletName = RESIN_DEFAULT_SERVLET_NAME; 103 } 104 else if (this.servletContext.getNamedDispatcher(WEBLOGIC_DEFAULT_SERVLET_NAME) != null) { 105 this.defaultServletName = WEBLOGIC_DEFAULT_SERVLET_NAME; 106 } 107 else if (this.servletContext.getNamedDispatcher(WEBSPHERE_DEFAULT_SERVLET_NAME) != null) { 108 this.defaultServletName = WEBSPHERE_DEFAULT_SERVLET_NAME; 109 } 110 else { 111 throw new IllegalStateException("Unable to locate the default servlet for serving static content. " + 112 "Please set the 'defaultServletName' property explicitly."); 113 } 114 } 115 } 116 117 118 @Override 119 public void handleRequest(HttpServletRequest request, HttpServletResponse response) 120 throws ServletException, IOException { 121 122 Assert.state(this.servletContext != null, "No ServletContext set"); 123 RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName); 124 if (rd == null) { 125 throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" + 126 this.defaultServletName + "'"); 127 } 128 rd.forward(request, response); 129 } 130 131}