aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lu <chrislusf@users.noreply.github.com>2022-02-07 18:32:16 -0800
committerGitHub <noreply@github.com>2022-02-07 18:32:16 -0800
commita2ac540ecc765689fb75f0f97c0260570a586500 (patch)
treeb97105e65640be5bdd9727936ea3a9157b462565
parentb1cff07ab0541200b26d345d1d396fddcba66d79 (diff)
parent7f0c79308309660b9e0c7e04e90b9c199bd67839 (diff)
downloadseaweedfs-a2ac540ecc765689fb75f0f97c0260570a586500.tar.xz
seaweedfs-a2ac540ecc765689fb75f0f97c0260570a586500.zip
Merge pull request #2645 from guol-fnst/fix_Precedence
fix preconditions
-rw-r--r--weed/server/filer_server_handlers_read.go79
-rw-r--r--weed/util/parse.go5
2 files changed, 64 insertions, 20 deletions
diff --git a/weed/server/filer_server_handlers_read.go b/weed/server/filer_server_handlers_read.go
index 56aee18be..8037b1d94 100644
--- a/weed/server/filer_server_handlers_read.go
+++ b/weed/server/filer_server_handlers_read.go
@@ -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()
diff --git a/weed/util/parse.go b/weed/util/parse.go
index 0955db682..502f3a80f 100644
--- a/weed/util/parse.go
+++ b/weed/util/parse.go
@@ -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, "\"")
+}