mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-11-24 02:59:13 +08:00
fix preconditions according to https://tools.ietf.org/id/draft-ietf-httpbis-p4-conditional-26.html#preconditions
This commit is contained in:
parent
433fde4b18
commit
7f0c793083
@ -21,6 +21,64 @@ import (
|
||||
"github.com/chrislusf/seaweedfs/weed/util"
|
||||
)
|
||||
|
||||
|
||||
// Validates the preconditions. Returns true if GET/HEAD operation should not proceed.
|
||||
// Preconditions supported are:
|
||||
// If-Modified-Since
|
||||
// If-Unmodified-Since
|
||||
// If-Match
|
||||
// If-None-Match
|
||||
func checkPreconditions(w http.ResponseWriter, r *http.Request, entry *filer.Entry) bool {
|
||||
|
||||
etag := filer.ETagEntry(entry)
|
||||
/// When more than one conditional request header field is present in a
|
||||
/// request, the order in which the fields are evaluated becomes
|
||||
/// important. In practice, the fields defined in this document are
|
||||
/// consistently implemented in a single, logical order, since "lost
|
||||
/// update" preconditions have more strict requirements than cache
|
||||
/// validation, a validated cache is more efficient than a partial
|
||||
/// response, and entity tags are presumed to be more accurate than date
|
||||
/// validators. https://tools.ietf.org/html/rfc7232#section-5
|
||||
if entry.Attr.Mtime.IsZero() {
|
||||
return false
|
||||
}
|
||||
w.Header().Set("Last-Modified", entry.Attr.Mtime.UTC().Format(http.TimeFormat))
|
||||
|
||||
ifMatchETagHeader := r.Header.Get("If-Match")
|
||||
ifUnmodifiedSinceHeader := r.Header.Get("If-Unmodified-Since")
|
||||
if ifMatchETagHeader != "" {
|
||||
if util.CanonicalizeETag(etag) != util.CanonicalizeETag(ifMatchETagHeader) {
|
||||
w.WriteHeader(http.StatusPreconditionFailed)
|
||||
return true
|
||||
}
|
||||
} else if ifUnmodifiedSinceHeader != "" {
|
||||
if t, parseError := time.Parse(http.TimeFormat, ifUnmodifiedSinceHeader); parseError == nil {
|
||||
if t.Before(entry.Attr.Mtime) {
|
||||
w.WriteHeader(http.StatusPreconditionFailed)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ifNoneMatchETagHeader := r.Header.Get("If-None-Match")
|
||||
ifModifiedSinceHeader := r.Header.Get("If-Modified-Since")
|
||||
if ifNoneMatchETagHeader != "" {
|
||||
if util.CanonicalizeETag(etag) == util.CanonicalizeETag(ifNoneMatchETagHeader) {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return true
|
||||
}
|
||||
} else if ifModifiedSinceHeader != "" {
|
||||
if t, parseError := time.Parse(http.TimeFormat, ifModifiedSinceHeader); parseError == nil {
|
||||
if t.After(entry.Attr.Mtime) {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (fs *FilerServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
path := r.URL.Path
|
||||
@ -61,10 +119,8 @@ func (fs *FilerServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
// set etag
|
||||
etag := filer.ETagEntry(entry)
|
||||
if ifm := r.Header.Get("If-Match"); ifm != "" && (ifm != "\""+etag+"\"" && ifm != etag) {
|
||||
w.WriteHeader(http.StatusPreconditionFailed)
|
||||
if checkPreconditions(w, r, entry) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -81,19 +137,6 @@ func (fs *FilerServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request)
|
||||
w.Header().Set("Content-Type", mimeType)
|
||||
}
|
||||
|
||||
// if modified since
|
||||
if !entry.Attr.Mtime.IsZero() {
|
||||
w.Header().Set("Last-Modified", entry.Attr.Mtime.UTC().Format(http.TimeFormat))
|
||||
if r.Header.Get("If-Modified-Since") != "" {
|
||||
if t, parseError := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); parseError == nil {
|
||||
if !t.Before(entry.Attr.Mtime) {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print out the header from extended properties
|
||||
for k, v := range entry.Extended {
|
||||
if !strings.HasPrefix(k, "xattr-") {
|
||||
@ -123,10 +166,6 @@ func (fs *FilerServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request)
|
||||
w.Header().Set(xhttp.AmzTagCount, strconv.Itoa(tagCount))
|
||||
}
|
||||
|
||||
if inm := r.Header.Get("If-None-Match"); inm == "\""+etag+"\"" {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
setEtag(w, etag)
|
||||
|
||||
filename := entry.Name()
|
||||
|
@ -61,3 +61,8 @@ func ParseHostPort(hostPort string) (filerServer string, filerPort int64, err er
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func CanonicalizeETag(etag string) string {
|
||||
canonicalETag := strings.TrimPrefix(etag, "\"")
|
||||
return strings.TrimSuffix(canonicalETag, "\"")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user