@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2002 - 2012 the original author or authors .
* Copyright 2002 - 2014 the original author or authors .
*
* Licensed under the Apache License , Version 2 . 0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
@ -16,6 +16,7 @@
@@ -16,6 +16,7 @@
package org.springframework.web.servlet.resource ;
import java.io.IOException ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.List ;
@ -35,189 +36,171 @@ import org.springframework.web.servlet.HandlerMapping;
@@ -35,189 +36,171 @@ import org.springframework.web.servlet.HandlerMapping;
import static org.junit.Assert.* ;
/ * *
* Unit tests for ResourceHttpRequestHandler .
*
* @author Keith Donald
* @author Jeremy Grelle
* @author Rossen Stoyanchev
* /
public class ResourceHttpRequestHandlerTests {
private ResourceHttpRequestHandler handler ;
private MockHttpServletRequest request ;
private MockHttpServletResponse response ;
@Before
public void setUp ( ) throws Exception {
List < Resource > resourcePaths = new ArrayList < Resource > ( ) ;
resourcePaths . add ( new ClassPathResource ( "test/" , getClass ( ) ) ) ;
resourcePaths . add ( new ClassPathResource ( "testalternatepath/" , getClass ( ) ) ) ;
handler = new ResourceHttpRequestHandler ( ) ;
handler . setLocations ( resourcePaths ) ;
handler . setCacheSeconds ( 3600 ) ;
handler . setServletContext ( new TestServletContext ( ) ) ;
handler . afterPropertiesSet ( ) ;
List < Resource > paths = new ArrayList < > ( 2 ) ;
paths . add ( new ClassPathResource ( "test/" , getClass ( ) ) ) ;
paths . add ( new ClassPathResource ( "testalternatepath/" , getClass ( ) ) ) ;
this . handler = new ResourceHttpRequestHandler ( ) ;
this . handler . setLocations ( paths ) ;
this . handler . setCacheSeconds ( 3600 ) ;
this . handler . setServletContext ( new TestServletContext ( ) ) ;
this . handler . afterPropertiesSet ( ) ;
this . request = new MockHttpServletRequest ( "GET" , "" ) ;
this . response = new MockHttpServletResponse ( ) ;
}
@Test
public void getResource ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/foo.css" ) ;
request . setMethod ( "GET" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( "text/css" , response . getContentType ( ) ) ;
assertEquals ( 17 , response . getContentLength ( ) ) ;
assertTrue ( Long . valueOf ( response . getHeader ( "Expires" ) ) > = System . currentTimeMillis ( ) - 1000 + ( 3600 * 1000 ) ) ;
assertEquals ( "max-age=3600, must-revalidate" , response . getHeader ( "Cache-Control" ) ) ;
assertTrue ( response . containsHeader ( "Last-Modified" ) ) ;
assertEquals ( Long . valueOf ( response . getHeader ( "Last-Modified" ) ) . longValue ( ) ,
new ClassPathResource ( "test/foo.css" , getClass ( ) ) . getFile ( ) . lastModified ( ) ) ;
assertEquals ( "h1 { color:red; }" , response . getContentAsString ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/foo.css" ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( "text/css" , this . response . getContentType ( ) ) ;
assertEquals ( 17 , this . response . getContentLength ( ) ) ;
assertTrue ( headerAsLong ( "Expires" ) > = System . currentTimeMillis ( ) - 1000 + ( 3600 * 1000 ) ) ;
assertEquals ( "max-age=3600, must-revalidate" , this . response . getHeader ( "Cache-Control" ) ) ;
assertTrue ( this . response . containsHeader ( "Last-Modified" ) ) ;
assertEquals ( headerAsLong ( "Last-Modified" ) , resourceLastModified ( "test/foo.css" ) ) ;
assertEquals ( "h1 { color:red; }" , this . response . getContentAsString ( ) ) ;
}
@Test
public void getResourceWithHtmlMediaType ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/foo.html" ) ;
request . setMethod ( "GET" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( "text/html" , response . getContentType ( ) ) ;
assertTrue ( Long . valueOf ( response . getHeader ( "Expires" ) ) > = System . currentTimeMillis ( ) - 1000 + ( 3600 * 1000 ) ) ;
assertEquals ( "max-age=3600, must-revalidate" , response . getHeader ( "Cache-Control" ) ) ;
assertTrue ( response . containsHeader ( "Last-Modified" ) ) ;
assertEquals ( Long . valueOf ( response . getHeader ( "Last-Modified" ) ) . longValue ( ) ,
new ClassPathResource ( "test/foo.html" , getClass ( ) ) . getFile ( ) . lastModified ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/foo.html" ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( "text/html" , this . response . getContentType ( ) ) ;
assertTrue ( headerAsLong ( "Expires" ) > = System . currentTimeMillis ( ) - 1000 + ( 3600 * 1000 ) ) ;
assertEquals ( "max-age=3600, must-revalidate" , this . response . getHeader ( "Cache-Control" ) ) ;
assertTrue ( this . response . containsHeader ( "Last-Modified" ) ) ;
assertEquals ( headerAsLong ( "Last-Modified" ) , resourceLastModified ( "test/foo.html" ) ) ;
}
@Test
public void getResourceFromAlternatePath ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/baz.css" ) ;
request . setMethod ( "GET" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( "text/css" , response . getContentType ( ) ) ;
assertEquals ( 17 , response . getContentLength ( ) ) ;
assertTrue ( Long . valueOf ( response . getHeader ( "Expires" ) ) > = System . currentTimeMillis ( ) - 1000 + ( 3600 * 1000 ) ) ;
assertEquals ( "max-age=3600, must-revalidate" , response . getHeader ( "Cache-Control" ) ) ;
assertTrue ( response . containsHeader ( "Last-Modified" ) ) ;
assertEquals ( Long . valueOf ( response . getHeader ( "Last-Modified" ) ) . longValue ( ) ,
new ClassPathResource ( "testalternatepath/baz.css" , getClass ( ) ) . getFile ( ) . lastModified ( ) ) ;
assertEquals ( "h1 { color:red; }" , response . getContentAsString ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/baz.css" ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( "text/css" , this . response . getContentType ( ) ) ;
assertEquals ( 17 , this . response . getContentLength ( ) ) ;
assertTrue ( headerAsLong ( "Expires" ) > = System . currentTimeMillis ( ) - 1000 + ( 3600 * 1000 ) ) ;
assertEquals ( "max-age=3600, must-revalidate" , this . response . getHeader ( "Cache-Control" ) ) ;
assertTrue ( this . response . containsHeader ( "Last-Modified" ) ) ;
assertEquals ( headerAsLong ( "Last-Modified" ) , resourceLastModified ( "testalternatepath/baz.css" ) ) ;
assertEquals ( "h1 { color:red; }" , this . response . getContentAsString ( ) ) ;
}
@Test
public void getResourceFromSubDirectory ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/js/foo.js" ) ;
request . setMethod ( "GET" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( "text/javascript" , response . getContentType ( ) ) ;
assertEquals ( "function foo() { console.log(\"hello world\"); }" , response . getContentAsString ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/js/foo.js" ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( "text/javascript" , this . response . getContentType ( ) ) ;
assertEquals ( "function foo() { console.log(\"hello world\"); }" , this . response . getContentAsString ( ) ) ;
}
@Test
public void getResourceFromSubDirectoryOfAlternatePath ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/js/baz.js" ) ;
request . setMethod ( "GET" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( "text/javascript" , response . getContentType ( ) ) ;
assertEquals ( "function foo() { console.log(\"hello world\"); }" , response . getContentAsString ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/js/baz.js" ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( "text/javascript" , this . response . getContentType ( ) ) ;
assertEquals ( "function foo() { console.log(\"hello world\"); }" , this . response . getContentAsString ( ) ) ;
}
@Test
public void getResourceViaDirectoryTraversal ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setMethod ( "GET" ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "../testsecret/secret.txt" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( 404 , response . getStatus ( ) ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "test/../../testsecret/secret.txt" ) ;
response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( 404 , response . getStatus ( ) ) ;
handler . setLocations ( Arrays . < Resource > asList ( new ClassPathResource ( "testsecret/" , getClass ( ) ) ) ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "secret.txt" ) ;
response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( 200 , response . getStatus ( ) ) ;
assertEquals ( "text/plain" , response . getContentType ( ) ) ;
assertEquals ( "big secret" , response . getContentAsString ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "../testsecret/secret.txt" ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( 404 , this . response . getStatus ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "test/../../testsecret/secret.txt" ) ;
this . response = new MockHttpServletResponse ( ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( 404 , this . response . getStatus ( ) ) ;
this . handler . setLocations ( Arrays . < Resource > asList ( new ClassPathResource ( "testsecret/" , getClass ( ) ) ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "secret.txt" ) ;
this . response = new MockHttpServletResponse ( ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( 200 , this . response . getStatus ( ) ) ;
assertEquals ( "text/plain" , this . response . getContentType ( ) ) ;
assertEquals ( "big secret" , this . response . getContentAsString ( ) ) ;
}
@Test
public void notModified ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/foo.css" ) ;
request . addHeader ( "If-Modified-Since" , new ClassPathResource ( "test/foo.css" , getClass ( ) ) . getFile ( ) . lastModified ( ) ) ;
request . setMethod ( "GET" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( HttpServletResponse . SC_NOT_MODIFIED , response . getStatus ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/foo.css" ) ;
this . request . addHeader ( "If-Modified-Since" , resourceLastModified ( "test/foo.css" ) ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( HttpServletResponse . SC_NOT_MODIFIED , this . response . getStatus ( ) ) ;
}
@Test
public void modified ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/foo.css" ) ;
request . addHeader ( "If-Modified-Since" ,
new ClassPathResource ( "test/foo.css" , getClass ( ) ) . getFile ( ) . lastModified ( ) / 1000 * 1000 - 1 ) ;
request . setMethod ( "GET" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( HttpServletResponse . SC_OK , response . getStatus ( ) ) ;
assertEquals ( "h1 { color:red; }" , response . getContentAsString ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/foo.css" ) ;
this . request . addHeader ( "If-Modified-Since" , resourceLastModified ( "test/foo.css" ) / 1000 * 1000 - 1 ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( HttpServletResponse . SC_OK , this . response . getStatus ( ) ) ;
assertEquals ( "h1 { color:red; }" , this . response . getContentAsString ( ) ) ;
}
@Test
public void directory ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/js/" ) ;
request . setMethod ( "GET" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( 404 , response . getStatus ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/js/" ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( 404 , this . response . getStatus ( ) ) ;
}
@Test
public void missingResourcePath ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "" ) ;
request . setMethod ( "GET" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( 404 , response . getStatus ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "" ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( 404 , this . response . getStatus ( ) ) ;
}
@Test ( expected = IllegalStateException . class )
public void noPathWithinHandlerMappingAttribute ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setMethod ( "GET" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
this . handler . handleRequest ( this . request , this . response ) ;
}
@Test ( expected = HttpRequestMethodNotSupportedException . class )
public void unsupportedHttpMethod ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/foo.css" ) ;
request . setMethod ( "POST" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/foo.css" ) ;
this . request . setMethod ( "POST" ) ;
this . handler . handleRequest ( this . request , this . response ) ;
}
@Test
public void resourceNotFound ( ) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest ( ) ;
request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/not-there.css" ) ;
request . setMethod ( "GET" ) ;
MockHttpServletResponse response = new MockHttpServletResponse ( ) ;
handler . handleRequest ( request , response ) ;
assertEquals ( 404 , response . getStatus ( ) ) ;
this . request . setAttribute ( HandlerMapping . PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , "/not-there.css" ) ;
this . handler . handleRequest ( this . request , this . response ) ;
assertEquals ( 404 , this . response . getStatus ( ) ) ;
}
private long headerAsLong ( String responseHeaderName ) {
return Long . valueOf ( this . response . getHeader ( responseHeaderName ) ) ;
}
private long resourceLastModified ( String resourceName ) throws IOException {
return new ClassPathResource ( resourceName , getClass ( ) ) . getFile ( ) . lastModified ( ) ;
}