Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the Date header field value first. #44

Merged
merged 1 commit into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 32 additions & 38 deletions rfc9111/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,71 +323,65 @@
ok, age := rule.Cacheable(req, res)
if ok {
// Add Expires header field
var expires time.Time
if res.Header.Get("Date") != "" {
date, err := http.ParseTime(res.Header.Get("Date"))
if err == nil {
expires = date.Add(age)
} else {
expires = now.Add(age)
}
} else {
expires = now.Add(age)
}
od := originDate(res.Header, now)
expires := od.Add(age)

Check failure on line 327 in rfc9111/shared.go

View workflow job for this annotation

GitHub Actions / Test

[gostyle.varnames] "expires" is small scope. Variable name length of small scope should be less than or equal to 4. (THIS IS NOT IN Go Style)
res.Header.Set("Expires", expires.UTC().Format(http.TimeFormat))
return true, expires
}
}
return false, time.Time{}
}

func CalclateExpires(d *ResponseDirectives, header http.Header, heuristicExpirationRatio float64, now time.Time) time.Time {
func CalclateExpires(d *ResponseDirectives, resHeader http.Header, heuristicExpirationRatio float64, now time.Time) time.Time {
// 4.2.1. Calculating Freshness Lifetime
// A cache can calculate the freshness lifetime (denoted as freshness_lifetime) of a response by evaluating the following rules and using the first match:

// - If the cache is shared and the s-maxage response directive (https://httpwg.org/specs/rfc9111.html#rfc.section.5.2.2.10) is present, use its value, or
// - If the cache is shared and the s-maxage response directive (https://httpwg.org/specs/rfc9111.html#rfc.section.5.2.2.10) is present, use its value
if d.SMaxAge != nil {
return now.Add(time.Duration(*d.SMaxAge) * time.Second)
od := originDate(resHeader, now)
return od.Add(time.Duration(*d.SMaxAge) * time.Second)
}
// - If the max-age response directive (https://httpwg.org/specs/rfc9111.html#rfc.section.5.2.2.1) is present, use its value, or
// - If the max-age response directive (https://httpwg.org/specs/rfc9111.html#rfc.section.5.2.2.1) is present, use its value
if d.MaxAge != nil {
return now.Add(time.Duration(*d.MaxAge) * time.Second)
od := originDate(resHeader, now)
return od.Add(time.Duration(*d.MaxAge) * time.Second)
}
if header.Get("Expires") != "" {
// - If the Expires response header field (https://httpwg.org/specs/rfc9111.html#rfc.section.5.3) is present, use its value minus the value of the Date response header field
et, err := http.ParseTime(header.Get("Expires"))
if resHeader.Get("Expires") != "" {
// - If the Expires response header field (https://httpwg.org/specs/rfc9111.html#rfc.section.5.3) is present, use its value minus the value of the Date response header field (using the time the message was received if it is not present, as per Section 6.6.1 of [HTTP])
et, err := http.ParseTime(resHeader.Get("Expires"))
if err == nil {
if header.Get("Date") != "" {
dt, err := http.ParseTime(header.Get("Date"))
if err == nil {
return now.Add(et.Sub(dt))
}
} else {
// (using the time the message was received if it is not present, as per https://httpwg.org/specs/rfc9110.html#rfc.section.6.6.1 of [HTTP])
return et // == return now.Add(et.Sub(now))
}
od := originDate(resHeader, now)
return now.Add(et.Sub(od))
}
}
// Otherwise, no explicit expiration time is present in the response. A heuristic freshness lifetime might be applicable; see https://httpwg.org/specs/rfc9111.html#rfc.section.4.2.2.
if header.Get("Last-Modified") != "" {
lt, err := http.ParseTime(header.Get("Last-Modified"))
if resHeader.Get("Last-Modified") != "" {
lt, err := http.ParseTime(resHeader.Get("Last-Modified"))
if err == nil {
// If the response has a Last-Modified header field (https://httpwg.org/specs/rfc9110.html#rfc.section.8.8.2 of [HTTP]), caches are encouraged to use a heuristic expiration value that is no more than some fraction of the interval since that time. A typical setting of this fraction might be 10%.
if header.Get("Date") != "" {
dt, err := http.ParseTime(header.Get("Date"))
if err == nil {
return dt.Add(time.Duration(float64(dt.Sub(lt)) * heuristicExpirationRatio))
}
} else {
return now.Add(time.Duration(float64(now.Sub(lt)) * heuristicExpirationRatio))
}
od := originDate(resHeader, now)
return od.Add(time.Duration(float64(od.Sub(lt)) * heuristicExpirationRatio))
}
}

// Can't calculate expires
return time.Time{}
}

func originDate(resHeader http.Header, now time.Time) time.Time {
if resHeader.Get("Date") != "" {
t, err := http.ParseTime(resHeader.Get("Date"))
if err == nil {
return t
}
}
// A recipient with a clock that receives a response with an invalid Date header field value MAY replace that value with the time that response was received. (https://httpwg.org/specs/rfc9110.html#rfc.section.6.6.1 of [HTTP])
//
// ...using the time the message was received if it is not present, as per https://httpwg.org/specs/rfc9110.html#rfc.section.6.6.1 of [HTTP]
// (https://httpwg.org/specs/rfc9111.html#rfc.section.4.2.1)
return now
}

func contains[T comparable](v T, vv []T) bool {
for _, vvv := range vv {
if vvv == v {
Expand Down
2 changes: 1 addition & 1 deletion testdata/go_test.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.21.5

require (
github.com/google/go-cmp v0.6.0
github.com/k1LoW/httpstub v0.11.1
github.com/k1LoW/httpstub v0.12.0
)

require (
Expand Down
4 changes: 2 additions & 2 deletions testdata/go_test.sum
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc=
github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/k1LoW/httpstub v0.11.1 h1:amfxTttNX82F12kmUr9vrptpLl+nCUzHrEpvUqoCWQ0=
github.com/k1LoW/httpstub v0.11.1/go.mod h1:PYUmCF/2A7+TPhRPVJ4xSynM0O1x2mIjh+Tzd/DmiG8=
github.com/k1LoW/httpstub v0.12.0 h1:BDiTmO8G8FIdvDavHaYgl7+kVlQQACLESpC+02/DzQ0=
github.com/k1LoW/httpstub v0.12.0/go.mod h1:PYUmCF/2A7+TPhRPVJ4xSynM0O1x2mIjh+Tzd/DmiG8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
Expand Down
Loading