github.com/mholt/caddy-l4@v0.0.0-20241104153248-ec8fae209322/modules/l4subroute/handler.go (about) 1 // Copyright 2020 Matthew Holt 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package l4subroute 16 17 import ( 18 "fmt" 19 "time" 20 21 "github.com/caddyserver/caddy/v2" 22 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" 23 "go.uber.org/zap" 24 25 "github.com/mholt/caddy-l4/layer4" 26 ) 27 28 func init() { 29 caddy.RegisterModule(&Handler{}) 30 } 31 32 // Handler implements a handler that compiles and executes routes. 33 // This is useful for a batch of routes that all inherit the same 34 // matchers, or for multiple routes that should be treated as a 35 // single route. 36 type Handler struct { 37 // The primary list of routes to compile and execute. 38 Routes layer4.RouteList `json:"routes,omitempty"` 39 40 // Maximum time connections have to complete the matching phase (the first terminal handler is matched). Default: 3s. 41 MatchingTimeout caddy.Duration `json:"matching_timeout,omitempty"` 42 43 logger *zap.Logger 44 } 45 46 // CaddyModule returns the Caddy module information. 47 func (*Handler) CaddyModule() caddy.ModuleInfo { 48 return caddy.ModuleInfo{ 49 ID: "layer4.handlers.subroute", 50 New: func() caddy.Module { return new(Handler) }, 51 } 52 } 53 54 // Provision sets up the module. 55 func (h *Handler) Provision(ctx caddy.Context) error { 56 h.logger = ctx.Logger(h) 57 58 if h.MatchingTimeout <= 0 { 59 h.MatchingTimeout = caddy.Duration(layer4.MatchingTimeoutDefault) 60 } 61 62 if h.Routes != nil { 63 err := h.Routes.Provision(ctx) 64 if err != nil { 65 return fmt.Errorf("setting up subroutes: %v", err) 66 } 67 } 68 return nil 69 } 70 71 // Handle handles the connections. 72 func (h *Handler) Handle(cx *layer4.Connection, next layer4.Handler) error { 73 subroute := h.Routes.Compile(h.logger, time.Duration(h.MatchingTimeout), next) 74 return subroute.Handle(cx) 75 } 76 77 // UnmarshalCaddyfile sets up the Handler from Caddyfile tokens. Syntax: 78 // 79 // subroute { 80 // matching_timeout <duration> 81 // @a <matcher> [<matcher_args>] 82 // @b { 83 // <matcher> [<matcher_args>] 84 // <matcher> [<matcher_args>] 85 // } 86 // route @a @b { 87 // <handler> [<handler_args>] 88 // } 89 // @c <matcher> { 90 // <matcher_option> [<matcher_option_args>] 91 // } 92 // route @c { 93 // <handler> [<handler_args>] 94 // <handler> { 95 // <handler_option> [<handler_option_args>] 96 // } 97 // } 98 // } 99 func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { 100 d.Next() // consume wrapper name 101 102 // No same-line options are supported 103 if d.CountRemainingArgs() > 0 { 104 return d.ArgErr() 105 } 106 107 if err := layer4.ParseCaddyfileNestedRoutes(d, &h.Routes, &h.MatchingTimeout); err != nil { 108 return err 109 } 110 111 return nil 112 } 113 114 // Interface guards 115 var ( 116 _ caddy.Provisioner = (*Handler)(nil) 117 _ caddyfile.Unmarshaler = (*Handler)(nil) 118 _ layer4.NextHandler = (*Handler)(nil) 119 )