diff --git a/internal/route/rules/rules.go b/internal/route/rules/rules.go index 2b2d6dc..1908eb1 100644 --- a/internal/route/rules/rules.go +++ b/internal/route/rules/rules.go @@ -2,8 +2,6 @@ package rules import ( "net/http" - - "github.com/yusing/go-proxy/internal/logging" ) type ( @@ -48,76 +46,58 @@ type ( // BuildHandler returns a http.HandlerFunc that implements the rules. // -// Bypass rules are executed first // if a bypass rule matches, // the request is passed to the upstream and no more rules are executed. // -// Other rules are executed later // if no rule matches, the default rule is executed // if no rule matches and default rule is not set, // the request is passed to the upstream. func (rules Rules) BuildHandler(up http.Handler) http.HandlerFunc { - // move bypass rules to the front. - bypassRules := make(Rules, 0, len(rules)) - otherRules := make(Rules, 0, len(rules)) + var ( + defaultRule Rule + defaultRuleIndex int + ) - var defaultRule Rule - - for _, rule := range rules { - switch { - case rule.Do.isBypass(): - bypassRules = append(bypassRules, rule) - case rule.Name == "default": + for i, rule := range rules { + if rule.Name == "default" { defaultRule = rule - default: - otherRules = append(otherRules, rule) + defaultRuleIndex = i + break } } + rules = append(rules[:defaultRuleIndex], rules[defaultRuleIndex+1:]...) + // free allocated empty slices // before encapsulating them into the handlerFunc. - if len(bypassRules) == 0 { - bypassRules = []Rule{} - } - if len(otherRules) == 0 { - otherRules = []Rule{} + if len(rules) == 0 { + if defaultRule.Do.isBypass() { + return up.ServeHTTP + } + rules = []Rule{} } return func(w http.ResponseWriter, r *http.Request) { - for _, rule := range bypassRules { - if rule.On.check(r) { - logging.Debug(). - Str("rule", rule.Name). - Msg("matched: bypass") - up.ServeHTTP(w, r) - return - } - } hasMatch := false - for _, rule := range otherRules { + for _, rule := range rules { if rule.On.check(r) { - logging.Debug(). - Str("rule", rule.Name). - Msgf("matched proceed=%t", rule.Do.exec.proceed) - hasMatch = true + if rule.Do.isBypass() { + up.ServeHTTP(w, r) + return + } rule.Do.exec.HandlerFunc(w, r) if !rule.Do.exec.proceed { return } + hasMatch = true } } + if hasMatch || defaultRule.Do.isBypass() { - logging.Debug(). - Str("rule", defaultRule.Name). - Msg("matched: bypass") up.ServeHTTP(w, r) return } - logging.Debug(). - Str("rule", defaultRule.Name). - Msg("matched: default") - defaultRule.Do.exec.HandlerFunc(w, r) } }