mirror of
https://github.com/caddyserver/caddy.git
synced 2025-05-25 20:29:59 +08:00
encode: Improve Etag handling (fix #5849)
We also improve Last-Modified handling in the file server. Both changes should be more compliant with RFC 9110.
This commit is contained in:
@ -156,6 +156,18 @@ func (enc *Encode) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyh
|
||||
}
|
||||
w = enc.openResponseWriter(encName, w)
|
||||
defer w.(*responseWriter).Close()
|
||||
|
||||
// to comply with RFC 9110 section 8.8.3(.3), we modify the Etag when encoding
|
||||
// by appending a hyphen and the encoder name; the problem is, the client will
|
||||
// send back that Etag in a If-None-Match header, but upstream handlers that set
|
||||
// the Etag in the first place don't know that we appended to their Etag! so here
|
||||
// we have to strip our addition so the upstream handlers can still honor client
|
||||
// caches without knowing about our changes...
|
||||
if etag := r.Header.Get("If-None-Match"); etag != "" && !strings.HasPrefix(etag, "W/") {
|
||||
etag = strings.TrimSuffix(etag, "-"+encName+`"`) + `"`
|
||||
r.Header.Set("If-None-Match", etag)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -220,6 +232,14 @@ type responseWriter struct {
|
||||
func (rw *responseWriter) WriteHeader(status int) {
|
||||
rw.statusCode = status
|
||||
|
||||
// See #5849 and RFC 9110 section 15.4.5 (https://www.rfc-editor.org/rfc/rfc9110.html#section-15.4.5) - 304
|
||||
// Not Modified must have certain headers set as if it was a 200 response, and according to the issue
|
||||
// we would miss the Vary header in this case when compression was also enabled; note that we set this
|
||||
// header in the responseWriter.init() method but that is only called if we are writing a response body
|
||||
if status == http.StatusNotModified {
|
||||
rw.Header().Add("Vary", "Accept-Encoding")
|
||||
}
|
||||
|
||||
// write status immediately when status code is informational
|
||||
// see: https://caddy.community/t/disappear-103-early-hints-response-with-encode-enable-caddy-v2-7-6/23081/5
|
||||
if 100 <= status && status <= 199 {
|
||||
@ -334,6 +354,18 @@ func (rw *responseWriter) init() {
|
||||
rw.Header().Set("Content-Encoding", rw.encodingName)
|
||||
rw.Header().Add("Vary", "Accept-Encoding")
|
||||
rw.Header().Del("Accept-Ranges") // we don't know ranges for dynamically-encoded content
|
||||
|
||||
// strong ETags need to be distinct depending on the encoding ("selected representation")
|
||||
// see RFC 9110 section 8.8.3.3:
|
||||
// https://www.rfc-editor.org/rfc/rfc9110.html#name-example-entity-tags-varying
|
||||
// I don't know a great way to do this... how about appending? That's a neat trick!
|
||||
// (We have to strip the value we append from If-None-Match headers before
|
||||
// sending subsequent requests back upstream, however, since upstream handlers
|
||||
// don't know about our appending to their Etag since they've already done their work)
|
||||
if etag := rw.Header().Get("Etag"); etag != "" && !strings.HasPrefix(etag, "W/") {
|
||||
etag = fmt.Sprintf(`%s-%s"`, strings.TrimSuffix(etag, `"`), rw.encodingName)
|
||||
rw.Header().Set("Etag", etag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user