mirror of
https://github.com/caddyserver/caddy.git
synced 2026-11-06 02:03:39 -05:00
method-matcher-case
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
30d3bd2a89 |
caddyhttp: only bound HTTP/2 body reads in flight with the idle timeout (#8125)
* caddyhttp: only bound HTTP/2 body reads in flight with the idle timeout On HTTP/2, the read deadline is a timer that fails the request body when it fires, even with no read in flight. IdleTimeoutReader left the idle deadline armed between reads, so a handler that stopped reading for longer than read_body_idle (1 minute by default) lost the body, although the client was only held back by flow control. For example, reverse_proxy uploading to an upstream that's slow to accept the body failed with a 502. This is the read side of #8118. Like IdleTimeoutWriter does since read on HTTP/2, so the idle deadline only bounds reads in flight. A client that stops sending is still cut off, since the deadline is set before each read. HTTP/1 and HTTP/3 only check the deadline during a read, so they're unchanged. Written with Claude Code (Claude Opus 5.5); the human submitter is responsible for reviewing it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * caddyhttp: track a released hard read deadline as armed From review: with HardDeadline set, releasing the idle deadline between reads left an HTTP/2 timer armed (at HardDeadline) while deadlineSet recorded that none was, so clearDeadlineLocked would skip clearing it. Track which deadline is armed (none, idle, or only the hard one) instead of a bool, and have each check ask the question it means: re-arming and releasing only apply to an armed idle deadline, while clearing applies to any. The writer's deadlineSet already only means "idle deadline armed", since nothing clears the hard deadline it leaves; document that. Written with Claude Code (Claude Opus 5.5); the human submitter is responsible for reviewing it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * caddyhttp: clear released hard deadline at handler end, skip no-op sets From review: - After a partial read releases the idle deadline to HardDeadline, a handler that returns without reading again left that timer armed past HandlerDone, which only cleared after a terminal error. HandlerDone now also clears a released hard deadline. - When the idle deadline is capped to HardDeadline, the reader and writer set the same deadline again when releasing it, and the writer once more in HandlerDone. On HTTP/2 each is a message to the serve loop. Both now remember the deadline they armed and skip setting it again. Within a request, only these wrappers set the client's deadlines. Replaces the earlier test that faked a terminal error with the partial read followed directly by HandlerDone. Written with Claude Code (Claude Opus 5.5); the human submitter is responsible for reviewing it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * caddyhttp: only skip re-setting an armed hard deadline Skipping any deadline equal to the one already armed also skipped idle deadlines on Windows, where two calls to time.Now in the same clock tick return the same time, so successive idle deadlines can be equal. That broke tests counting deadline calls there. Only skip HardDeadline, the case from review where the idle deadline is capped to it; other deadlines are always set. Written with Claude Code (Claude Opus 5.5); the human submitter is responsible for reviewing it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * caddyhttp: restore deadlines without trusting cached transport state Always set the requested read and write deadlines because another handler can change them through its own response controller. Remove the armedAt shortcut and cover intervening deadline changes for reads, writes, ReadFrom, flushes, and HandlerDone. AI-assisted with OpenAI Codex (GPT-6); tested under human direction. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
8f549e6df1 |
timeouts: take precedence over server-wide and enclosing idle timeouts (#8121)
* timeouts: take precedence over server-wide and enclosing idle timeouts The timeouts handler wrapped the request body and response writer again, on top of the server's own idle timeout wrappers. The wrapper closest to the connection sets the deadline last, so the server-wide read_body_idle and write_idle (on by default since 2.11.6) silently overrode the route's settings. The same happened between nested timeouts handlers, where the outer, less specific one won. The server now makes its idle timeout wrappers available through the request context, and the timeouts handler overrides their settings while it runs, restoring them when it returns. It only wraps when there's nothing to override, and then registers its own wrappers so that nested handlers override those. The server-wide read_timeout and write_timeout still cap the whole transfer. A handler that doesn't set max_write_chunk keeps the server-wide one. Written with Claude Code (Claude Opus 5.5); the human submitter is responsible for reviewing it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * timeouts: re-arm deadlines on override and suspend outer min-rate window From review: - On HTTP/2, a read or write deadline is a timer that fires even with no read or write in flight. A deadline armed before a timeouts handler started kept the outer timeout and could fail the body (or reset the stream) inside a longer inner scope before the next read reset it. Override and restore now move an armed deadline to the settings that apply. - Time spent under an override counted against the outer MinRate window, so the restored deadline could already have expired. The outer window is now suspended while overridden: its start moves forward by the time spent overridden, and bytes transferred in the meantime don't count towards it. Adds an HTTP/2 read-before-inner-scope regression test and nested minimum-rate coverage. Written with Claude Code (Claude Opus 5.5); the human submitter is responsible for reviewing it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
72dd0fb067 |
timeouts: fix idle writer terminate h2 response writers between writes (#8119)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Francis Lavoie <lavofr@gmail.com> |
||
|
|
ab7e6b6d81 |
caddyhttp: end request-body deadline ownership with handler (#8107)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Francis Lavoie <lavofr@gmail.com> |
||
|
|
0cf03d32f7 |
caddyhttp: mitigate slowloris via idle read/write deadlines (#7913)
* caddyhttp: mitigate slowloris via idle read/write deadlines ReadTimeout and WriteTimeout previously applied as a single hard deadline over the whole body/response through http.Server, so any non-zero value also killed large transfers from legitimately slow clients. Reset the deadline on every successful read/write instead (via http.ResponseController), and give both a sane 1m default now that doing so no longer penalizes slow-but-progressing clients. * caddyhttp: split idle read/write timeouts from the existing hard ones Reworking ReadTimeout/WriteTimeout's own semantics was an unwanted behavior change for existing configs relying on the hard deadline. Leave them untouched and add ReadIdleTimeout/WriteIdleTimeout instead, reset on every successful read/write; both default to 1m since, being new, no existing config could have depended on a different value. Combining an idle timeout with its hard counterpart now gives the same base+ceiling shape as Apache's mod_reqtimeout, for free. * caddyhttp: cap idle-reset deadlines at the hard timeout ceiling Deadlines are a single absolute value on the connection, not a min of several: ReadTimeout/WriteTimeout's own hard deadline, set once by net/http before the handler runs, was silently getting overwritten by the first idle-reset Read/Write, voiding it entirely. Clamp the idle-reset deadline to the hard one when both are set, so combining them actually behaves like the advertised base+ceiling. * caddyhttp: add ReadMinRate/WriteMinRate, Apache MinRate equivalent Pure idle-reset alone doesn't bound a trickle that sends just enough to never go idle. ReadMinRate/WriteMinRate (bytes/second) grow the allowed deadline from a fixed start based on bytes transferred so far instead of resetting to a flat window on every call, so a transfer that doesn't sustain the configured rate falls behind real time and gets cut, matching Apache mod_reqtimeout's MinRate. Zero (default) keeps the existing flat idle-reset behavior unchanged. * caddyhttp: use named return and consistent blank lines in idleDeadline Matches the named-return style already used by ResponseWriterWrapper.ReadFrom. * caddyhttp: chunk idleTimeoutWriter's Write/ReadFrom, cap at 64 KiB SetWriteDeadline bounds the whole call it precedes, not just a stall within it. net.Conn.Write loops internally until a buffer is fully sent (unlike Read, which returns after one syscall), and ResponseWriter.ReadFrom hands the entire remaining source to the connection in one call. A single large Write, or any body copied via io.Copy triggering the ReadFrom fast path (http.ServeContent, static file serving), had its whole transfer bounded by one deadline, silently truncating a slow-but-healthy transfer exactly like a hard WriteTimeout would - the same bug found and fixed the same way in FrankenPHP's go_ub_write (php/frankenphp#2574). Cap each underlying call at 64 KiB and reset the deadline between chunks instead. net/sendfile.go special-cases *io.LimitedReader, so chunking ReadFrom still uses the sendfile fast path per chunk. * caddyhttp: export idle-timeout types, add configurable MaxWriteChunk Export IdleTimeoutReader/IdleTimeoutWriter/IdleDeadline so other packages (request_body next) can reuse the same idle-reset mechanism instead of reimplementing it, and turn the hardcoded 64 KiB write chunk size into a configurable MaxWriteChunk field defaulting to the same value - nginx's sendfile_max_chunk exists for the identical reason and is admin-tunable rather than fixed. * requestbody: idle-reset ReadTimeout/WriteTimeout, add MinRate/MaxWriteChunk ReadTimeout/WriteTimeout set a single deadline once, so any transfer running longer than the timeout got cut regardless of whether it was actually stalled - the same bug the server-wide timeouts had before switching to idle-reset. Reuse caddyhttp.IdleTimeoutReader/Writer here too, giving per-route granularity nginx/Apache have via location/ directory scoping and Caddy's server-wide timeouts don't: a route matching this handler can now set its own idle window independently from the rest of the server block. * caddyhttp: fold read/write min_rate into the idle-timeout directive Two directives per rate (read_body_idle + read_body_min_rate) for a value that's meaningless without the other. Fold min_rate into the idle-timeout directive as an optional second argument instead. * caddyhttp: split write pacing out of request_body into new timeouts handler request_body is a request-body concern (max_size, set); ReadTimeout/ WriteTimeout/MinRate/MaxWriteChunk pace both directions, and write pacing has nothing to do with the request body. Move all of it to a dedicated http.handlers.timeouts module instead, mirroring the server-wide timeouts option one level down. |