Description
Martin Bonato opened SPR-17320 and commented
The ResourceHTTPRequestHandler returns HTTP 404 Not Found for static resources that have a file modification date of 0L (i.e. the unix epoch 00:00:00 GMT, January 1, 1970). This breaks resolving static resources in web applications build as Docker images with Jib.
One of the goals of Docker images build with Jib are "reproducible builds". That is, Docker images build from the same sources should result in the same docker image with the same SHAs for the Docker image and it's layers. To achieve this, Jib sets the modification date of every file it includes to 0 (see ReproducibleLayerBuilder). When the ResourceHTTPRequestHandler resolves a static resource from the classpath or the filesystem it checks the resource's lastModified date (ResourceHttpRequestHandler line 467|[https://github.com/spring-projects/spring-framework/blob/7aa933437c874122fef10a3cb8282359312e8d6e/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java#L467]. The AbstractResource however, throws a FileNotFoundException when the file last-modified date is 0:
public long lastModified() throws IOException {
long lastModified = getFileForLastModifiedCheck().lastModified();
if (lastModified == 0L) {
throw new FileNotFoundException(getDescription() +
" cannot be resolved in the file system for resolving its last-modified timestamp");
}
return lastModified;
}
In consequence, static resources in the classpath or filesystem in Docker images build with Jib are not resolvable by Spring WebMVCs standard ResourceHttpRequestHandler.
This renders Spring WebApplications build with Jib unusable in most cases.
Resources having a last modified date of 0L should not be treated special by Spring, however ...
Up to Java 6 the contract of java.io.File.getLastModifed() defined a return value of 0L as being returned if the file does not exist or if an I/O error occurs. From Java 7 it also considers 0L as vaild return value in the Javadoc of getLastModified()
Where it is required to distinguish an I/O exception from the case where 0L
is returned, or where several attributes of the same file are required at the same time, or where the time of last access or the creation time are required, then the Files.readAttributes
method may be used.
IMHO, Spring should not throw a FileNotFoundException in case getLastModified() returns 0L but should either just return 0L itself or try to read file attributes in such cases.
Issue Links:
- Spring's AbstractResource (used in spring-mvc) is unusable in Docker. [SPR-12862] #17460 Spring's AbstractResource (used in spring-mvc) is unusable in Docker.
- Last modified check of Resource created from Tomcat war:file: URL fails with FileNotFoundException [SPR-15485] #20045 Last modified check of Resource created from Tomcat war:file: URL fails with FileNotFoundException
- PropertySourcesPlaceholderConfigurer can not ignore resource if not found [SPR-16334] #20881 PropertySourcesPlaceholderConfigurer can not ignore resource if not found
- java.nio.file.Path support in FileSystemResource (with regular createRelative behavior, superseding PathResource) [SPR-16833] #21373 java.nio.file.Path support in FileSystemResource (with regular createRelative behavior, superseding PathResource)
Referenced from: commits b7e4a56, ff0afcf, b53995b, cf3635b
1 votes, 2 watchers