Skip to content

fix(tonic-xds): match routes on request path and anchor safe_regex - #2804

Open
YutaoMa wants to merge 5 commits into
grpc:masterfrom
YutaoMa:yutaoma/tonic-xds-routing-path-fix
Open

fix(tonic-xds): match routes on request path and anchor safe_regex#2804
YutaoMa wants to merge 5 commits into
grpc:masterfrom
YutaoMa:yutaoma/tonic-xds-routing-path-fix

Conversation

@YutaoMa

@YutaoMa YutaoMa commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Motivation

Two route-matching bugs were discovered while testing tonic-xds::RoutingLayer. Previously because the routing config wasn't wired in, the buggy path wouldn't be exercised in production. Now they are surfaced and needs fixing:

  1. RoutingLayer used to fetch :path header from the HeaderMap, but that pseudo header isn't actually inserted there. (Rust http::HeaderMap does not allow storing pseudo headers).
  2. The StringMatcher::SafeRegex does partial match, while the spec mandates full match (see https://github.com/envoyproxy/envoy/blob/743baafef00f4f8d5fc234e6ee5cb7ed87cba148/api/envoy/type/matcher/v3/regex.proto#L66)

Solution

  • Change to extract the path from the request URI, with the query string excluded as the matcher requires.
  • safe_regex patterns are now anchored as \A(?:{})\z in the new type SafeRegex. We enforce full match by only exposing that matching function from the type. For debuggability the Debug implementation does print the original unanchored pattern.

## Summary

Two independent route-matching bugs, each of which silently selects the
wrong route. Both are masked by a catch-all prefix route, and the first
hides the second: while every request matched "/", no regex route could
match at all.

## What changed

- **Match on the request path.** The path was read from the `:path`
  header, which never resolves, so every request matched "/" rather than
  the method being invoked. It now comes from the request URI, with the
  query string excluded as the matcher requires.

- **Anchor `safe_regex` to the whole path.** Patterns were matched
  anywhere in the path, so a route matched any path merely containing
  the pattern. Envoy requires the entire path to match, so patterns are
  now compiled as `\A(?:{})\z`.

Anchoring is applied to the path matcher only; the two header-value
regex sites are left to a follow-up. There is no public API change.

## Testing

Three tests, each failing without its fix: one drives the routing layer
with a specific route ordered ahead of a catch-all, two go through
validation to check the anchors.
@YutaoMa YutaoMa changed the title Yutaoma/tonic xds routing path fix fix(tonic-xds): match routes on request path and anchor safe_regex Aug 13, 2026
@YutaoMa
YutaoMa marked this pull request as ready for review August 13, 2026 23:52
/// regardless of those flags, whereas `^`/`$` become line anchors under
/// `(?m)`.
pub(crate) fn new(pattern: &str) -> Result<Self, regex::Error> {
Regex::new(&format!("{ANCHOR_PREFIX}{pattern}{ANCHOR_SUFFIX}")).map(Self)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate the regex first so that injection such as "foo)|bar(?:" will not cause loopholes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, added a pre-anchoring compile so patterns with unbalanced parens get rejected.

}

#[test]
fn an_invalid_pattern_is_rejected() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can add to this test as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added tests for the above cases.

@gu0keno0 gu0keno0 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One comment about regex safety, otherwise LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants