Skip to content

Commit

Permalink
mux rule support multi hosts (#1024)
Browse files Browse the repository at this point in the history
  • Loading branch information
localvar committed Jul 4, 2023
1 parent 6e5679b commit d49bcbb
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 24 deletions.
23 changes: 18 additions & 5 deletions doc/reference/controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- [TrafficController](#trafficcontroller)
- [RawConfigTrafficController](#rawconfigtrafficcontroller)
- [HTTPServer](#httpserver)
- [AccessLogVariable](#accesslogvariable)
- [Pipeline](#pipeline)
- [StatusSyncController](#statussynccontroller)
- [Business Controllers](#business-controllers)
Expand All @@ -30,6 +31,7 @@
- [zipkin.DeprecatedSpec](#zipkindeprecatedspec)
- [ipfilter.Spec](#ipfilterspec)
- [httpserver.Rule](#httpserverrule)
- [httpserver.Host](#httpserverhost)
- [httpserver.Path](#httpserverpath)
- [httpserver.Header](#httpserverheader)
- [pipeline.Spec](#pipelinespec)
Expand Down Expand Up @@ -596,13 +598,24 @@ domains:

### httpserver.Rule

| Name | Type | Description | Required |
| ---------- | ---------------------------------- | ------------------------------------------------------------- | -------- |
| ipFilter | [ipfilter.Spec](#ipfilterSpec) | IP Filter for all traffic under the rule | No |
| host | string | Exact host to match, empty means to match all | No |
| hostRegexp | string | Host in regular expression to match, empty means to match all | No |
| Name | Type | Description | Required |
| ---------- | ----------------------------------- | ------------------------------------------------------------- | -------- |
| ipFilter | [ipfilter.Spec](#ipfilterSpec) | IP Filter for all traffic under the rule | No |
| host | string | Exact host to match | No |
| hostRegexp | string | Host in regular expression to match | No |
| hosts | [][httpserver.Host](#httpserverhost) | Hosts to match | No |
| paths | [][httpserver.Path](#httpserverPath) | Path matching rules, empty means to match nothing. Note that multiple paths are matched in the order of their appearance in the spec, this is different from Nginx. | No |

**Note**: if `host` or `hostRegexp` is not empty, they will be added into
`hosts` at runtime, and if the result `hosts` is empty, all hosts are matched.

### httpserver.Host

| Name | Type | Description | Required |
| ------------- | ------------------------ | ---------------------------------------------------------------------- | -------- |
| isRegexp | bool | Whether `value` is regular expression or exact value, default is false | No |
| value | string | Host value to match | Yes |

### httpserver.Path

| Name | Type | Description | Required |
Expand Down
49 changes: 33 additions & 16 deletions pkg/object/httpserver/routers/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ type Rules []*Rule
// Paths represents the set of paths.
type Paths []*Path

// Host defines the host match rule.
type Host struct {
IsRegexp bool `json:"isRegexp" jsonschema:"omitempty"`
Value string `json:"value" jsonschema:"required"`
re *regexp.Regexp
}

// Rule is first level entry of router.
type Rule struct {
// NOTICE: If the field is a pointer, it must have `omitempty` in tag `json`
Expand All @@ -46,10 +53,10 @@ type Rule struct {
IPFilterSpec *ipfilter.Spec `json:"ipFilter,omitempty" jsonschema:"omitempty"`
Host string `json:"host" jsonschema:"omitempty"`
HostRegexp string `json:"hostRegexp" jsonschema:"omitempty,format=regexp"`
Hosts []Host `json:"hosts" jsonschema:"omitempty"`
Paths Paths `json:"paths" jsonschema:"omitempty"`

ipFilter *ipfilter.IPFilter
hostRE *regexp.Regexp
}

// Path is second level entry of router.
Expand Down Expand Up @@ -107,37 +114,47 @@ func (rules Rules) Init() {

// Init is the initialization portal for Rule.
func (rule *Rule) Init() {
var hostRE *regexp.Regexp
if len(rule.Host) > 0 {
rule.Hosts = append(rule.Hosts, Host{Value: rule.Host})
}
if len(rule.HostRegexp) > 0 {
rule.Hosts = append(rule.Hosts, Host{IsRegexp: true, Value: rule.HostRegexp})
}

if rule.HostRegexp != "" {
var err error
hostRE, err = regexp.Compile(rule.HostRegexp)
if err != nil {
logger.Errorf("BUG: compile %s failed: %v", rule.HostRegexp, err)
for i := range rule.Hosts {
h := &rule.Hosts[i]
if !h.IsRegexp {
continue
}
if re, err := regexp.Compile(h.Value); err != nil {
logger.Errorf("failed to compile %q failed: %v", h.Value, err)
} else {
h.re = re
}
}

rule.ipFilter = ipfilter.New(rule.IPFilterSpec)
rule.hostRE = hostRE

for _, p := range rule.Paths {
p.Init(rule.ipFilter)
}
}

// MatchHost matches the host of the request to the rule.
func (rule *Rule) MatchHost(ctx *RouteContext) bool {
if rule.Host == "" && rule.hostRE == nil {
if len(rule.Hosts) == 0 {
return true
}

host := ctx.GetHost()

if rule.Host != "" && rule.Host == host {
return true
}
if rule.hostRE != nil && rule.hostRE.MatchString(host) {
return true
for i := range rule.Hosts {
h := &rule.Hosts[i]
if h.IsRegexp {
if h.re != nil && h.re.MatchString(host) {
return true
}
} else if host == h.Value {
return true
}
}

return false
Expand Down
6 changes: 3 additions & 3 deletions pkg/object/httpserver/routers/spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ func TestRuleInit(t *testing.T) {
rules.Init()

rule := rules[0]
assert.NotNil(rule.hostRE)
assert.NotNil(rule.Hosts[1].re)
assert.NotNil(rule.ipFilter)
assert.Equal(len(rule.Paths), 1)

rule = rules[1]
assert.NotNil(rule.hostRE)
assert.NotNil(rule.Hosts[1].re)
assert.NotNil(rule.ipFilter)

assert.Equal(len(rule.Paths), 1)
Expand All @@ -96,7 +96,7 @@ func TestRuleInit(t *testing.T) {
},
}
rule.Init()
assert.Nil(rule.hostRE)
assert.Nil(rule.Hosts[1].re)
}

func TestRuleMatch(t *testing.T) {
Expand Down

0 comments on commit d49bcbb

Please sign in to comment.