Set the LastModified header for raw files (#18356)

Although the use of LastModified dates for caching of git objects should be
discouraged (as it is not native to git - and there are a LOT of ways this
could be incorrect) - LastModified dates can be a helpful somewhat more human
way of caching for simple cases.

This PR adds this header and handles the If-Modified-Since header to the /raw/
routes.

Fix #18354

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
zeripath 2022-05-09 16:54:51 +01:00 committed by GitHub
parent e435283c0f
commit 9f5ddca57c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 135 additions and 31 deletions

View file

@ -37,18 +37,23 @@ func generateETag(fi os.FileInfo) string {
// HandleTimeCache handles time-based caching for a HTTP request
func HandleTimeCache(req *http.Request, w http.ResponseWriter, fi os.FileInfo) (handled bool) {
return HandleGenericTimeCache(req, w, fi.ModTime())
}
// HandleGenericTimeCache handles time-based caching for a HTTP request
func HandleGenericTimeCache(req *http.Request, w http.ResponseWriter, lastModified time.Time) (handled bool) {
AddCacheControlToHeader(w.Header(), setting.StaticCacheTime)
ifModifiedSince := req.Header.Get("If-Modified-Since")
if ifModifiedSince != "" {
t, err := time.Parse(http.TimeFormat, ifModifiedSince)
if err == nil && fi.ModTime().Unix() <= t.Unix() {
if err == nil && lastModified.Unix() <= t.Unix() {
w.WriteHeader(http.StatusNotModified)
return true
}
}
w.Header().Set("Last-Modified", fi.ModTime().Format(http.TimeFormat))
w.Header().Set("Last-Modified", lastModified.Format(http.TimeFormat))
return false
}
@ -85,3 +90,33 @@ func checkIfNoneMatchIsValid(req *http.Request, etag string) bool {
}
return false
}
// HandleGenericETagTimeCache handles ETag-based caching with Last-Modified caching for a HTTP request.
// It returns true if the request was handled.
func HandleGenericETagTimeCache(req *http.Request, w http.ResponseWriter, etag string, lastModified time.Time) (handled bool) {
if len(etag) > 0 {
w.Header().Set("Etag", etag)
}
if !lastModified.IsZero() {
w.Header().Set("Last-Modified", lastModified.Format(http.TimeFormat))
}
if len(etag) > 0 {
if checkIfNoneMatchIsValid(req, etag) {
w.WriteHeader(http.StatusNotModified)
return true
}
}
if !lastModified.IsZero() {
ifModifiedSince := req.Header.Get("If-Modified-Since")
if ifModifiedSince != "" {
t, err := time.Parse(http.TimeFormat, ifModifiedSince)
if err == nil && lastModified.Unix() <= t.Unix() {
w.WriteHeader(http.StatusNotModified)
return true
}
}
}
AddCacheControlToHeader(w.Header(), setting.StaticCacheTime)
return false
}