mirror of
https://github.com/ferdzo/fs.git
synced 2026-08-03 01:06:47 +00:00
Avoid truncating large uploads with body timeouts
http.Server.ReadTimeout and WriteTimeout cover the full request/ response lifetime including streaming bodies, so finite values truncate large object PUTs and GETs mid-flight. Disable both and rely on ReadHeaderTimeout (header phase) and IdleTimeout (between keepalive requests), consistent with how S3-style streaming servers behave. serverMaxConnections still bounds concurrent load. Also log io.Copy errors in handleGetObject so a client disconnect or mid-stream chunk failure is no longer invisible.
This commit is contained in:
26
api/api.go
26
api/api.go
@@ -43,11 +43,17 @@ const (
|
|||||||
maxObjectKeyBytes = 1024
|
maxObjectKeyBytes = 1024
|
||||||
maxAWSChunkedLineBytes = 8 << 10
|
maxAWSChunkedLineBytes = 8 << 10
|
||||||
serverReadHeaderTimeout = 5 * time.Second
|
serverReadHeaderTimeout = 5 * time.Second
|
||||||
serverReadTimeout = 60 * time.Second
|
// serverReadTimeout and serverWriteTimeout are disabled on purpose: both
|
||||||
serverWriteTimeout = 120 * time.Second
|
// cover the full request/response lifetime including streaming bodies, so a
|
||||||
serverIdleTimeout = 120 * time.Second
|
// finite value truncates large uploads and downloads mid-flight. Read and
|
||||||
serverMaxHeaderBytes = 1 << 20
|
// idle liveness are still enforced by serverReadHeaderTimeout (header
|
||||||
serverMaxConnections = 1024
|
// phase) and serverIdleTimeout (between keepalive requests), and concurrent
|
||||||
|
// load is bounded by serverMaxConnections.
|
||||||
|
serverReadTimeout = 0
|
||||||
|
serverWriteTimeout = 0
|
||||||
|
serverIdleTimeout = 120 * time.Second
|
||||||
|
serverMaxHeaderBytes = 1 << 20
|
||||||
|
serverMaxConnections = 1024
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewHandler(svc *service.ObjectService, logger *slog.Logger, logConfig logging.Config, authSvc *auth.Service, adminAPI bool) *Handler {
|
func NewHandler(svc *service.ObjectService, logger *slog.Logger, logConfig logging.Config, authSvc *auth.Service, adminAPI bool) *Handler {
|
||||||
@@ -271,8 +277,14 @@ func (h *Handler) handleGetObject(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set("Last-Modified", time.Unix(manifest.CreatedAt, 0).UTC().Format(http.TimeFormat))
|
w.Header().Set("Last-Modified", time.Unix(manifest.CreatedAt, 0).UTC().Format(http.TimeFormat))
|
||||||
w.Header().Set("Accept-Ranges", "bytes")
|
w.Header().Set("Accept-Ranges", "bytes")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, err = io.Copy(w, stream)
|
if _, err = io.Copy(w, stream); err != nil && !errors.Is(err, context.Canceled) {
|
||||||
|
h.logger.Warn("get_object_stream_failed",
|
||||||
|
"bucket", bucket,
|
||||||
|
"key", key,
|
||||||
|
"etag", manifest.ETag,
|
||||||
|
"error", err,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) handlePostObject(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) handlePostObject(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
Reference in New Issue
Block a user