fix(webdav): stabilize fallback ETags

- Use second-precision modification times for reproducible fallback ETags
- Cover ETag stability across cache refresh timestamp normalization

Co-authored-by: Codex <267193182+codex@users.noreply.github.com>
Signed-off-by: jyxjjj <16695261+jyxjjj@users.noreply.github.com>
This commit is contained in:
jyxjjj
2026-09-20 00:55:25 +08:00
parent 9b75a0c21c
commit f75e79047a
2 changed files with 14 additions and 12 deletions
+11 -10
View File
@@ -8,18 +8,19 @@ import (
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
)
func TestGetEtagSubsecondChanges(t *testing.T) {
file := &model.Object{Size: 4, Modified: time.Unix(1700000000, 100)}
before := GetEtag(file, file.Size)
if got := GetEtag(file, file.Size); got != before {
t.Fatalf("unchanged file ETag = %q, want %q", got, before)
func TestGetEtagStableAcrossCacheRefresh(t *testing.T) {
uploaded := &model.Object{Size: 4, Modified: time.Unix(1700000000, 123456789)}
before := GetEtag(uploaded, uploaded.Size)
refreshed := &model.Object{Size: uploaded.Size, Modified: time.Unix(1700000000, 0)}
if got := GetEtag(refreshed, refreshed.Size); got != before {
t.Fatalf("refreshed file ETag = %q, want %q", got, before)
}
file.Modified = file.Modified.Add(time.Nanosecond)
if got := GetEtag(file, file.Size); got == before {
t.Errorf("same-size overwrite within one second retained ETag %q", got)
refreshed.Modified = refreshed.Modified.Add(time.Second)
if got := GetEtag(refreshed, refreshed.Size); got == before {
t.Errorf("changed modification second retained ETag %q", got)
}
file.Modified = file.Modified.Add(-time.Nanosecond)
if got := GetEtag(file, file.Size+1); got == before {
refreshed.Modified = uploaded.Modified
if got := GetEtag(refreshed, refreshed.Size+1); got == before {
t.Errorf("changed size retained ETag %q", got)
}
}
+3 -2
View File
@@ -97,8 +97,9 @@ func GetEtag(file model.Obj, size int64) string {
if len(hash) > 0 {
return fmt.Sprintf(`"%s"`, hash)
}
// Preserve sub-second changes when files of the same size are overwritten.
return fmt.Sprintf(`"%x-%x"`, file.ModTime().UnixNano(), size)
// Storage backends may not preserve sub-second timestamps across cache
// refreshes, so only use the reproducible second precision here.
return fmt.Sprintf(`"%x-%x"`, file.ModTime().Unix(), size)
}
func ProxyRange(ctx context.Context, link *model.Link, size int64) *model.Link {