Browse Source

Fix Headers Being Set After WriteHeader

pull/7481/head
chrislu 1 month ago
parent
commit
cdfe61e389
  1. 65
      weed/s3api/s3api_object_handlers.go

65
weed/s3api/s3api_object_handlers.go

@ -600,8 +600,9 @@ func (s3a *S3ApiServer) streamFromVolumeServers(w http.ResponseWriter, r *http.R
startOffset = totalSize - suffixLen startOffset = totalSize - suffixLen
endOffset = totalSize - 1 endOffset = totalSize - 1
} else { } else {
w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
// Set header BEFORE WriteHeader
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", totalSize)) w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", totalSize))
w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
return fmt.Errorf("invalid suffix range") return fmt.Errorf("invalid suffix range")
} }
} else { } else {
@ -622,8 +623,9 @@ func (s3a *S3ApiServer) streamFromVolumeServers(w http.ResponseWriter, r *http.R
// Validate range // Validate range
if startOffset < 0 || startOffset >= totalSize { if startOffset < 0 || startOffset >= totalSize {
w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
// Set header BEFORE WriteHeader
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", totalSize)) w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", totalSize))
w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
return fmt.Errorf("invalid range start") return fmt.Errorf("invalid range start")
} }
@ -632,8 +634,9 @@ func (s3a *S3ApiServer) streamFromVolumeServers(w http.ResponseWriter, r *http.R
} }
if endOffset < startOffset { if endOffset < startOffset {
w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
// Set header BEFORE WriteHeader
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", totalSize)) w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", totalSize))
w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
return fmt.Errorf("invalid range: end before start") return fmt.Errorf("invalid range: end before start")
} }
} }
@ -641,31 +644,26 @@ func (s3a *S3ApiServer) streamFromVolumeServers(w http.ResponseWriter, r *http.R
offset = startOffset offset = startOffset
size = endOffset - startOffset + 1 size = endOffset - startOffset + 1
isRangeRequest = true isRangeRequest = true
// Set range response headers
w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", startOffset, endOffset, totalSize))
w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
w.WriteHeader(http.StatusPartialContent)
} }
} }
rangeParseTime = time.Since(tRangeParse) rangeParseTime = time.Since(tRangeParse)
// Set standard HTTP headers from entry metadata (but not Content-Length if range request)
// Set standard HTTP headers from entry metadata
// IMPORTANT: Set ALL headers BEFORE calling WriteHeader (headers are ignored after WriteHeader)
tHeaderSet := time.Now() tHeaderSet := time.Now()
if !isRangeRequest {
s3a.setResponseHeaders(w, entry, totalSize)
} else {
// For range requests, set headers without Content-Length (already set above)
if etag := filer.ETag(entry); etag != "" {
w.Header().Set("ETag", "\""+etag+"\"")
}
if entry.Attributes != nil {
modTime := time.Unix(entry.Attributes.Mtime, 0).UTC()
w.Header().Set("Last-Modified", modTime.Format(http.TimeFormat))
}
w.Header().Set("Accept-Ranges", "bytes")
s3a.setResponseHeaders(w, entry, totalSize)
// Override/add range-specific headers if this is a range request
if isRangeRequest {
w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", offset, offset+size-1, totalSize))
w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
} }
headerSetTime = time.Since(tHeaderSet) headerSetTime = time.Since(tHeaderSet)
// Now write status code (headers are all set)
if isRangeRequest {
w.WriteHeader(http.StatusPartialContent)
}
// For small files stored inline in entry.Content // For small files stored inline in entry.Content
if len(entry.Content) > 0 && totalSize == int64(len(entry.Content)) { if len(entry.Content) > 0 && totalSize == int64(len(entry.Content)) {
@ -919,27 +917,22 @@ func (s3a *S3ApiServer) streamFromVolumeServersWithSSE(w http.ResponseWriter, r
keyValidateTime = time.Since(tKeyValidate) keyValidateTime = time.Since(tKeyValidate)
// Set response headers // Set response headers
// IMPORTANT: Set ALL headers BEFORE calling WriteHeader (headers are ignored after WriteHeader)
tHeaderSet := time.Now() tHeaderSet := time.Now()
s3a.setResponseHeaders(w, entry, totalSize)
s3a.addSSEResponseHeadersFromEntry(w, r, entry, sseType)
// Override/add range-specific headers if this is a range request
if isRangeRequest { if isRangeRequest {
// Set range-specific headers
w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", offset, offset+size-1, totalSize)) w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", offset, offset+size-1, totalSize))
w.Header().Set("Content-Length", strconv.FormatInt(size, 10)) w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
// Set basic headers without Content-Length override
if etag := filer.ETag(entry); etag != "" {
w.Header().Set("ETag", "\""+etag+"\"")
}
if entry.Attributes != nil {
modTime := time.Unix(entry.Attributes.Mtime, 0).UTC()
w.Header().Set("Last-Modified", modTime.Format(http.TimeFormat))
}
w.Header().Set("Accept-Ranges", "bytes")
s3a.addSSEResponseHeadersFromEntry(w, r, entry, sseType)
w.WriteHeader(http.StatusPartialContent)
} else {
s3a.setResponseHeaders(w, entry, totalSize)
s3a.addSSEResponseHeadersFromEntry(w, r, entry, sseType)
} }
headerSetTime = time.Since(tHeaderSet) headerSetTime = time.Since(tHeaderSet)
// Now write status code (headers are all set)
if isRangeRequest {
w.WriteHeader(http.StatusPartialContent)
}
// Full Range Optimization: Use ViewFromChunks to only fetch/decrypt needed chunks // Full Range Optimization: Use ViewFromChunks to only fetch/decrypt needed chunks
tDecryptSetup := time.Now() tDecryptSetup := time.Now()

Loading…
Cancel
Save