mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-06-09 18:32:43 +00:00
s3api: reject malformed Range offsets (#10034)
This commit is contained in:
@@ -190,14 +190,22 @@ func (s3a *S3ApiServer) parseAndValidateRange(w http.ResponseWriter, r *http.Req
|
||||
endOffset = totalSize - 1
|
||||
|
||||
if parts[0] != "" {
|
||||
if parsed, err := strconv.ParseInt(parts[0], 10, 64); err == nil {
|
||||
startOffset = parsed
|
||||
parsed, parseErr := strconv.ParseInt(parts[0], 10, 64)
|
||||
if parseErr != nil {
|
||||
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", totalSize))
|
||||
s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRange)
|
||||
return 0, 0, false, newStreamErrorWithResponse(fmt.Errorf("invalid range start: %w", parseErr))
|
||||
}
|
||||
startOffset = parsed
|
||||
}
|
||||
if parts[1] != "" {
|
||||
if parsed, err := strconv.ParseInt(parts[1], 10, 64); err == nil {
|
||||
endOffset = parsed
|
||||
parsed, parseErr := strconv.ParseInt(parts[1], 10, 64)
|
||||
if parseErr != nil {
|
||||
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", totalSize))
|
||||
s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRange)
|
||||
return 0, 0, false, newStreamErrorWithResponse(fmt.Errorf("invalid range end: %w", parseErr))
|
||||
}
|
||||
endOffset = parsed
|
||||
}
|
||||
|
||||
// Special case: range requests on empty files should return 416
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package s3api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
)
|
||||
|
||||
func TestParseAndValidateRangeRejectsMalformedNumericOffsets(t *testing.T) {
|
||||
s3a := &S3ApiServer{}
|
||||
entry := &filer_pb.Entry{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
rangeHeader string
|
||||
}{
|
||||
{"invalid start", "bytes=abc-5"},
|
||||
{"invalid end", "bytes=5-abc"},
|
||||
{"invalid open ended start", "bytes=abc-"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/bucket/object", nil)
|
||||
req.Header.Set("Range", tt.rangeHeader)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
_, _, _, streamErr := s3a.parseAndValidateRange(rec, req, entry, 100, "bucket", "object")
|
||||
if streamErr == nil {
|
||||
t.Fatalf("parseAndValidateRange(%q) error = nil, want invalid range error", tt.rangeHeader)
|
||||
}
|
||||
if rec.Code != http.StatusRequestedRangeNotSatisfiable {
|
||||
t.Fatalf("parseAndValidateRange(%q) status = %d, want %d", tt.rangeHeader, rec.Code, http.StatusRequestedRangeNotSatisfiable)
|
||||
}
|
||||
if got := rec.Header().Get("Content-Range"); got != "bytes */100" {
|
||||
t.Fatalf("parseAndValidateRange(%q) Content-Range = %q, want %q", tt.rangeHeader, got, "bytes */100")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user