I'm trying to override the Last-Modified
-header set by http.FileServer
, but it reverts to the Last-Modified
-time of the file I'm trying to serve:
var myTime time.Time
func main() {
myTime = time.Now()
fs := http.StripPrefix("/folder/", SetCacheHeader(http.FileServer(http.Dir("/folder/"))))
http.Handle("/folder/", fs)
http.ListenAndServe(":80", nil)
}
My SetCacheHeader
-handler:
func SetCacheHeader(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Last-Modified", myTime.Format(http.TimeFormat))
h.ServeHTTP(w, r)
})
}
The handler returned by http.FileServer()
unconditionally sets the "Last-Modified"
header in the http.serveFile()
and http.serveContent()
unexported functions:
func serveFile(w ResponseWriter, r *Request, fs FileSystem,
name string, redirect bool) {
// ...
f, err := fs.Open(name)
// ...
d, err := f.Stat()
// ...
// serveContent will check modification time
sizeFunc := func() (int64, error) { return d.Size(), nil }
serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f)
}
func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
sizeFunc func() (int64, error), content io.ReadSeeker) {
setLastModified(w, modtime)
// ...
}
func setLastModified(w ResponseWriter, modtime time.Time) {
if !isZeroTime(modtime) {
w.Header().Set("Last-Modified", modtime.UTC().Format(TimeFormat))
}
}
So what you set prior to calling the file server handler will get overwritten. You can't really do anything about this.
If you need to serve the content of a file with custom last-modified time, you may use http.ServeContent()
:
func ServeContent(w ResponseWriter, req *Request, name string,
modtime time.Time, content io.ReadSeeker)
Where you can pass the last-modified time to be used, but then of course you lose all the convenient features provided by http.FileServer()
.
If you want to keep using http.FileServer()
, another option would be to not use the http.Dir
type, but create your own http.FileSystem
implementation that you pass to http.FileServer()
, in which you could report any last-modified timestamp you wish.
This would require you to implement the following interface:
type FileSystem interface {
Open(name string) (File, error)
}
So you need a method which opens a file by its name, and returns a value which implements http.File
, which is:
type File interface {
io.Closer
io.Reader
io.Seeker
Readdir(count int) ([]os.FileInfo, error)
Stat() (os.FileInfo, error)
}
And the value you return (that implements http.File
) could have a Stat() (os.FileInfo, error)
method implementation, whose os.FileInfo
returned value contains the last-modified time of your choosing. Note that you should also implement the Readdir()
method to return custom last-modified timestamps consistent with the timestamps returned by Stat()
's fileinfo. See related question how to do that: Simples way to make a []byte into a "virtual" File object in golang?