Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/caddyserver/certmagic v0.25.3
github.com/caddyserver/zerossl v0.1.5
github.com/cloudflare/circl v1.6.3
github.com/dunglas/go-urlpattern v0.0.0-20260421141449-cbab7cf1e16d
github.com/dustin/go-humanize v1.0.1
github.com/go-chi/chi/v5 v5.2.5
github.com/google/cel-go v0.28.1
Expand Down Expand Up @@ -58,6 +59,7 @@ require (
dario.cat/mergo v1.0.2 // indirect
filippo.io/bigmod v0.1.0 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/bits-and-blooms/bitset v1.24.4 // indirect
github.com/ccoveille/go-safecast/v2 v2.0.0 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/coreos/go-oidc/v3 v3.17.0 // indirect
Expand All @@ -76,6 +78,7 @@ require (
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nlnwa/whatwg-url v0.6.2 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/otlptranslator v1.0.0 // indirect
Expand Down Expand Up @@ -107,7 +110,7 @@ require (
go.opentelemetry.io/otel/sdk/log v0.19.0 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
golang.org/x/oauth2 v0.36.0 // indirect
google.golang.org/api v0.277.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d // indirect
Expand Down
17 changes: 15 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ github.com/aws/smithy-go v1.25.1 h1:J8ERsGSU7d+aCmdQur5Txg6bVoYelvQJgtZehD12GkI=
github.com/aws/smithy-go v1.25.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.24.4 h1:95H15Og1clikBrKr/DuzMXkQzECs1M6hhoGXLwLQOZE=
github.com/bits-and-blooms/bitset v1.24.4/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/caddyserver/certmagic v0.25.3 h1:mGf5ba8F7xA4c5jfDZZbK2buY1VEkbnwpMDixaju94A=
github.com/caddyserver/certmagic v0.25.3/go.mod h1:YVs43D5+H/Dckt4bTga1KSO/xYfFBfVZainGDywYPAA=
github.com/caddyserver/zerossl v0.1.5 h1:dkvOjBAEEtY6LIGAHei7sw2UgqSD6TrWweXpV7lvEvE=
Expand Down Expand Up @@ -135,6 +138,8 @@ github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55k
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8=
github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dunglas/go-urlpattern v0.0.0-20260421141449-cbab7cf1e16d h1:Mw8vvAx2b5bjIrQIJaVTO25vJY5DMBUO/hJGNLIl+6g=
github.com/dunglas/go-urlpattern v0.0.0-20260421141449-cbab7cf1e16d/go.mod h1:9qyjDljBPOWyWCGz7vo3Ek7cdnoG/DVk0Ucle7gWVS8=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
Expand Down Expand Up @@ -254,6 +259,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nlnwa/whatwg-url v0.6.2 h1:jU61lU2ig4LANydbEJmA2nPrtCGiKdtgT0rmMd2VZ/Q=
github.com/nlnwa/whatwg-url v0.6.2/go.mod h1:x0FPXJzzOEieQtsBT/AKvbiBbQ46YlL6Xa7m02M1ECk=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
Expand Down Expand Up @@ -455,13 +462,14 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
golang.org/x/crypto/x509roots/fallback v0.0.0-20260213171211-a408498e5541 h1:FmKxj9ocLKn45jiR2jQMwCVhDvaK7fKQFzfuT9GvyK8=
golang.org/x/crypto/x509roots/fallback v0.0.0-20260213171211-a408498e5541/go.mod h1:+UoQFNBq2p2wO+Q6ddVtYc25GZ6VNdOMyyrd4nrqrKs=
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY=
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
Expand All @@ -477,6 +485,7 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
Expand All @@ -487,6 +496,7 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
Expand All @@ -505,6 +515,7 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
Expand All @@ -516,6 +527,7 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
Expand All @@ -527,6 +539,7 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
Expand Down
32 changes: 32 additions & 0 deletions modules/caddyhttp/celmatcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,38 @@ eqp31wM9il1n+guTNyxJd+FzVAH+hCZE5K+tCgVDdVFUlDEHHbS/wqb2PSIoouLV
urlTarget: "https://example.com/foo/bar",
wantResult: false,
},
{
name: "url_pattern matches named group (MatchURLPattern)",
expression: &MatchExpression{
Expr: `url_pattern('/books/:id')`,
},
urlTarget: "https://example.com/books/123",
wantResult: true,
},
{
name: "url_pattern does not match (MatchURLPattern)",
expression: &MatchExpression{
Expr: `url_pattern('/books/:id')`,
},
urlTarget: "https://example.com/movies/123",
wantResult: false,
},
{
name: "url_pattern with base_url matches host (MatchURLPattern)",
expression: &MatchExpression{
Expr: `url_pattern('/foo', 'https://example.com')`,
},
urlTarget: "https://example.com/foo",
wantResult: true,
},
{
name: "url_pattern with base_url rejects other host (MatchURLPattern)",
expression: &MatchExpression{
Expr: `url_pattern('/foo', 'https://example.com')`,
},
urlTarget: "https://other.com/foo",
wantResult: false,
},
{
name: "protocol matches (MatchProtocol)",
expression: &MatchExpression{
Expand Down
213 changes: 213 additions & 0 deletions modules/caddyhttp/urlpatternmatcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package caddyhttp

import (
"fmt"
"net/http"
"strings"

"github.com/dunglas/go-urlpattern"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types/ref"

"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
)

// urlPatternPlaceholderPrefix namespaces placeholders for captured groups.
const urlPatternPlaceholderPrefix = "http.url_pattern"

func init() {
caddy.RegisterModule(&MatchURLPattern{})
}

// MatchURLPattern matches requests against a [URLPattern], giving named
// groups, wildcards and regexp components beyond what the simpler path
// matcher offers.
//
// [URLPattern]: https://urlpattern.spec.whatwg.org/
type MatchURLPattern struct {
// Pattern is the URLPattern to match against. A relative pattern (e.g.
// "/books/:id") matches the request path on any host; an absolute pattern
// (e.g. "https://example.com/books/:id") also constrains scheme and host.
Pattern string `json:"pattern,omitempty"`

// BaseURL resolves a relative Pattern against a fixed origin, scoping the
// match to that scheme and host. Leave empty to match any origin.
BaseURL string `json:"base_url,omitempty"`

// IgnoreCase matches the pattern case-insensitively.
IgnoreCase bool `json:"ignore_case,omitempty"`

compiledPattern *urlpattern.URLPattern
}

// CaddyModule returns the Caddy module information.
func (*MatchURLPattern) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "http.matchers.url_pattern",
New: func() caddy.Module { return new(MatchURLPattern) },
}
}

// Provision compiles the URL pattern.
func (m *MatchURLPattern) Provision(_ caddy.Context) error {
input := m.Pattern

// A relative pattern with no base matches any origin: prefix wildcard
// protocol, host and port so only the path, search and hash are
// constrained. The port wildcard is needed because a request Host may
// carry an explicit port. Host-scoped matching stays opt-in via an
// absolute pattern or base_url.
if m.BaseURL == "" && !strings.Contains(input, "://") {
input = "*://*:*" + input
}

p, err := urlpattern.New(input, m.BaseURL, &urlpattern.Options{IgnoreCase: m.IgnoreCase})
if err != nil {
return fmt.Errorf("unable to parse URL pattern: %w", err)
}

m.compiledPattern = p

return nil
}

// Match returns true if the request matches the URL pattern.
func (m *MatchURLPattern) Match(r *http.Request) bool {
ok, _ := m.MatchWithError(r)

return ok
}

// MatchWithError returns true if the request matches the URL pattern. The
// request's origin (scheme://host) is the base against which the path is
// resolved, so an absolute pattern or base_url can match on scheme and host.
//
// On a match, captured groups are exposed as placeholders scoped by URL
// component, mirroring the URLPattern result object: a named group :id in the
// pathname becomes {http.url_pattern.pathname.id}, a group q in the query
// becomes {http.url_pattern.search.q}, and so on.
func (m *MatchURLPattern) MatchWithError(r *http.Request) (bool, error) {
scheme := "http"
if r.TLS != nil {
scheme = "https"
}

result := m.compiledPattern.Exec(r.URL.RequestURI(), scheme+"://"+r.Host)
if result == nil {
return false, nil
}

if repl, ok := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer); ok {
setURLPatternGroups(repl, "protocol", result.Protocol)
setURLPatternGroups(repl, "username", result.Username)
setURLPatternGroups(repl, "password", result.Password)
setURLPatternGroups(repl, "hostname", result.Hostname)
setURLPatternGroups(repl, "port", result.Port)
setURLPatternGroups(repl, "pathname", result.Pathname)
setURLPatternGroups(repl, "search", result.Search)
setURLPatternGroups(repl, "hash", result.Hash)
}

return true, nil
}

// setURLPatternGroups publishes a component's captured groups as
// {http.url_pattern.<component>.<group>} placeholders.
func setURLPatternGroups(repl *caddy.Replacer, component string, c urlpattern.URLPatternComponentResult) {
for name, value := range c.Groups {
repl.Set(urlPatternPlaceholderPrefix+"."+component+"."+name, value)
}
}

// CELLibrary produces options that expose this matcher for use in CEL
// expression matchers.
//
// Example:
//
// expression url_pattern('/books/:id')
// expression url_pattern('/books/:id', 'https://example.com')
func (MatchURLPattern) CELLibrary(ctx caddy.Context) (cel.Library, error) {
pattern, err := CELMatcherImpl(
"url_pattern",
"url_pattern_request_string",
[]*cel.Type{cel.StringType},
func(data ref.Val) (RequestMatcherWithError, error) {
pattern, ok := data.Value().(string)
if !ok {
return nil, fmt.Errorf("url_pattern expects a string argument")
}

matcher := MatchURLPattern{Pattern: pattern}
err := matcher.Provision(ctx)

return &matcher, err
},
)
if err != nil {
return nil, err
}

patternWithBase, err := CELMatcherImpl(
"url_pattern",
"url_pattern_request_string_string",
[]*cel.Type{cel.StringType, cel.StringType},
func(data ref.Val) (RequestMatcherWithError, error) {
params, err := data.ConvertToNative(stringSliceType)
if err != nil {
return nil, err
}
strParams := params.([]string)
matcher := MatchURLPattern{Pattern: strParams[0], BaseURL: strParams[1]}
err = matcher.Provision(ctx)
return &matcher, err
},
)
if err != nil {
return nil, err
}

envOpts := append(pattern.CompileOptions(), patternWithBase.CompileOptions()...)
prgOpts := append(pattern.ProgramOptions(), patternWithBase.ProgramOptions()...)
return NewMatcherCELLibrary(envOpts, prgOpts), nil
}

// UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax:
//
// url_pattern <pattern> {
// base_url <url>
// ignore_case
// }
func (m *MatchURLPattern) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() {
if !d.Args(&m.Pattern) {
return d.Err("expected exactly one URL pattern")
}

for d.NextBlock(0) {
switch d.Val() {
case "base_url":
if !d.Args(&m.BaseURL) {
return d.ArgErr()
}
case "ignore_case":
if d.NextArg() {
return d.ArgErr()
}
m.IgnoreCase = true
default:
return d.Errf("unrecognized url_pattern option '%s'", d.Val())
}
}
}

return nil
}

// Interface guards
var (
_ RequestMatcherWithError = (*MatchURLPattern)(nil)
_ caddy.Provisioner = (*MatchURLPattern)(nil)
_ caddyfile.Unmarshaler = (*MatchURLPattern)(nil)
_ CELLibraryProducer = (*MatchURLPattern)(nil)
)
Loading
Loading