package ingress import ( "encoding/json" "regexp" "strings" "github.com/cloudflare/cloudflared/ingress/middleware" ) // Rule routes traffic from a hostname/path on the public internet to the // service running on the given URL. type Rule struct { // Requests for this hostname will be proxied to this rule's service. Hostname string `json:"hostname"` // punycodeHostname is an additional optional hostname converted to punycode. punycodeHostname string // Path is an optional regex that can specify path-driven ingress rules. Path *Regexp `json:"path"` // A (probably local) address. Requests for a hostname which matches this // rule's hostname pattern will be proxied to the service running on this // address. Service OriginService `json:"service"` // Handlers is a list of functions that acts as a middleware during ProxyHTTP Handlers []middleware.Handler // Configure the request cloudflared sends to this specific origin. Config OriginRequestConfig `json:"originRequest"` } // MultiLineString is for outputting rules in a human-friendly way when Cloudflared // is used as a CLI tool (not as a daemon). func (r Rule) MultiLineString() string { var out strings.Builder if r.Hostname != "" { out.WriteString("\thostname: ") out.WriteString(r.Hostname) out.WriteRune('\n') } if r.Path != nil && r.Path.Regexp != nil { out.WriteString("\tpath: ") out.WriteString(r.Path.Regexp.String()) out.WriteRune('\n') } out.WriteString("\tservice: ") out.WriteString(r.Service.String()) return out.String() } // Matches checks if the rule matches a given hostname/path combination. func (r *Rule) Matches(hostname, path string) bool { hostMatch := false if r.Hostname == "" || r.Hostname == "*" { hostMatch = true } else { hostMatch = matchHost(r.Hostname, hostname) } punycodeHostMatch := false if r.punycodeHostname != "" { punycodeHostMatch = matchHost(r.punycodeHostname, hostname) } pathMatch := r.Path == nil || r.Path.Regexp == nil || r.Path.Regexp.MatchString(path) return (hostMatch || punycodeHostMatch) && pathMatch } // Regexp adds unmarshalling from json for regexp.Regexp type Regexp struct { *regexp.Regexp } func (r *Regexp) MarshalJSON() ([]byte, error) { if r.Regexp == nil { return json.Marshal(nil) } return json.Marshal(r.Regexp.String()) }