mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-21 13:34:26 +02:00
s3: return IncompleteBody instead of 500 for truncated PUT bodies (#10186)
* s3: add IncompleteBody error code * operation: tag a truncated source read as ErrTruncatedBody The chunked uploader wraps both source-read failures and volume-upload failures, and a mid-write volume server drop also carries io.ErrUnexpectedEOF. Tag only the source read so callers can tell a truncated input apart from a server-side fault. * s3: return IncompleteBody for a truncated PUT body A client abort or reverse-proxy timeout truncates the request body mid-upload. putToFiler mapped every streaming-upload failure to InternalError (500), which a reverse proxy relays as a 502. Classify a source-read truncation as IncompleteBody (400) so the response matches AWS and passes through. All S3 write paths share putToFiler, so they all benefit.
This commit is contained in:
1 parent
cf64cafc3b
commit
155140bed8
5 files changed
+128
-4
No files matched your search
@@ -545,10 +545,7 @@ func (s3a *S3ApiServer) putToFiler(r *http.Request, filePath string, dataReader
|
||||
s3a.deleteOrphanedChunks(chunkResult.FileChunks)
|
||||
}
|
||||
|
||||
if strings.Contains(err.Error(), s3err.ErrMsgPayloadChecksumMismatch) {
|
||||
return "", s3err.ErrInvalidDigest, SSEResponseMetadata{}
|
||||
}
|
||||
return "", s3err.ErrInternalError, SSEResponseMetadata{}
|
||||
return "", mapChunkedUploadErrorToS3Error(err), SSEResponseMetadata{}
|
||||
}
|
||||
|
||||
// Step 3: Calculate MD5 hash and add SSE metadata to chunks
|
||||
@@ -1170,6 +1167,22 @@ func filerErrorToS3Error(err error) s3err.ErrorCode {
|
||||
}
|
||||
}
|
||||
|
||||
// mapChunkedUploadErrorToS3Error classifies a failed streaming upload. A truncated
|
||||
// request body (client abort or reverse-proxy timeout) is a request error, so report
|
||||
// IncompleteBody (400) rather than a 500 a reverse proxy would relay as a confusing
|
||||
// 502. Only the source read is tagged, so a volume-server upload fault still maps to
|
||||
// InternalError.
|
||||
func mapChunkedUploadErrorToS3Error(err error) s3err.ErrorCode {
|
||||
switch {
|
||||
case strings.Contains(err.Error(), s3err.ErrMsgPayloadChecksumMismatch):
|
||||
return s3err.ErrInvalidDigest
|
||||
case errors.Is(err, operation.ErrTruncatedBody):
|
||||
return s3err.ErrIncompleteBody
|
||||
default:
|
||||
return s3err.ErrInternalError
|
||||
}
|
||||
}
|
||||
|
||||
// setObjectOwnerFromRequest sets the object owner metadata based on the bucket ownership policy.
|
||||
// When BucketOwnerEnforced (the modern AWS default), the bucket owner owns all objects.
|
||||
// Otherwise, the uploader's account ID is used (ObjectWriter mode).
|
||||
|
||||
Reference in new issue
Block a user