51 Commits
Author SHA1 Message Date
Chris Oliver 553b62c3f3 reverseproxy: send every close message before closing tunnel connections (#8371)
Closing one side of a tunnel ends its copy loops, which close the other
side. closeConnectionsLocked sent each close message and closed that
connection before moving on, in map order, so when the client side came
first the upstream was often closed before its close message went out.
Send every close message in the batch first, then close the connections.

The second close then regularly finds the connection already closed.
Treat net.ErrClosed as expected instead of returning it, so reloads with
open websockets no longer log "use of closed network connection" at
ERROR level.

The upstream close message test goes back to running the real cleanup,
which it can now do reliably.
2026-11-08 11:05:28 +00:00
Chris Oliver b3d67c861d reverseproxy: set a write deadline on websocket close messages (#8309)
* reverseproxy: set a write deadline on websocket close messages

Cleanup sends a Close control message to every attached websocket while
holding the tunnel tracker lock, during a config reload. If the peer has
stopped reading, the tunnel's copy goroutine is blocked writing to it and
the close message waits behind that write forever. The reload never
finishes and holds the config lock, so every later /load and /config
request hangs until Caddy is restarted.

Setting a write deadline before the close message unblocks both writes.
The connection is closed right after, so the deadline is never cleared.

* Add bot disclosure

* reverseproxy: make close control timeout a const, harden stalled-peer test

* Delete BOT_DISCLOSURE.md

Signed-off-by: Francis Lavoie <lavofr@gmail.com>

* reverseproxy: bound each batch of websocket close messages by one deadline

The close loops are serial and hold the tunnel tracker lock, so a
per-connection write timeout let N stalled peers hold a reload for N
times the timeout. Compute one absolute deadline per batch instead,
and skip the best-effort close frame on connections that cannot set a
write deadline rather than risk the hang.

Extended CONNECT streams gain SetWriteDeadline through
http.ResponseController. For HTTP/1 upgrades, net/http returns the
upstream socket inside a body that hides its deadline methods, so the
upstream close message was never bounded; record the connection from
the request's ClientTrace and write the close message to that socket.

Restores the TODO about being the exclusive writer, per review.

* reverseproxy: make websocket close tests deterministic

Per review, the stalled-peer tests use net.Pipe instead of real TCP:
it is unbuffered and lets one write through at a time, so a close
message waits behind a stuck copy write without large allocations or
sleeps. The batch test checks that graceful closes share one deadline
instead of timing cleanup.

The HTTP/1 upstream close test now runs a real upgrade through
ServeHTTP and the transport, so it fails if the GotConn hook is
removed. The choice of upstream close writer moves into
upstreamCloseWriter, with a table test for the HTTP/2 and HTTP/3 case.

* reverseproxy: record the upstream conn with atomic.Pointer

Per review, store the connection from the GotConn hook in an
atomic.Pointer[net.Conn] instead of a mutex-guarded holder type.

Rename upstreamCloseWriter to upstreamWriteCloser. It returns
io.ReadWriteCloser, since both the body and the recorded socket are
one, so gracefulClose keeps its original io.ReadWriteCloser parameter.

* reverseproxy: share one close deadline across detached trackers

Per review, an upstream removal notifies every stopped tracker in
turn, and each close loop holds its own lock, so a deadline per
tracker let N trackers with stalled peers hold a reload for N times
the timeout. Compute one absolute deadline in
notifyDetachedTunnelTrackersOfUpstreamRemoval and pass it through to
closeConnectionsForUpstream.

Add a test with two stopped trackers holding stalled net.Pipe peers
that asserts both graceful closes receive the same deadline.

* reverseproxy: simplify the websocket close deadline change

Fold the two tunnel close loops into closeConnectionsLocked, so the
shared-deadline rule and its rationale live in one place. Replace the
per-tracker closeWriteTimeout field, which production never varied,
with a package variable that tests shorten.

Record the upstream socket only for websocket requests, since only
their graceful close reads it, and store a copy of the connection
rather than the address of the hook's parameter. Use the package's
caddy.CtxKey convention for the context key.

Share the upgrade tunnel fixture between the half-close test and the
upstream close message test.
2026-11-06 10:49:16 +00:00
Suganraj 0da7b08e81 reverseproxy: remove unreachable isBidirectionalStream (#8366) 2026-11-06 10:46:43 +00:00
Zen Dodd f4d9826bf2 reverseproxy: simplify WebSocket header handling (#8365) 2026-11-05 04:45:23 -05:00
Zen Dodd fbfc061e70 caddyhttp: detach streams at the server writer boundary (#8346) 2026-11-04 17:36:00 +10:00
Kévin DunglasandKağan Küçük 857d5731f3 caddyhttp: optimise header access and fix encoding negotiation (#8025)
* perf: bypass header key normalization for canonical literals

http.Header's Get, Set, Add and Del run textproto.CanonicalMIMEHeaderKey
on every call. When the key is a canonical literal the result is the key
itself, so the scan is pure overhead. Access the map directly instead.

Only hot, allocation-free paths are converted, and only where the key is
a canonical literal. Call sites taking a key from config, a template or
the request itself still go through the normalizing methods, since they
need it for correctness.

allHeaderValues and lastHeaderValue dropped their http.CanonicalHeaderKey
call for the same reason: all callers pass canonical literals.

benchstat, Apple M5 Pro, go1.27.1:

    PrepareRequest-15      659.4n ± 2%  ->  457.7n ± 2%  -30.58% (p=0.000 n=12)
    AcceptedEncodings-15   330.8n ± 5%  ->  309.4n ± 7%   -6.44% (p=0.019 n=10)

    ResponseWriterWriteHeader/event-stream-15    1007.5n ± 3%  ->  732.5n ± 1%  -27.30%
    ResponseWriterWriteHeader/informational-15     60.0n ± 3%  ->   48.0n ± 2%  -20.01%
    ResponseWriterWriteHeader/not-modified-15     214.3n ± 6%  ->  175.3n ± 4%  -18.20%
    ResponseWriterWriteHeader/connect-15           60.2n ± 3%  ->   51.9n ± 4%  -13.85%
    ResponseWriterWriteHeader/html-15             206.5n ± 4%  ->  197.9n ± 2%   -4.19%
    geomean                                                                    -14.38%

Allocations are unchanged.

* tests: verify http.Header map keys are canonical

Indexing http.Header directly skips the canonicalization Get/Set/Add/Del
perform, which also puts the key outside what CI checks. canonicalheader
only inspects method calls. staticcheck's SA1008 covers reads, but stops
descending as soon as an assignment writes to a header, so it misses the
write, the delete builtin and the read-modify-write append. A key that is
not canonical in those positions is a silent lookup miss, not a compile
error.

Walk the loaded packages and verify every string constant used as a key in
an http.Header map operation matches http.CanonicalHeaderKey. A helper that
takes the key from its caller would hide the literal again, so a parameter
named with a canonical prefix opts its arguments into the same check.

The WebSocket headers Caddy deliberately writes with RFC 6455 casing are
allowed explicitly; they are only ever written out, never looked up against
a parsed header map.

Covers 64 operations, runs in under a second, and promotes golang.org/x/tools
from an indirect to a direct dependency at the version already in the module
graph.

* headercheck: resolve aliases of http.Header

* headercheck: check http.Header composite literal keys

* headercheck: note overlap with canonicalheader

* headercheck: drop parameter-name check

Helpers now take the indexed values, so every key sits in an index expression the analyzer and the linter already check.

* headercheck: scope RFC 6455 exceptions to their call sites

A key-based allow-list also accepted reads such as h["Sec-WebSocket-Key"], which miss because parsed headers are canonical. Honor //nolint:canonicalheader on the line instead, which the linter will use too.

* encode: read every Accept-Encoding field line

AcceptedEncodings read only the first field line, so a client that split
the list across several lines had the rest ignored. RFC 9110 section 5.3
treats repeated list-field lines as one comma-joined list. Iterate over
the items of every line instead of joining them, and skip empty items,
which used to yield an empty encoding. file_server's precompressed
selection uses the same function and is fixed with it.

Fixes https://github.com/caddyserver/caddy/issues/8272

Co-authored-by: Kağan Küçük <kaankck@gmail.com>

* encode: read every Cache-Control and Content-Encoding field line

Only the first field line was read, but RFC 9110 section 5.3 makes
multiple lines of a list-based field equivalent to one comma-joined
value:

- Cache-Control: no-transform on a later line was ignored, so the
  request or response was compressed anyway.
- Content-Encoding: an empty first line followed by a real coding let
  the handler encode the body a second time.

* encode: parse Cache-Control no-transform per RFC 9111

The substring match missed No-Transform, though RFC 9111 section 5.2 compares directive names case-insensitively, and fired on text that is not the directive: longer tokens such as x-no-transform-ext, quoted arguments such as community="no-transform", and semicolon-separated values, which are not valid Cache-Control syntax. Split the field on commas outside quoted strings and match only a well-formed no-transform element.

* encode: keep accepted encoding preferences on the stack

AcceptedEncodings counted commas to size the preference slice, and the variable capacity put it on the heap. A constant capacity covers typical Accept-Encoding headers and lets the compiler keep the slice on the stack; append still moves it to the heap for longer ones. BenchmarkAcceptedEncodings: 151.8ns -> 120.5ns (-21%), 192 -> 64 B/op, 2 -> 1 allocs/op (n=8).

* encode: build the encoded ETag without fmt

fmt.Sprintf boxed both arguments and parsed the format on every encoded response with a strong ETag. Concatenation: 47ns -> 16.5ns, 56 -> 24 B, 3 -> 1 allocs.

* reverseproxy: access response Server and Via headers directly

finalizeResponse runs on every proxied response; skip the key normalization as prepareRequest already does on the request side.

* encode: access headers directly in Write, WriteHeader and Close

These run once per response; convert the remaining literal-key Get, Set and Add calls like the rest of the handler.

* encode: match Cache-Control no-transform with httpguts

httpguts.HeaderValuesContainsToken already compares list elements case-insensitively across field lines, so the hand-written list parser is unnecessary. A no-transform inside a comma-separated quoted argument now also disables encoding, which only errs toward not transforming.

* encode: inline the no-transform check

isEncodeAllowed only wrapped one httpguts call. Its unit test now drives the response directive through ServeHTTP instead.

---------

Co-authored-by: Kağan Küçük <kaankck@gmail.com>
2026-10-29 23:19:50 +10:00
Rob Martin 62bc606433 reverseproxy: close backend body and hijacked socket on upgrade setup failures (#8269)
* reverseproxy: close backend body and hijacked socket on upgrade setup failures

When an upstream response indicates an HTTP upgrade (101 Switching Protocols),
handleUpgradeResponse takes ownership of res.Body and subsequently hijacks
the client connection.

However, if any setup check fails prior to starting handleUpgradeTunnel
(such as mismatched upgrade headers, non-writable body assertion failure,
hijack unsupported, or handshake buffer flush errors), the function returned
early without closing res.Body or the hijacked client socket.

Because calling Hijack() permanently disables net/http's automatic connection
cleanup, and raw TCP sockets are not closed by the garbage collector, these
early failure exits leaked file descriptors into CLOSE_WAIT/ESTABLISHED.

Fix this by:
1. Adding a deferred cleanup guard that closes res.Body and any hijacked
   front connection unless the tunnel successfully takes ownership.
2. Wrapping connections with onceCloseConn to ensure idempotent closure
   while preserving optional CloseWrite (TCP half-close) support.
3. Adding TestUpgradeResponseCleanupOnFailure to verify cleanup.

* reverseproxy: test post-hijack cleanup and remove once-close wrappers

Cover handshake flush and buffered backend-write failures after successful hijacking, checking that both connections close. Keep setup-failure cleanup while using the original connections directly.

Code and tests were AI-assisted using an OpenAI coding assistant in Pi.
2026-10-24 22:19:19 +00:00
Francis Lavoie 8ad83ebd43 reverseproxy: Keep streams attached when writer detachment fails (#8139) 2026-10-04 12:46:34 -04:00
Saleh f7eeb1d65c reverseproxy: log HTTP/3 client cancellations at debug level (#8135) 2026-10-04 12:48:06 +00:00
Francis LavoieandWeidiDeng 7ef5c60ed0 reverseproxy: Optionally detach stream (websockets) from config lifecycle (#7649)
* reverseproxy: Optionally detach stream (websockets) from config lifecycle

* lint

* Improved logging facilities

* Adjustments from Weidi's review

* record bytes read and written for response writers unless detached

* simplify streaming handling

* correctly close detached streams

* make handleUpgradeTunnel a standalone func

* fix tests

* fix tests

* change the log level if hijacking without writing a status code first

* only clean up connections when stopped

* Move type and const down to the bottom

* Rename to tunnelTracker, reflow some comments

* Add note about capturing h

* Rename to stream_detached

* More comments

* reverseproxy: Preserve half-close behavior after rebase

Keep master half-close propagation and its unit coverage in the refactored tunnel lifecycle. Adapt response finalization tests to the selected upstream argument.

AI-assisted-by: Codex (GPT-6)

* reverseproxy: Fix detached stream cleanup and recorder chains

Snapshot the tracker registry before closing connections, and unregister empty trackers outside their mutex. Mark trackers stopped at cleanup entry so upstream removal closes detached streams even with stream_close_delay, while attached streams retain their delay.

Detach every supported response writer in the middleware chain so inner recorders do not retain state or count detached traffic. Add regressions for all four failures and an access-log/encode/intercept reload integration test.

AI-assisted-by: Codex (GPT-6)

---------

Co-authored-by: WeidiDeng <weidi_deng@icloud.com>
2026-10-04 07:45:10 -04:00
Kévin DunglasandZen Dodd 2f34b936f5 feat: implement the Incremental header field (RFC 10036) (#8020)
Co-authored-by: Zen Dodd <mail@steadytao.com>
2026-10-02 20:59:34 -04:00
Turhan ACAR 9be8fb2794 reverseproxy: propagate TCP half-close on upgraded streams (#8027)
* reverseproxy: propagate TCP half-close on upgraded streams

handleUpgradeResponse starts one copy goroutine per direction but returns as
soon as the first one reports a result, and returning runs two unconditional
deferred closes (the client connection and the backend connection). A client
that ends its send direction with a TCP half-close therefore causes the whole
tunnel to be torn down: the backend connection is reset mid-conversation and
whatever it was about to send is never delivered.

Treat a clean EOF as the end of one direction rather than the end of the
tunnel. When a copy finishes without error, propagate the half-close to the
destination with CloseWrite where the connection supports it, and keep waiting
for the other direction so pending bytes can still drain. Real copy errors, the
stream timeout and request cancellation/shutdown still tear down immediately.

If the destination does not support CloseWrite, the peer cannot be told that
the direction ended, so the previous behavior is kept and the tunnel is torn
down rather than held open until the stream timeout.

This is the same class that was fixed upstream in net/http/httputil
(https://go.dev/issue/35892); Caddy has its own upgraded-stream copier, so the
standard library fix does not apply here.

Fixes #8026

* reverseproxy: follow net/http/httputil shape for the half-close

Replace the copyResult struct and the closeWriter/closeWrite helpers with
upstream's plain error channel and errCopyDone sentinel, propagating
CloseWrite inside the copier, as requested in review.

Behaviour is unchanged. The wait is repeated twice inside the existing
select because handleUpgradeResponse also selects on the stream timeout
and sizes the channel at 2 so both goroutines can exit when it fires
(#7418), which net/http/httputil has no equivalent of.

* reverseproxy: explain the repeated wait next to it

Move the reasoning for why the wait is repeated inside the select, rather
than written as upstream's two-line form, into a comment beside the loop
so a future reader does not have to find the review discussion.

* reverseproxy: add an upgraded-stream half-close integration test

Drive a real upgraded stream through the handler and check that closing one
direction is propagated to the other side instead of tearing the tunnel down.

Mirrors net/http/httputil's TestReverseProxyWebSocketHalfTCP, which covers the
same class upstream (https://go.dev/issue/35892): a backend that hijacks and
hands back a *net.TCPConn, the handler in front of it, and a client that dials
it directly, then the four close-read / close-write combinations.

Against the unfixed handler the two half-close cases fail - the surviving
direction never delivers its pending bytes - while the two close-read cases
pass, so the test isolates exactly the reported behaviour.

* reverseproxy: give the half-close test reads a deadline

Without one, a regression blocks in ReadFull until the package timeout
instead of failing the test, which is the flakiness an end-to-end test of
this kind is usually accused of. Ten seconds is far above any real latency
here and turns a hang into a clear failure.

* reverseproxy: hijack the test backend via http.NewResponseController

Matches how the rest of the tree reaches Hijack (responsewriter.go,
caddyauth.go, streaming.go itself) and keeps working if the writer is
wrapped, where a direct http.Hijacker assertion would not.
2026-09-16 10:10:24 +00:00
Zen Dodd ca0ca67fbd reverseproxy: make stream copy buffer size configurable (#7627) 2026-04-10 14:49:32 -06:00
Oleksandr Redko 72eaf2583a chore: Enable modernize linter (#7519) 2026-02-26 14:01:35 -07:00
Matt Holt 95941a71e8 chore: Add nolints to work around haywire linters (#7493)
* chore: Add nolints to work around haywire linters

* More lint wrangling
2026-02-17 16:52:54 -07:00
WeidiDeng 47f3e8f8dc use math/rand/v2 instead of math/rand (#7413) 2026-02-11 09:15:51 -07:00
WeidiDeng 80f2ae92cd reverseproxy: make error chan bigger when reverse proxying websocket (#7419) 2026-01-06 04:55:47 -05:00
Anthony BiondoandWeidiDeng 7fb39ec1e5 reverseproxy: Use http1.1 upgrade for websocket for extended connect of http2 and http3 (#7305)
Co-authored-by: WeidiDeng <weidi_deng@icloud.com>
2025-10-16 02:20:20 +00:00
Mohammed Al Sahaf 25be2f26fc chore: ugh, lint fix... (#7275)
* chore: ugh, lint fix...

Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>

* more lint fixes

Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>

---------

Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>
2025-09-26 03:14:48 -04:00
mountdisk c712cfcd76 docs: fix some minor issues in the comments (#7101) 2025-06-30 06:50:00 +00:00
WeidiDeng 9c0c71e577 reverseproxy: Rewrite requests and responses for websocket over http2 (#6567)
* reverse proxy: rewrite requests and responses for websocket over http2

* delete protocol pseudo-header

* modify cloned requests

* set request variable to track if it's a h2 websocket

* use request bodu

* rewrite request body

* use WebSocket instead of Websocket in the headers

* use logger check for zap loggers

* fix lint
2024-12-06 13:23:27 -07:00
Matthew Holt 5e6024c48d reverseproxy: Fix log message
Fixes regression from #6560
2024-10-21 12:19:04 -06:00
WeidiDengandFrancis Lavoie 48ce47f1d4 reverseproxy: Use correct cases for websocket related headers (#6621)
Co-authored-by: Francis Lavoie <lavofr@gmail.com>
2024-10-11 09:02:23 +00:00
Kévin Dunglas f4bf4e0097 perf: use zap's Check() to prevent useless allocs (#6560)
* perf: use zap's Check() to prevent useless allocs

* fix

* fix

* fix

* fix

* restore previous replacer behavior

* fix linter
2024-09-13 11:16:37 -06:00
WeidiDeng 1b9042bcdd reverseproxy: handle buffered data during hijack (#6274) 2024-04-26 09:09:18 -06:00
WeidiDeng b40cacf5ce reverseproxy: Wait for both ends of websocket to close (#6175) 2024-04-15 11:37:37 -06:00
Francis Lavoie 3248e4c89f logging: Add zap.Option support (#5944) 2023-12-18 20:48:34 +00:00
Matt HoltandFrancis Lavoie 3a3182fba3 reverseproxy: Add more debug logs (#5793)
* reverseproxy: Add more debug logs

This makes debug logging very noisy when reverse proxying, but I guess
that's the point.

This has shown to be useful in troubleshooting infrastructure issues.

* Update modules/caddyhttp/reverseproxy/streaming.go

Co-authored-by: Francis Lavoie <lavofr@gmail.com>

* Update modules/caddyhttp/reverseproxy/streaming.go

Co-authored-by: Francis Lavoie <lavofr@gmail.com>

* Add opt-in `trace_logs` option

* Rename to VerboseLogs

---------

Co-authored-by: Francis Lavoie <lavofr@gmail.com>
2023-10-11 13:36:20 -06:00
Jacob Gadikian b32f265eca ci: Use gofumpt to format code (#5707) 2023-08-07 19:40:31 +00:00
WeidiDeng e2fc08bd34 reverseproxy: Fix hijack ordering which broke websockets (#5679) 2023-08-03 04:08:12 +00:00
Francis Lavoie cd486c25d1 caddyhttp: Make use of http.ResponseController (#5654)
* caddyhttp: Make use of http.ResponseController

Also syncs the reverseproxy implementation with stdlib's which now uses ResponseController as well https://github.com/golang/go/commit/2449bbb5e614954ce9e99c8a481ea2ee73d72d61

* Enable full-duplex for HTTP/1.1

* Appease linter

* Add warning for builds with Go 1.20, so it's less surprising to users

* Improved godoc for EnableFullDuplex, copied text from stdlib

* Only wrap in encode if not already wrapped
2023-08-02 20:03:26 +00:00
mmm444andFrancis Lavoie 424ae0f420 reverseproxy: Experimental streaming timeouts (#5567)
* reverseproxy: WIP streaming timeouts

* More verbose logging by using the child logger

* reverseproxy: Implement streaming timeouts

* reverseproxy: Refactor cleanup

* reverseproxy: Avoid **time.Timer

---------

Co-authored-by: Francis Lavoie <lavofr@gmail.com>
2023-06-19 15:54:43 -06:00
Francis LavoieandMatt Holt 66e571e687 reverseproxy: Add mention of which half a copyBuffer err comes from (#5472)
Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
2023-03-31 15:46:29 -04:00
WeidiDeng c77a6bea66 reverseproxy: Log status code and byte count for websockets (#5140)
* log response size for websocket request

* record size when using hijack bufio.Writer
2023-02-06 16:14:59 -07:00
Francis Lavoie ee7c92ec9b reverseproxy: Mask the WS close message when we're the client (#5199)
* reverseproxy: Mask the WS close message when we're the client

* weakrand

* Bump golangci-lint version so path ignores work on Windows

* gofmt

* ugh, gofmt everything, I guess
2022-11-14 09:38:02 -07:00
Matt HoltandFrancis Lavoie 66476d8c8f reverseproxy: Close hijacked conns on reload/quit (#4895)
* reverseproxy: Close hijacked conns on reload/quit

We also send a Close control message to both ends of
WebSocket connections. I have tested this many times in
my dev environment with consistent success, although
the variety of scenarios was limited.

* Oops... actually call Close() this time

* CloseMessage --> closeMessage

Co-authored-by: Francis Lavoie <lavofr@gmail.com>

* Use httpguts, duh

* Use map instead of sync.Map

Co-authored-by: Francis Lavoie <lavofr@gmail.com>
2022-09-02 17:01:55 -06:00
Francis Lavoie 141872ed80 chore: Bump up to Go 1.19, minimum 1.18 (#4925) 2022-08-02 16:39:09 -04:00
Francis LavoieandMatthew Holt e4ce40f8ff reverseproxy: Sync up handleUpgradeResponse with stdlib (#4664)
* reverseproxy: Sync up `handleUpgradeResponse` with stdlib

I had left this as a TODO for when we bump to minimum 1.17, but I should've realized it was under `internal` so it couldn't be used directly.

Copied the functions we needed for parity. Hopefully this is ok!

* Add tests and fix godoc comments

Co-authored-by: Matthew Holt <mholt@users.noreply.github.com>
2022-04-11 12:49:56 -06:00
Francis Lavoie e6c29ce081 reverseproxy: Incorporate latest proxy changes from stdlib (#4266)
I went through the commits that touched stdlib's `reverseproxy.go` file, and copied over all the changes that are to code that was copied into Caddy.

The commits I pulled changes from:

- https://github.com/golang/go/commit/2cc347382f4df3fb40d8d81ec9331f0748b1c394
- https://github.com/golang/go/commit/a5cea062b305c8502bdc959c0eec279dbcd4391f
- https://github.com/golang/go/commit/ecdbffd4ec68b509998792f120868fec319de59b
- https://github.com/golang/go/commit/21898524f66c075d7cfb64a38f17684140e57675
-https://github.com/golang/go/commit/ca3c0df1f8e07337ba4048b191bf905118ebe251
- https://github.com/golang/go/commit/9c017ff30dd21bbdcdb11f39458d3944db530d7e

This may also fix https://github.com/caddyserver/caddy/issues/4247 because of the change to `copyResponse` to set `mlw.flushPending = true` right away.
2021-08-12 10:48:24 -06:00
Matthew Holt a17c3b568d reverseproxy: Minor logging improvements 2021-05-05 14:52:24 -06:00
bd17eb205d ci: Use golangci's github action for linting (#3794)
* ci: Use golangci's github action for linting

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix most of the staticcheck lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix the prealloc lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix the misspell lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix the varcheck lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix the errcheck lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix the bodyclose lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix the deadcode lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix the unused lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix the gosec lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix the gosimple lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix the ineffassign lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Fix the staticcheck lint errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Revert the misspell change, use a neutral English

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Remove broken golangci-lint CI job

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Re-add errantly-removed weakrand initialization

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* don't break the loop and return

* Removing extra handling for null rootKey

* unignore RegisterModule/RegisterAdapter

Co-authored-by: Mohammed Al Sahaf <msaa1990@gmail.com>

* single-line log message

Co-authored-by: Matt Holt <mholt@users.noreply.github.com>

* Fix lint after a1808b0dbf209c615e438a496d257ce5e3acdce2 was merged

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Revert ticker change, ignore it instead

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Ignore some of the write errors

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Remove blank line

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Use lifetime

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* close immediately

Co-authored-by: Matt Holt <mholt@users.noreply.github.com>

* Preallocate configVals

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Update modules/caddytls/distributedstek/distributedstek.go

Co-authored-by: Mohammed Al Sahaf <msaa1990@gmail.com>
Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
2020-11-22 14:50:29 -07:00
Francis LavoieandMatthew Holt 96058538f0 reverseproxy: Logging for streaming and upgrades (#3689)
* reverseproxy: Enable error logging for connection upgrades

* reverseproxy: Change some of the error levels, unsugar

* Use unsugared log in one spot

Co-authored-by: Matthew Holt <mholt@users.noreply.github.com>
2020-11-20 14:24:58 -07:00
Christian Flach fdfdc03339 reverseproxy: Ignore RFC 1521 params in Content-Type header (#3758)
Without this change, a Content-Type header like "text/event-stream;charset=utf-8"
would not trigger the immediate flushing.

Fixes #3765
2020-10-01 12:15:45 -06:00
Matthew Holt c94f5bb7dd reverseproxy: Make default buffer size const 2020-08-17 16:17:16 -06:00
Kevin LinandMatthew Holt 904f149e5b reverse_proxy: fix bidirectional streams with encodings (fix #3606) (#3620)
* reverse_proxy: fix bi-h2stream breaking gzip encode handle(#3606).

* reverse_proxy: check http version of both sides to avoid affecting non-h2 upstream.

* Minor cleanup; apply review suggestions

Co-authored-by: Matthew Holt <mholt@users.noreply.github.com>
2020-08-03 20:50:38 -06:00
Kevin Lin e9b1d7dcb4 reverse_proxy: flush HTTP/2 response when ContentLength is unknown (#3561)
* reverse proxy: Support more h2 stream scenarios (#3556)

* reverse proxy: add integration test for better h2 stream (#3556)

* reverse proxy: adjust comments as francislavoie suggests

* link to issue #3556 in the comments
2020-07-20 12:14:46 -06:00
Matthew Holt b3bff13f7d reverseproxy: Close websocket conn if req context cancels
This is a recent patch in the Go standard library
2020-06-11 15:25:26 -06:00
Matthew Holt 881b826fb5 reverseproxy: Pool copy buffers (minor optimization) 2020-05-27 11:42:19 -06:00
Mohammed Al Sahaf dff78d82ce v2: housekeeping: address minor lint complaints (#2957)
* v2: housekeeping: update tools

* v2: housekeeping: adhere to US locale in spelling

* v2: housekeeping: simplify code
2020-01-03 11:33:22 -07:00
Matthew Holt 1228dd7d93 reverse_proxy: Allow buffering of client requests
This is a bad idea, but some backends apparently require it. See
discussion in #176.
2019-11-15 17:15:33 -07:00