file_server: use the UTC timezone for modified time (#6830)

* use UTC timezone for modified time

* use http.ParseTime to handle If-Modified-Since

* use time.Compare to simplify comparison

* take the directory's modtime into consideration when calculating lastModified

* update comments about If-Modified-Since's handling
This commit is contained in:
WeidiDeng 2025-02-10 23:39:43 +08:00 committed by GitHub
parent 9b74a53e51
commit 22563a70eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 18 additions and 8 deletions

View file

@ -130,9 +130,9 @@ func (fsrv *FileServer) serveBrowse(fileSystem fs.FS, root, dirPath string, w ht
// speed up browser/client experience and caching by supporting If-Modified-Since // speed up browser/client experience and caching by supporting If-Modified-Since
if ifModSinceStr := r.Header.Get("If-Modified-Since"); ifModSinceStr != "" { if ifModSinceStr := r.Header.Get("If-Modified-Since"); ifModSinceStr != "" {
ifModSince, err := time.ParseInLocation(http.TimeFormat, ifModSinceStr, time.Local) // basically a copy of stdlib file server's handling of If-Modified-Since
lastModTrunc := listing.lastModified.Truncate(time.Second) ifModSince, err := http.ParseTime(ifModSinceStr)
if err == nil && (lastModTrunc.Equal(ifModSince) || lastModTrunc.Before(ifModSince)) { if err == nil && listing.lastModified.Truncate(time.Second).Compare(ifModSince) <= 0 {
w.WriteHeader(http.StatusNotModified) w.WriteHeader(http.StatusNotModified)
return nil return nil
} }
@ -213,6 +213,11 @@ func (fsrv *FileServer) serveBrowse(fileSystem fs.FS, root, dirPath string, w ht
} }
func (fsrv *FileServer) loadDirectoryContents(ctx context.Context, fileSystem fs.FS, dir fs.ReadDirFile, root, urlPath string, repl *caddy.Replacer) (*browseTemplateContext, error) { func (fsrv *FileServer) loadDirectoryContents(ctx context.Context, fileSystem fs.FS, dir fs.ReadDirFile, root, urlPath string, repl *caddy.Replacer) (*browseTemplateContext, error) {
// modTime for the directory itself
stat, err := dir.Stat()
if err != nil {
return nil, err
}
dirLimit := defaultDirEntryLimit dirLimit := defaultDirEntryLimit
if fsrv.Browse.FileLimit != 0 { if fsrv.Browse.FileLimit != 0 {
dirLimit = fsrv.Browse.FileLimit dirLimit = fsrv.Browse.FileLimit
@ -225,7 +230,7 @@ func (fsrv *FileServer) loadDirectoryContents(ctx context.Context, fileSystem fs
// user can presumably browse "up" to parent folder if path is longer than "/" // user can presumably browse "up" to parent folder if path is longer than "/"
canGoUp := len(urlPath) > 1 canGoUp := len(urlPath) > 1
return fsrv.directoryListing(ctx, fileSystem, files, canGoUp, root, urlPath, repl), nil return fsrv.directoryListing(ctx, fileSystem, stat.ModTime(), files, canGoUp, root, urlPath, repl), nil
} }
// browseApplyQueryParams applies query parameters to the listing. // browseApplyQueryParams applies query parameters to the listing.

View file

@ -35,15 +35,16 @@ import (
"github.com/caddyserver/caddy/v2/modules/caddyhttp" "github.com/caddyserver/caddy/v2/modules/caddyhttp"
) )
func (fsrv *FileServer) directoryListing(ctx context.Context, fileSystem fs.FS, entries []fs.DirEntry, canGoUp bool, root, urlPath string, repl *caddy.Replacer) *browseTemplateContext { func (fsrv *FileServer) directoryListing(ctx context.Context, fileSystem fs.FS, parentModTime time.Time, entries []fs.DirEntry, canGoUp bool, root, urlPath string, repl *caddy.Replacer) *browseTemplateContext {
filesToHide := fsrv.transformHidePaths(repl) filesToHide := fsrv.transformHidePaths(repl)
name, _ := url.PathUnescape(urlPath) name, _ := url.PathUnescape(urlPath)
tplCtx := &browseTemplateContext{ tplCtx := &browseTemplateContext{
Name: path.Base(name), Name: path.Base(name),
Path: urlPath, Path: urlPath,
CanGoUp: canGoUp, CanGoUp: canGoUp,
lastModified: parentModTime,
} }
for _, entry := range entries { for _, entry := range entries {
@ -131,6 +132,10 @@ func (fsrv *FileServer) directoryListing(ctx context.Context, fileSystem fs.FS,
}) })
} }
// this time is used for the Last-Modified header and comparing If-Modified-Since from client
// both are expected to be in UTC, so we convert to UTC here
// see: https://github.com/caddyserver/caddy/issues/6828
tplCtx.lastModified = tplCtx.lastModified.UTC()
return tplCtx return tplCtx
} }