Skip to content

Matcher

A matcher is a routing DSL (Domain Specific Language) that filters requests based on their attributes — hostname, path, method, headers, client IP, etc. Matchers are used in multiple places throughout GOST to route traffic conditionally:

Component Field Scope
Node matcher.rule Selects nodes within a hop
Hop Group hopGroup.hops[].matcher Selects hop entries within a forwarder
Chain Group chainGroup.chains[].matcher Selects chain entries within a listener/handler

In all three places the matcher uses the same DSL and the same routing context. The available context fields depend on the protocol layer:

Level Available fields
Node (inside a hop) Host, Path, Method, Header, Query, BodyRegexp, BodyJSON, ClientIP, Network, Proto
Hop Group (forwarder) Same as node — full HTTP request context via hop.SelectOptions
Chain Group Host — target hostname from the request. RouteOptions currently only carries Host.

DSL Reference

Boolean Operators

Rules support standard boolean logic:

Operator Meaning Example
&& AND Host("a.com") && PathPrefix("/api/")
\|\| OR Host("a.com") \|\| Host("b.com")
! NOT !Host("blocked.com")
() Grouping (Host("a.com") \|\| Host("b.com")) && PathPrefix("/api/")

Matcher Functions

Function Args Description Example
Host pattern Match hostname exactly or by wildcard (also matches SNI for TLS) Host("*.example.com")
HostRegexp regex Match hostname against a Go regexp HostRegexp("^api[0-9]+\\.example\\.com$")
Path pattern Match request path exactly Path("/api/v1/users")
PathPrefix prefix Match if path starts with prefix PathPrefix("/api/")
PathRegexp regex Match path against a Go regexp PathRegexp("\\.(jpeg\\|jpg\\|png)$")
Method method Match HTTP method Method("POST")
Header key Match if the HTTP header key exists Header("Content-Type")
Header key, value Match header key value exactly Header("Content-Type", "application/json")
Header key, op, value Compare numeric header key with op against value 1 Header("Content-Length", "gt", "1024")
HeaderRegexp key, regex Match header key against a Go regexp HeaderRegexp("Content-Type", "^application/(json\\|yaml)$")
Query key Match if the query parameter key exists Query("page")
Query key, value Match query parameter key value exactly Query("page", "1")
Query key, op, value Compare numeric query param key with op against value 1 Query("page", "gt", "2")
QueryRegexp key, regex Match query param key against a Go regexp QueryRegexp("q", ".*")
ClientIP ip... Match client IP against one or more IPs or CIDRs ClientIP("10.0.0.0/8", "::1")
Network net Match connection network type Network("tcp")
Proto protocol Match detected application protocol (requires sniffing) Proto("http")
BodyRegexp regex Match the buffered request body prefix against a Go regexp 3 BodyRegexp("\"model\"\\s*:\\s*\"claude-opus[^\"]*\"")
BodyJSON path, regex Extract a JSON field via GJSON path and match against a Go regexp 3 BodyJSON("model", "claude.*")
BodyJSON path, op, value Extract a numeric JSON field via GJSON path and compare with op against value 3 1 BodyJSON("age", "ge", "18")
Admission name Delegate to a named admission controller 2 Admission("block-internal")
Bypass name Delegate to a named bypass rule 2 Bypass("china-mainland")

Comparison Operators

3.3.0

Header, Query, and BodyJSON accept a 3-parameter form with a comparison operator: Header("Content-Length", "gt", "1024").

Operator Matches when
gt value is greater than
ge value is greater or equal
lt value is less than
le value is less or equal
eq value is equal
ne value is not equal

The value is parsed as a floating-point number. Non-numeric values are silently skipped (treated as no match). For multi-value headers and query parameters, the match succeeds if any value satisfies the comparison.

Priority

priority (int, default: auto)

To avoid path overlap, nodes are sorted by default in descending order using rule length. The priority is directly equal to the length of the rule — the longest rule has the highest priority.

Set priority to a specific value to override this. A negative value disables automatic priority ordering entirely — all matching nodes go through the selector equally.

Body Size

bodySize (int, default: 1MB)

Maximum size of the HTTP request body prefix (in bytes) to read for body matchers. Defaults to 1MB (1048576). Capped at 10MB (10485760); larger values are clamped.

Set to -1 to disable body matching entirely.

!!! note The body prefix is automatically decompressed according to Content-Encoding (gzip, deflate, br, zstd) before matching. Only the prefix used for matching is decoded; the full body forwarded to the target keeps its original compression.

Regexp Syntax

Matchers that accept a regexp use Go's regexp syntax (RE2). Perl-style lookahead/lookbehind and backreferences are not supported.

Examples

Basic: Route by hostname

matcher:
  rule: Host("api.example.com")

With boolean logic

matcher:
  rule: 'Method("POST") && PathPrefix("/v1/") && Header("Content-Type", "application/json")'

With body matching

matcher:
  rule: 'BodyJSON("output_config.effort", "^(xhigh|max)$")'
  bodySize: 65536

Chain group: route by target hostname

chainGroup:
  chains:
  - chain: chain-api
    matcher:
      rule: Host("api.example.com")
  - chain: chain-web
  selector:
    strategy: round

Hop group: route by path prefix

hopGroup:
  hops:
  - hop: hop-api
    matcher:
      rule: 'PathPrefix("/api/") && Host("*.example.com")'
  - hop: hop-internal
    matcher:
      rule: 'ClientIP("10.0.0.0/8", "172.16.0.0/12")'
  - hop: hop-default
  selector:
    strategy: rr

See Also


  1. 3.3.0 

  2. 3.2.4 

  3. Body matchers require sniffing: true on the handler. Only a prefix is read for matching (see Body Size); the full request body is forwarded unchanged. The prefix is automatically decompressed according to Content-Encoding (gzip, deflate, br, zstd) before matching. 

Comments