@@ -96,17 +96,43 @@ public void handleRequest(HttpServletRequest request, HttpServletResponse respon
9696 throws ServletException , IOException {
9797
9898 checkAndPrepare (request , response , true );
99+
100+ // check whether a matching resource exists
99101 Resource resource = getResource (request );
100102 if (resource == null ) {
103+ logger .debug ("No matching resource found - returning 404" );
101104 response .sendError (HttpServletResponse .SC_NOT_FOUND );
102105 return ;
103106 }
104- setHeaders (resource , response );
105- if (new ServletWebRequest (request , response ).checkNotModified (resource .lastModified ()) ||
106- METHOD_HEAD .equals (request .getMethod ())) {
107+
108+ // check the resource's media type
109+ MediaType mediaType = getMediaType (resource );
110+ if (mediaType != null ) {
111+ if (logger .isDebugEnabled ()) {
112+ logger .debug ("Determined media type [" + mediaType + "] for " + resource );
113+ }
114+ }
115+ else {
116+ if (logger .isDebugEnabled ()) {
117+ logger .debug ("No media type found for " + resource + " - returning 404" );
118+ }
119+ response .sendError (HttpServletResponse .SC_NOT_FOUND );
107120 return ;
108121 }
109- writeContent (resource , response );
122+
123+ // header phase
124+ setHeaders (response , resource , mediaType );
125+ if (new ServletWebRequest (request , response ).checkNotModified (resource .lastModified ())) {
126+ logger .debug ("Resource not modified - returning 304" );
127+ return ;
128+ }
129+
130+ // content phase
131+ if (METHOD_HEAD .equals (request .getMethod ())) {
132+ logger .trace ("HEAD request - skipping content" );
133+ return ;
134+ }
135+ writeContent (response , resource );
110136 }
111137
112138 protected Resource getResource (HttpServletRequest request ) {
@@ -115,42 +141,72 @@ protected Resource getResource(HttpServletRequest request) {
115141 throw new IllegalStateException ("Required request attribute '" +
116142 HandlerMapping .PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE + "' is not set" );
117143 }
144+
118145 if (!StringUtils .hasText (path ) || path .contains ("WEB-INF" ) || path .contains ("META-INF" )) {
146+ if (logger .isDebugEnabled ()) {
147+ logger .debug ("Ignoring invalid resource path [" + path + "]" );
148+ }
119149 return null ;
120150 }
121- for (Resource resourcePath : this .locations ) {
151+
152+ for (Resource location : this .locations ) {
122153 try {
123- Resource resource = resourcePath .createRelative (path );
154+ if (logger .isDebugEnabled ()) {
155+ logger .debug ("Trying relative path [" + path + "] against base location: " + location );
156+ }
157+ Resource resource = location .createRelative (path );
124158 if (resource .exists () && resource .isReadable ()) {
159+ if (logger .isDebugEnabled ()) {
160+ logger .debug ("Found matching resource: " + resource );
161+ }
125162 return resource ;
126163 }
164+ else if (logger .isTraceEnabled ()) {
165+ logger .trace ("Relative resource doesn't exist or isn't readable: " + resource );
166+ }
127167 }
128168 catch (IOException ex ) {
129- // resource not found
130- return null ;
169+ logger .debug ("Failed to create relative resource - trying next resource location" , ex );
131170 }
132171 }
133172 return null ;
134173 }
135174
136- protected void setHeaders (Resource resource , HttpServletResponse response ) throws IOException {
137- MediaType mediaType = getMediaType (resource );
138- if (mediaType != null ) {
139- response .setContentType (mediaType .toString ());
140- }
175+ /**
176+ * Determine an appropriate media type for the given resource.
177+ * @param resource the resource to check
178+ * @return the corresponding media type, or <code>null</code> if none found
179+ */
180+ protected MediaType getMediaType (Resource resource ) {
181+ String mimeType = getServletContext ().getMimeType (resource .getFilename ());
182+ return (StringUtils .hasText (mimeType ) ? MediaType .parseMediaType (mimeType ) : null );
183+ }
184+
185+ /**
186+ * Set headers on the given servlet response.
187+ * Called for GET requests as well as HEAD requests.
188+ * @param response current servlet response
189+ * @param resource the identified resource (never <code>null</code>)
190+ * @param mediaType the resource's media type (never <code>null</code>)
191+ * @throws IOException in case of errors while setting the headers
192+ */
193+ protected void setHeaders (HttpServletResponse response , Resource resource , MediaType mediaType ) throws IOException {
141194 long length = resource .contentLength ();
142195 if (length > Integer .MAX_VALUE ) {
143196 throw new IOException ("Resource content too long (beyond Integer.MAX_VALUE): " + resource );
144197 }
145198 response .setContentLength ((int ) length );
199+ response .setContentType (mediaType .toString ());
146200 }
147201
148- protected MediaType getMediaType (Resource resource ) {
149- String mimeType = getServletContext ().getMimeType (resource .getFilename ());
150- return (StringUtils .hasText (mimeType ) ? MediaType .parseMediaType (mimeType ) : null );
151- }
152-
153- protected void writeContent (Resource resource , HttpServletResponse response ) throws IOException {
202+ /**
203+ * Write the actual content out to the given servlet response,
204+ * streaming the resource's content.
205+ * @param response current servlet response
206+ * @param resource the identified resource (never <code>null</code>)
207+ * @throws IOException in case of errors while writing the content
208+ */
209+ protected void writeContent (HttpServletResponse response , Resource resource ) throws IOException {
154210 FileCopyUtils .copy (resource .getInputStream (), response .getOutputStream ());
155211 }
156212
0 commit comments