Merged
Conversation
This commit introduces a new framework for adding implementing custom application protocols. This enables bidirectional message streams alongside standard HTTP flows and provides seamless proxying between HTTP/1.1, HTTP/2, and custom protocols. This should have a zero, or near-zero performance impact on existin HTTP/1.1 and HTTP/2 use cases. Co-authored-by: Abhishek Aiyer <aaiyer@cloudflare.com>
Saw this in logs:
```
2025-08-16T11:11:42.859488Z ERROR ThreadId(36) pingora_proxy: /usr/local/cargo/registry/src/index.crates.~~~cf8c6b5b557f/pingora-~~~.5.0/src/lib.rs:148: Fail to proxy: Downstream InvalidHTTPHeader context: buf: \u{16}\u{3}\u{1}\u{0}\u{fffd}\u{1}\u{0}\u{0}\u{fffd}\u{3}\u{3}\u{fffd}\u{17}\u{b}0\u{fffd}!\u{fffd}T\u{fffd}\u{fffd}\u{b}\u{fffd}\u{1e}\u{fffd}\u{fffd}\u{fffd}i\u{2e4}\u{fffd}\u{fffd}\u{fffd}\u{fffd}\u{fffd}BD\u{12}k m\u{fffd}&:\u{fffd}\u{fffd}\u{fffd}\u{fffd}\u{fffd}\u{14}\u{fffd}]\u{fffd}?\u{7a4}a\u{fffd}\u{1f}\u{fffd}m\u{fffd}\u{1c}L\u{c}I\u{fffd}\u{14}N\u{fffd}\u{fffd}\u{0}&\u{328}\u{329}\u{fffd}/\u{fffd}0\u{fffd}+\u{fffd},\u{fffd}\u{13}\u{fffd}\t\u{fffd}\u{14}\u{fffd}\n\u{0}\u{fffd}\u{0}\u{fffd}\u{0}/\u{0}5\u{fffd}\u{12}\u{0}\n\u{13}\u{3}\u{13}\u{1}\u{13}\u{2}\u{1}\u{0}\u{0}{\u{0}\u{5}\u{0}\u{5}\u{1}\u{0}\u{0}\u{0}\u{0}\u{0}\n\u{0}\n\u{0}\u{8}\u{0}\u{1d}\u{0}\u{17}\u{0}\u{18}\u{0}\u{19}\u{0}\u{b}\u{0}\u{2}\u{1}\u{0}\u{0}\r\u{0}\u{1a}\u{0}\u{18}\u{8}\u{4}\u{4}\u{3}\u{8}\u{7}\u{8}\u{5}\u{8}\u{6}\u{4}\u{1}\u{5}\u{1}\u{6}\u{1}\u{5}\u{3}\u{6}\u{3}\u{2}\u{1}\u{2}\u{3}\u{fffd}\u{1}\u{0}\u{1}\u{0}\u{0}\u{12}\u{0}\u{0}\u{0}+\u{0}\t\u{8}\u{3}\u{4}\u{3}\u{3}\u{3}\u{2}\u{3}\u{1}\u{0}3\u{0}&\u{0}$\u{0}\u{1d}\u{0} \u{e}\u{fffd}\u{fffd}Q\u{f}\u{fffd}\u{fffd}\u{fffd}\u{79bc}:\u{fffd}\r\u{fffd}\u{fffd}\\\u{fffd}\u{c}\u{fffd}E\u{7f}\u{fffd}b\u{fffd}\u{fffd}\u{fffd}H\u{fffd}HHz cause: invalid token
```
There are two issues here:
- it is too verbose
- it is lossy (which might help if we need to actually decode these bytes)
`bstr` crate is designed to print such strings. It is popular crate
developed by a person known in Rust community, so this dependency
is fine.
Includes-commit: 5fcc52e
Replicated-from: cloudflare#683
Co-authored-by: Matthew Gumport <mbg@cloudflare.com>
Previously the downstream error was only ignored once ServeFromCache had miss enabled (when partial read support exists and we have a confirmed miss). The proxy state machines now also ignore errors prior to the header being received.
This enables enriching lock wait spans for user-defined CacheKeyLock implementations.
Additionally a max_size param is added to the increment_weight APIs for eviction manager consumption.
httparse itself does not treat the terminating chunk (0 + CRLF) any differently when parsing its chunk size, and the body reader does not validate the following CRLF required to close the body. Additionally, that current parsing scheme will not consider trailers before the end CRLF. Now the trailers are considered but simply discarded. The CRLFs between the trailers (and now, the CRLFs after the body payloads) are validated, however.
--- chore: address clippy::single_match --- Fix connection filter inheritance for endpoints added after filter setup Previously, endpoints added to Listeners after set_connection_filter() was called would not inherit the filter. This change stores the filter in the Listeners struct and applies it to all subsequently added endpoints. - Store connection filter in Listeners for future endpoints - Apply stored filter when adding new endpoints via add_endpoint() - Update Service to propagate filter to its Listeners - Add test to verify filter inheritance behavior - Add example demonstrating connection filter usage --- chore: no unicode --- feat: add connection_filter feature for early TCP-level connection filtering --- feat: add connection_filter feature flag to main pingora crate --- fix: clean up connection_filter implementation and remove debug code --- fix: clippy unused import --- fix: use expect() for consistency and document performance choice in filter --- Merge remote-tracking branch 'upstream/main' into feat/connection-filter --- fix: removed unused Includes-commit: 1b8bd90 Includes-commit: 69e94d0 Includes-commit: 755c9e5 Includes-commit: 81d5962 Includes-commit: 9b891bc Includes-commit: 9fd7fb9 Includes-commit: a04da3b Includes-commit: d353953 Includes-commit: d919e10 Includes-commit: ee7fac4 Includes-commit: f9d9f4c Replicated-from: cloudflare#671
While reader timeouts should still attempt to fetch without locking, writer age timeouts can cause thundering herds if they force existing readers to give up.
Cacheable responses http versions are already internally set to H1, but there were cases in which HTTP/1.0 origins could have HTTP/1.0 version responses proxied on miss with transfer-encoding which is not RFC compliant and rejected by some major clients.
includes-commit: e087175 includes-commit: 15b58ea replicated-from: cloudflare#289
RFC9112 is now extra explicit about the close delimiting applying exclusively to response messages for HTTP/1.0. Also disables reuse explicitly when close delimiting on the response side as defense-in-depth that shouldn't have behavioral diff.
The upgrade body mode changes also should be applied to subrequests though upgrade and websockets are still highly experimental for them.
If a content-length is present RFC9112 indicates we must reject invalid forms of that content-length header. This eliminates situations where we might be dealing with ambiguous request framing.
Custom sessions need to report their upgrade state to the proxy framework. Previously, Session::is_upgrade_req() and Session::was_upgraded() always returned false for Custom sessions, which broke WebSocket upgrade handling when using custom protocols. This change: - Adds is_upgrade_req() and was_upgraded() methods to the custom Session trait with default implementations returning false - Updates the main Session enum to delegate to the custom session's implementation instead of returning false
This can be enabled via server options. Since CONNECT changes the request-response flow separate from HTTP much like upgrade requests but is currently unsupported, these requests will be automatically rejected by default.
When a custom protocol is shutdown, it is passed a numeric code. This should be 0 to indicate an explicit shutdown rather than any other transport error.
Includes-commit: 286a015 Replicated-from: cloudflare#820
Anyone using caching must must now implement cache_key_callback themselves. This forces an explicit decision about what belongs in the cache key for anyone using thet trait for caching rather than providing an unsafe default that does not support web standards.
If the body is not init when upgraded, there was an issue where the body might be improperly ended early and the conn simply closed.
Rejecting bad upstream content-length by default to avoid forwarding ambiguously framed messages. An option still exists to allow this in the peer options, if needed, and treat these responses as close-delimited though this is non-RFC-compliant. The content-length is now also removed on the response if transfer-encoding is present, per RFC.
…ket` impl The `#[cfg(windows)] impl AsRawSocket for RawStream` was missing a match arm for the `RawStream::Virtual(_)` variant, causing a compilation error (E0004: non-exhaustive patterns) on Windows targets. The `Virtual` variant is not gated by any `#[cfg]` attribute and exists on all platforms, but the Windows `AsRawSocket` implementation only matched `RawStream::Tcp(s)`. This fix adds the missing arm, returning `!0` (INVALID_SOCKET) for virtual streams, consistent with the Unix `AsRawFd` implementation which returns `-1` for the same variant. Co-authored-by: Cursor <cursoragent@cursor.com> Includes-commit: 6da94f9 Replicated-from: cloudflare#809
Includes-commit: f06c1ad Replicated-from: cloudflare#767
The peer option wasn't always being applied when used with other connectors like v2. Also clarify this is to support legacy behavior and may be removed in the future.
--- Merge branch 'cloudflare:main' into fix-socket-perms Includes-commit: 7a748e7 Includes-commit: fdc2027 Replicated-from: cloudflare#810
`parse_range_header` was returning `RangeType::None` for the input `"bytes="` (the bytes= prefix with no range-specs after it). Per RFC 9110 14.1.2, `"bytes="` is syntactically a range request with zero satisfiable range-specs, so the correct response is 416 Range Not Satisfiable. Added an early check for an empty/whitespace-only range-set after the `bytes=` prefix, returning `RangeType::Invalid` instead of falling through to the regex loop.
This removes {transfer,content}-encoding headers from 416 resonses. This
mirrors what to_304() in conditional_filter.rs already does for 304 Not
Modified responses.
…ith dependents and dependencies
Resolves conflicts in: - pingora-core/Cargo.toml: keep proxy-protocol dep + upstream lru workspace change + daggy - pingora-core/src/listeners/tls/boringssl_openssl/mod.rs: keep GetSocketDigest + AlpnError imports - pingora-core/src/server/mod.rs: keep proxy protocol functions + upstream service dependency system Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.