From 2faeac0a104c72e9396717406ecb7c353bf9aa64 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Wed, 25 Sep 2024 16:30:56 -0400 Subject: [PATCH] chore: Use slices package where possible (#6585) * chore: Use slices package where possible * More, mostly using ContainsFunc * Even more slice operations --- admin.go | 19 ++----- caddyconfig/caddyfile/importgraph.go | 8 +-- caddyconfig/httpcaddyfile/directives.go | 39 +++---------- caddyconfig/httpcaddyfile/httptype.go | 33 +++-------- caddyconfig/httpcaddyfile/options.go | 40 ++++++------- caddyconfig/httpcaddyfile/serveroptions.go | 24 +++----- caddyconfig/httpcaddyfile/tlsapp.go | 57 +++++++++---------- modules/caddyevents/app.go | 25 ++++---- modules/caddyhttp/autohttps.go | 16 +----- modules/caddyhttp/encode/encode.go | 10 ++-- .../caddyhttp/fileserver/browsetplcontext.go | 10 ++-- modules/caddyhttp/headers/headers.go | 13 +++-- modules/caddyhttp/map/map.go | 14 +---- modules/caddyhttp/matchers.go | 7 +-- .../caddyhttp/reverseproxy/healthchecks.go | 9 +-- .../caddyhttp/reverseproxy/httptransport.go | 17 ++---- modules/caddyhttp/server.go | 26 +++------ modules/caddyhttp/templates/frontmatter.go | 1 + modules/caddytls/automation.go | 10 ++-- modules/caddytls/certselection.go | 13 ++--- modules/caddytls/matchers.go | 19 +++---- 21 files changed, 142 insertions(+), 268 deletions(-) diff --git a/admin.go b/admin.go index ef78254e..e78adeec 100644 --- a/admin.go +++ b/admin.go @@ -34,6 +34,7 @@ import ( "os" "path" "regexp" + "slices" "strconv" "strings" "sync" @@ -675,13 +676,7 @@ func (remote RemoteAdmin) enforceAccessControls(r *http.Request) error { // key recognized; make sure its HTTP request is permitted for _, accessPerm := range adminAccess.Permissions { // verify method - methodFound := accessPerm.Methods == nil - for _, method := range accessPerm.Methods { - if method == r.Method { - methodFound = true - break - } - } + methodFound := accessPerm.Methods == nil || slices.Contains(accessPerm.Methods, r.Method) if !methodFound { return APIError{ HTTPStatus: http.StatusForbidden, @@ -877,13 +872,9 @@ func (h adminHandler) handleError(w http.ResponseWriter, r *http.Request, err er // a trustworthy/expected value. This helps to mitigate DNS // rebinding attacks. func (h adminHandler) checkHost(r *http.Request) error { - var allowed bool - for _, allowedOrigin := range h.allowedOrigins { - if r.Host == allowedOrigin.Host { - allowed = true - break - } - } + allowed := slices.ContainsFunc(h.allowedOrigins, func(u *url.URL) bool { + return r.Host == u.Host + }) if !allowed { return APIError{ HTTPStatus: http.StatusForbidden, diff --git a/caddyconfig/caddyfile/importgraph.go b/caddyconfig/caddyfile/importgraph.go index d5037fe6..ca859299 100644 --- a/caddyconfig/caddyfile/importgraph.go +++ b/caddyconfig/caddyfile/importgraph.go @@ -16,6 +16,7 @@ package caddyfile import ( "fmt" + "slices" ) type adjacency map[string][]string @@ -91,12 +92,7 @@ func (i *importGraph) areConnected(from, to string) bool { if !ok { return false } - for _, v := range al { - if v == to { - return true - } - } - return false + return slices.Contains(al, to) } func (i *importGraph) willCycle(from, to string) bool { diff --git a/caddyconfig/httpcaddyfile/directives.go b/caddyconfig/httpcaddyfile/directives.go index 6972bb67..19ef4bc0 100644 --- a/caddyconfig/httpcaddyfile/directives.go +++ b/caddyconfig/httpcaddyfile/directives.go @@ -17,6 +17,7 @@ package httpcaddyfile import ( "encoding/json" "net" + "slices" "sort" "strconv" "strings" @@ -100,17 +101,6 @@ var defaultDirectiveOrder = []string{ // plugins or by the user via the "order" global option. var directiveOrder = defaultDirectiveOrder -// directiveIsOrdered returns true if dir is -// a known, ordered (sorted) directive. -func directiveIsOrdered(dir string) bool { - for _, d := range directiveOrder { - if d == dir { - return true - } - } - return false -} - // RegisterDirective registers a unique directive dir with an // associated unmarshaling (setup) function. When directive dir // is encountered in a Caddyfile, setupFunc will be called to @@ -161,7 +151,7 @@ func RegisterHandlerDirective(dir string, setupFunc UnmarshalHandlerFunc) { // EXPERIMENTAL: This API may change or be removed. func RegisterDirectiveOrder(dir string, position Positional, standardDir string) { // check if directive was already ordered - if directiveIsOrdered(dir) { + if slices.Contains(directiveOrder, dir) { panic("directive '" + dir + "' already ordered") } @@ -172,12 +162,7 @@ func RegisterDirectiveOrder(dir string, position Positional, standardDir string) // check if directive exists in standard distribution, since // we can't allow plugins to depend on one another; we can't // guarantee the order that plugins are loaded in. - foundStandardDir := false - for _, d := range defaultDirectiveOrder { - if d == standardDir { - foundStandardDir = true - } - } + foundStandardDir := slices.Contains(defaultDirectiveOrder, standardDir) if !foundStandardDir { panic("the 3rd argument '" + standardDir + "' must be a directive that exists in the standard distribution of Caddy") } @@ -603,23 +588,17 @@ func (sb serverBlock) hostsFromKeysNotHTTP(httpPort string) []string { // hasHostCatchAllKey returns true if sb has a key that // omits a host portion, i.e. it "catches all" hosts. func (sb serverBlock) hasHostCatchAllKey() bool { - for _, addr := range sb.keys { - if addr.Host == "" { - return true - } - } - return false + return slices.ContainsFunc(sb.keys, func(addr Address) bool { + return addr.Host == "" + }) } // isAllHTTP returns true if all sb keys explicitly specify // the http:// scheme func (sb serverBlock) isAllHTTP() bool { - for _, addr := range sb.keys { - if addr.Scheme != "http" { - return false - } - } - return true + return !slices.ContainsFunc(sb.keys, func(addr Address) bool { + return addr.Scheme != "http" + }) } // Positional are the supported modes for ordering directives. diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go index a8a2ae5b..c858ee56 100644 --- a/caddyconfig/httpcaddyfile/httptype.go +++ b/caddyconfig/httpcaddyfile/httptype.go @@ -536,7 +536,7 @@ func (st *ServerType) serversFromPairings( if k == j { continue } - if sliceContains(sblock2.block.GetKeysText(), key) { + if slices.Contains(sblock2.block.GetKeysText(), key) { return nil, fmt.Errorf("ambiguous site definition: %s", key) } } @@ -720,7 +720,7 @@ func (st *ServerType) serversFromPairings( if srv.AutoHTTPS == nil { srv.AutoHTTPS = new(caddyhttp.AutoHTTPSConfig) } - if !sliceContains(srv.AutoHTTPS.Skip, addr.Host) { + if !slices.Contains(srv.AutoHTTPS.Skip, addr.Host) { srv.AutoHTTPS.Skip = append(srv.AutoHTTPS.Skip, addr.Host) } } @@ -734,7 +734,7 @@ func (st *ServerType) serversFromPairings( // https://caddy.community/t/making-sense-of-auto-https-and-why-disabling-it-still-serves-https-instead-of-http/9761 createdTLSConnPolicies, ok := sblock.pile["tls.connection_policy"] hasTLSEnabled := (ok && len(createdTLSConnPolicies) > 0) || - (addr.Host != "" && srv.AutoHTTPS != nil && !sliceContains(srv.AutoHTTPS.Skip, addr.Host)) + (addr.Host != "" && srv.AutoHTTPS != nil && !slices.Contains(srv.AutoHTTPS.Skip, addr.Host)) // we'll need to remember if the address qualifies for auto-HTTPS, so we // can add a TLS conn policy if necessary @@ -1061,7 +1061,7 @@ func consolidateConnPolicies(cps caddytls.ConnectionPolicies) (caddytls.Connecti } else if cps[i].CertSelection != nil && cps[j].CertSelection != nil { // if both have one, then combine AnyTag for _, tag := range cps[j].CertSelection.AnyTag { - if !sliceContains(cps[i].CertSelection.AnyTag, tag) { + if !slices.Contains(cps[i].CertSelection.AnyTag, tag) { cps[i].CertSelection.AnyTag = append(cps[i].CertSelection.AnyTag, tag) } } @@ -1144,7 +1144,7 @@ func appendSubrouteToRouteList(routeList caddyhttp.RouteList, func buildSubroute(routes []ConfigValue, groupCounter counter, needsSorting bool) (*caddyhttp.Subroute, error) { if needsSorting { for _, val := range routes { - if !directiveIsOrdered(val.directive) { + if !slices.Contains(directiveOrder, val.directive) { return nil, fmt.Errorf("directive '%s' is not an ordered HTTP handler, so it cannot be used here - try placing within a route block or using the order global option", val.directive) } } @@ -1354,17 +1354,8 @@ func (st *ServerType) compileEncodedMatcherSets(sblock serverBlock) ([]caddy.Mod // add this server block's keys to the matcher // pair if it doesn't already exist - if addr.Host != "" { - var found bool - for _, h := range chosenMatcherPair.hostm { - if h == addr.Host { - found = true - break - } - } - if !found { - chosenMatcherPair.hostm = append(chosenMatcherPair.hostm, addr.Host) - } + if addr.Host != "" && !slices.Contains(chosenMatcherPair.hostm, addr.Host) { + chosenMatcherPair.hostm = append(chosenMatcherPair.hostm, addr.Host) } } @@ -1540,16 +1531,6 @@ func tryDuration(val any, warnings *[]caddyconfig.Warning) caddy.Duration { return durationVal } -// sliceContains returns true if needle is in haystack. -func sliceContains(haystack []string, needle string) bool { - for _, s := range haystack { - if s == needle { - return true - } - } - return false -} - // listenersUseAnyPortOtherThan returns true if there are any // listeners in addresses that use a port which is not otherPort. // Mostly borrowed from unexported method in caddyhttp package. diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go index db9be52c..53687d32 100644 --- a/caddyconfig/httpcaddyfile/options.go +++ b/caddyconfig/httpcaddyfile/options.go @@ -15,6 +15,7 @@ package httpcaddyfile import ( + "slices" "strconv" "github.com/caddyserver/certmagic" @@ -110,17 +111,12 @@ func parseOptOrder(d *caddyfile.Dispenser, _ any) (any, error) { } pos := Positional(d.Val()) - newOrder := directiveOrder + // if directive already had an order, drop it + newOrder := slices.DeleteFunc(directiveOrder, func(d string) bool { + return d == dirName + }) - // if directive exists, first remove it - for i, d := range newOrder { - if d == dirName { - newOrder = append(newOrder[:i], newOrder[i+1:]...) - break - } - } - - // act on the positional + // act on the positional; if it's First or Last, we're done right away switch pos { case First: newOrder = append([]string{dirName}, newOrder...) @@ -129,6 +125,7 @@ func parseOptOrder(d *caddyfile.Dispenser, _ any) (any, error) { } directiveOrder = newOrder return newOrder, nil + case Last: newOrder = append(newOrder, dirName) if d.NextArg() { @@ -136,8 +133,11 @@ func parseOptOrder(d *caddyfile.Dispenser, _ any) (any, error) { } directiveOrder = newOrder return newOrder, nil + + // if it's Before or After, continue case Before: case After: + default: return nil, d.Errf("unknown positional '%s'", pos) } @@ -151,17 +151,17 @@ func parseOptOrder(d *caddyfile.Dispenser, _ any) (any, error) { return nil, d.ArgErr() } - // insert directive into proper position - for i, d := range newOrder { - if d == otherDir { - if pos == Before { - newOrder = append(newOrder[:i], append([]string{dirName}, newOrder[i:]...)...) - } else if pos == After { - newOrder = append(newOrder[:i+1], append([]string{dirName}, newOrder[i+1:]...)...) - } - break - } + // get the position of the target directive + targetIndex := slices.Index(newOrder, otherDir) + if targetIndex == -1 { + return nil, d.Errf("directive '%s' not found", otherDir) } + // if we're inserting after, we need to increment the index to go after + if pos == After { + targetIndex++ + } + // insert the directive into the new order + newOrder = slices.Insert(newOrder, targetIndex, dirName) directiveOrder = newOrder diff --git a/caddyconfig/httpcaddyfile/serveroptions.go b/caddyconfig/httpcaddyfile/serveroptions.go index 4246cd7d..7087cdba 100644 --- a/caddyconfig/httpcaddyfile/serveroptions.go +++ b/caddyconfig/httpcaddyfile/serveroptions.go @@ -17,6 +17,7 @@ package httpcaddyfile import ( "encoding/json" "fmt" + "slices" "github.com/dustin/go-humanize" @@ -180,7 +181,7 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) { if proto != "h1" && proto != "h2" && proto != "h2c" && proto != "h3" { return nil, d.Errf("unknown protocol '%s': expected h1, h2, h2c, or h3", proto) } - if sliceContains(serverOpts.Protocols, proto) { + if slices.Contains(serverOpts.Protocols, proto) { return nil, d.Errf("protocol %s specified more than once", proto) } serverOpts.Protocols = append(serverOpts.Protocols, proto) @@ -229,7 +230,7 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) { case "client_ip_headers": headers := d.RemainingArgs() for _, header := range headers { - if sliceContains(serverOpts.ClientIPHeaders, header) { + if slices.Contains(serverOpts.ClientIPHeaders, header) { return nil, d.Errf("client IP header %s specified more than once", header) } serverOpts.ClientIPHeaders = append(serverOpts.ClientIPHeaders, header) @@ -288,24 +289,15 @@ func applyServerOptions( for key, server := range servers { // find the options that apply to this server - opts := func() *serverOptions { - for _, entry := range serverOpts { - if entry.ListenerAddress == "" { - return &entry - } - for _, listener := range server.Listen { - if entry.ListenerAddress == listener { - return &entry - } - } - } - return nil - }() + optsIndex := slices.IndexFunc(serverOpts, func(s serverOptions) bool { + return s.ListenerAddress == "" || slices.Contains(server.Listen, s.ListenerAddress) + }) // if none apply, then move to the next server - if opts == nil { + if optsIndex == -1 { continue } + opts := serverOpts[optsIndex] // set all the options server.ListenerWrappersRaw = opts.ListenerWrappersRaw diff --git a/caddyconfig/httpcaddyfile/tlsapp.go b/caddyconfig/httpcaddyfile/tlsapp.go index f69e2c54..157a3113 100644 --- a/caddyconfig/httpcaddyfile/tlsapp.go +++ b/caddyconfig/httpcaddyfile/tlsapp.go @@ -19,6 +19,7 @@ import ( "encoding/json" "fmt" "reflect" + "slices" "sort" "strconv" "strings" @@ -57,19 +58,20 @@ func (st ServerType) buildTLSApp( for _, pair := range pairings { for _, sb := range pair.serverBlocks { for _, addr := range sb.keys { - if addr.Host == "" { - // this server block has a hostless key, now - // go through and add all the hosts to the set - for _, otherAddr := range sb.keys { - if otherAddr.Original == addr.Original { - continue - } - if otherAddr.Host != "" && otherAddr.Scheme != "http" && otherAddr.Port != httpPort { - httpsHostsSharedWithHostlessKey[otherAddr.Host] = struct{}{} - } - } - break + if addr.Host != "" { + continue } + // this server block has a hostless key, now + // go through and add all the hosts to the set + for _, otherAddr := range sb.keys { + if otherAddr.Original == addr.Original { + continue + } + if otherAddr.Host != "" && otherAddr.Scheme != "http" && otherAddr.Port != httpPort { + httpsHostsSharedWithHostlessKey[otherAddr.Host] = struct{}{} + } + } + break } } } @@ -465,7 +467,7 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]any) e if globalACMECA != nil && acmeIssuer.CA == "" { acmeIssuer.CA = globalACMECA.(string) } - if globalACMECARoot != nil && !sliceContains(acmeIssuer.TrustedRootsPEMFiles, globalACMECARoot.(string)) { + if globalACMECARoot != nil && !slices.Contains(acmeIssuer.TrustedRootsPEMFiles, globalACMECARoot.(string)) { acmeIssuer.TrustedRootsPEMFiles = append(acmeIssuer.TrustedRootsPEMFiles, globalACMECARoot.(string)) } if globalACMEDNS != nil && (acmeIssuer.Challenges == nil || acmeIssuer.Challenges.DNS == nil) { @@ -580,7 +582,7 @@ func consolidateAutomationPolicies(aps []*caddytls.AutomationPolicy) []*caddytls if !automationPolicyHasAllPublicNames(aps[i]) { // if this automation policy has internal names, we might as well remove it // so auto-https can implicitly use the internal issuer - aps = append(aps[:i], aps[i+1:]...) + aps = slices.Delete(aps, i, i+1) i-- } } @@ -597,7 +599,7 @@ outer: for j := i + 1; j < len(aps); j++ { // if they're exactly equal in every way, just keep one of them if reflect.DeepEqual(aps[i], aps[j]) { - aps = append(aps[:j], aps[j+1:]...) + aps = slices.Delete(aps, j, j+1) // must re-evaluate current i against next j; can't skip it! // even if i decrements to -1, will be incremented to 0 immediately i-- @@ -627,18 +629,18 @@ outer: // cause example.com to be served by the less specific policy for // '*.com', which might be different (yes we've seen this happen) if automationPolicyShadows(i, aps) >= j { - aps = append(aps[:i], aps[i+1:]...) + aps = slices.Delete(aps, i, i+1) i-- continue outer } } else { // avoid repeated subjects for _, subj := range aps[j].SubjectsRaw { - if !sliceContains(aps[i].SubjectsRaw, subj) { + if !slices.Contains(aps[i].SubjectsRaw, subj) { aps[i].SubjectsRaw = append(aps[i].SubjectsRaw, subj) } } - aps = append(aps[:j], aps[j+1:]...) + aps = slices.Delete(aps, j, j+1) j-- } } @@ -658,13 +660,9 @@ func automationPolicyIsSubset(a, b *caddytls.AutomationPolicy) bool { return false } for _, aSubj := range a.SubjectsRaw { - var inSuperset bool - for _, bSubj := range b.SubjectsRaw { - if certmagic.MatchWildcard(aSubj, bSubj) { - inSuperset = true - break - } - } + inSuperset := slices.ContainsFunc(b.SubjectsRaw, func(bSubj string) bool { + return certmagic.MatchWildcard(aSubj, bSubj) + }) if !inSuperset { return false } @@ -709,12 +707,9 @@ func subjectQualifiesForPublicCert(ap *caddytls.AutomationPolicy, subj string) b // automationPolicyHasAllPublicNames returns true if all the names on the policy // do NOT qualify for public certs OR are tailscale domains. func automationPolicyHasAllPublicNames(ap *caddytls.AutomationPolicy) bool { - for _, subj := range ap.SubjectsRaw { - if !subjectQualifiesForPublicCert(ap, subj) || isTailscaleDomain(subj) { - return false - } - } - return true + return !slices.ContainsFunc(ap.SubjectsRaw, func(i string) bool { + return !subjectQualifiesForPublicCert(ap, i) || isTailscaleDomain(i) + }) } func isTailscaleDomain(name string) bool { diff --git a/modules/caddyevents/app.go b/modules/caddyevents/app.go index fe76a675..2e4a6f2c 100644 --- a/modules/caddyevents/app.go +++ b/modules/caddyevents/app.go @@ -124,18 +124,19 @@ func (app *App) Provision(ctx caddy.Context) error { app.subscriptions = make(map[string]map[caddy.ModuleID][]Handler) for _, sub := range app.Subscriptions { - if sub.HandlersRaw != nil { - handlersIface, err := ctx.LoadModule(sub, "HandlersRaw") - if err != nil { - return fmt.Errorf("loading event subscriber modules: %v", err) - } - for _, h := range handlersIface.([]any) { - sub.Handlers = append(sub.Handlers, h.(Handler)) - } - if len(sub.Handlers) == 0 { - // pointless to bind without any handlers - return fmt.Errorf("no handlers defined") - } + if sub.HandlersRaw == nil { + continue + } + handlersIface, err := ctx.LoadModule(sub, "HandlersRaw") + if err != nil { + return fmt.Errorf("loading event subscriber modules: %v", err) + } + for _, h := range handlersIface.([]any) { + sub.Handlers = append(sub.Handlers, h.(Handler)) + } + if len(sub.Handlers) == 0 { + // pointless to bind without any handlers + return fmt.Errorf("no handlers defined") } } diff --git a/modules/caddyhttp/autohttps.go b/modules/caddyhttp/autohttps.go index 263cd14c..ea5a07b3 100644 --- a/modules/caddyhttp/autohttps.go +++ b/modules/caddyhttp/autohttps.go @@ -17,6 +17,7 @@ package caddyhttp import ( "fmt" "net/http" + "slices" "strconv" "strings" @@ -66,17 +67,6 @@ type AutoHTTPSConfig struct { IgnoreLoadedCerts bool `json:"ignore_loaded_certificates,omitempty"` } -// Skipped returns true if name is in skipSlice, which -// should be either the Skip or SkipCerts field on ahc. -func (ahc AutoHTTPSConfig) Skipped(name string, skipSlice []string) bool { - for _, n := range skipSlice { - if name == n { - return true - } - } - return false -} - // automaticHTTPSPhase1 provisions all route matchers, determines // which domain names found in the routes qualify for automatic // HTTPS, and sets up HTTP->HTTPS redirects. This phase must occur @@ -158,7 +148,7 @@ func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) er return fmt.Errorf("%s: route %d, matcher set %d, matcher %d, host matcher %d: %v", srvName, routeIdx, matcherSetIdx, matcherIdx, hostMatcherIdx, err) } - if !srv.AutoHTTPS.Skipped(d, srv.AutoHTTPS.Skip) { + if !slices.Contains(srv.AutoHTTPS.Skip, d) { serverDomainSet[d] = struct{}{} } } @@ -193,7 +183,7 @@ func (app *App) automaticHTTPSPhase1(ctx caddy.Context, repl *caddy.Replacer) er } else { for d := range serverDomainSet { if certmagic.SubjectQualifiesForCert(d) && - !srv.AutoHTTPS.Skipped(d, srv.AutoHTTPS.SkipCerts) { + !slices.Contains(srv.AutoHTTPS.SkipCerts, d) { // if a certificate for this name is already loaded, // don't obtain another one for it, unless we are // supposed to ignore loaded certificates diff --git a/modules/caddyhttp/encode/encode.go b/modules/caddyhttp/encode/encode.go index 00e50727..f0d56a90 100644 --- a/modules/caddyhttp/encode/encode.go +++ b/modules/caddyhttp/encode/encode.go @@ -24,6 +24,7 @@ import ( "io" "math" "net/http" + "slices" "sort" "strconv" "strings" @@ -441,12 +442,9 @@ func AcceptedEncodings(r *http.Request, preferredOrder []string) []string { } // set server preference - prefOrder := -1 - for i, p := range preferredOrder { - if encName == p { - prefOrder = len(preferredOrder) - i - break - } + prefOrder := slices.Index(preferredOrder, encName) + if prefOrder > -1 { + prefOrder = len(preferredOrder) - prefOrder } prefs = append(prefs, encodingPreference{ diff --git a/modules/caddyhttp/fileserver/browsetplcontext.go b/modules/caddyhttp/fileserver/browsetplcontext.go index 37e1cc3d..8e5d138f 100644 --- a/modules/caddyhttp/fileserver/browsetplcontext.go +++ b/modules/caddyhttp/fileserver/browsetplcontext.go @@ -21,6 +21,7 @@ import ( "os" "path" "path/filepath" + "slices" "sort" "strconv" "strings" @@ -281,12 +282,9 @@ type fileInfo struct { // HasExt returns true if the filename has any of the given suffixes, case-insensitive. func (fi fileInfo) HasExt(exts ...string) bool { - for _, ext := range exts { - if strings.HasSuffix(strings.ToLower(fi.Name), strings.ToLower(ext)) { - return true - } - } - return false + return slices.ContainsFunc(exts, func(ext string) bool { + return strings.HasSuffix(strings.ToLower(fi.Name), strings.ToLower(ext)) + }) } // HumanSize returns the size of the file as a diff --git a/modules/caddyhttp/headers/headers.go b/modules/caddyhttp/headers/headers.go index bdb185f4..a3279d91 100644 --- a/modules/caddyhttp/headers/headers.go +++ b/modules/caddyhttp/headers/headers.go @@ -135,13 +135,14 @@ type HeaderOps struct { func (ops *HeaderOps) Provision(_ caddy.Context) error { for fieldName, replacements := range ops.Replace { for i, r := range replacements { - if r.SearchRegexp != "" { - re, err := regexp.Compile(r.SearchRegexp) - if err != nil { - return fmt.Errorf("replacement %d for header field '%s': %v", i, fieldName, err) - } - replacements[i].re = re + if r.SearchRegexp == "" { + continue } + re, err := regexp.Compile(r.SearchRegexp) + if err != nil { + return fmt.Errorf("replacement %d for header field '%s': %v", i, fieldName, err) + } + replacements[i].re = re } } return nil diff --git a/modules/caddyhttp/map/map.go b/modules/caddyhttp/map/map.go index 336f2572..d02085e7 100644 --- a/modules/caddyhttp/map/map.go +++ b/modules/caddyhttp/map/map.go @@ -18,6 +18,7 @@ import ( "fmt" "net/http" "regexp" + "slices" "strings" "github.com/caddyserver/caddy/v2" @@ -126,7 +127,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhtt // defer work until a variable is actually evaluated by using replacer's Map callback repl.Map(func(key string) (any, bool) { // return early if the variable is not even a configured destination - destIdx := h.destinationIndex(key) + destIdx := slices.Index(h.Destinations, key) if destIdx < 0 { return nil, false } @@ -170,17 +171,6 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhtt return next.ServeHTTP(w, r) } -// destinationIndex returns the positional index of the destination -// is name is a known destination; otherwise it returns -1. -func (h Handler) destinationIndex(name string) int { - for i, dest := range h.Destinations { - if dest == name { - return i - } - } - return -1 -} - // Mapping describes a mapping from input to outputs. type Mapping struct { // The input value to match. Must be distinct from other mappings. diff --git a/modules/caddyhttp/matchers.go b/modules/caddyhttp/matchers.go index b7952ab6..a0bc6d63 100644 --- a/modules/caddyhttp/matchers.go +++ b/modules/caddyhttp/matchers.go @@ -764,12 +764,7 @@ func (m *MatchMethod) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { // Match returns true if r matches m. func (m MatchMethod) Match(r *http.Request) bool { - for _, method := range m { - if r.Method == method { - return true - } - } - return false + return slices.Contains(m, r.Method) } // CELLibrary produces options that expose this matcher for use in CEL diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index 179805f2..319cc924 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -23,6 +23,7 @@ import ( "net/url" "regexp" "runtime/debug" + "slices" "strconv" "strings" "time" @@ -397,12 +398,8 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ u.Scheme = "https" // if the port is in the except list, flip back to HTTP - if ht, ok := h.Transport.(*HTTPTransport); ok { - for _, exceptPort := range ht.TLS.ExceptPorts { - if exceptPort == port { - u.Scheme = "http" - } - } + if ht, ok := h.Transport.(*HTTPTransport); ok && slices.Contains(ht.TLS.ExceptPorts, port) { + u.Scheme = "http" } } diff --git a/modules/caddyhttp/reverseproxy/httptransport.go b/modules/caddyhttp/reverseproxy/httptransport.go index 144960cf..bc823378 100644 --- a/modules/caddyhttp/reverseproxy/httptransport.go +++ b/modules/caddyhttp/reverseproxy/httptransport.go @@ -27,6 +27,7 @@ import ( "net/url" "os" "reflect" + "slices" "strings" "time" @@ -381,7 +382,7 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e rt.DisableCompression = !*h.Compression } - if sliceContains(h.Versions, "2") { + if slices.Contains(h.Versions, "2") { if err := http2.ConfigureTransport(rt); err != nil { return nil, err } @@ -400,13 +401,13 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e return nil, fmt.Errorf("making TLS client config for HTTP/3 transport: %v", err) } } - } else if len(h.Versions) > 1 && sliceContains(h.Versions, "3") { + } else if len(h.Versions) > 1 && slices.Contains(h.Versions, "3") { return nil, fmt.Errorf("if HTTP/3 is enabled to the upstream, no other HTTP versions are supported") } // if h2c is enabled, configure its transport (std lib http.Transport // does not "HTTP/2 over cleartext TCP") - if sliceContains(h.Versions, "h2c") { + if slices.Contains(h.Versions, "h2c") { // crafting our own http2.Transport doesn't allow us to utilize // most of the customizations/preferences on the http.Transport, // because, for some reason, only http2.ConfigureTransport() @@ -783,16 +784,6 @@ func decodeBase64DERCert(certStr string) (*x509.Certificate, error) { return x509.ParseCertificate(derBytes) } -// sliceContains returns true if needle is in haystack. -func sliceContains(haystack []string, needle string) bool { - for _, s := range haystack { - if s == needle { - return true - } - } - return false -} - // Interface guards var ( _ caddy.Provisioner = (*HTTPTransport)(nil) diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index 54b1c3b3..ece3f1cd 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -25,6 +25,7 @@ import ( "net/netip" "net/url" "runtime" + "slices" "strings" "sync" "time" @@ -543,12 +544,9 @@ func (s *Server) hasListenerAddress(fullAddr string) bool { } func (s *Server) hasTLSClientAuth() bool { - for _, cp := range s.TLSConnPolicies { - if cp.ClientAuthentication != nil && cp.ClientAuthentication.Active() { - return true - } - } - return false + return slices.ContainsFunc(s.TLSConnPolicies, func(cp *caddytls.ConnectionPolicy) bool { + return cp.ClientAuthentication != nil && cp.ClientAuthentication.Active() + }) } // findLastRouteWithHostMatcher returns the index of the last route @@ -849,12 +847,7 @@ func (s *Server) logRequest( // protocol returns true if the protocol proto is configured/enabled. func (s *Server) protocol(proto string) bool { - for _, p := range s.Protocols { - if p == proto { - return true - } - } - return false + return slices.Contains(s.Protocols, proto) } // Listeners returns the server's listeners. These are active listeners, @@ -959,12 +952,9 @@ func determineTrustedProxy(r *http.Request, s *Server) (bool, string) { // isTrustedClientIP returns true if the given IP address is // in the list of trusted IP ranges. func isTrustedClientIP(ipAddr netip.Addr, trusted []netip.Prefix) bool { - for _, ipRange := range trusted { - if ipRange.Contains(ipAddr) { - return true - } - } - return false + return slices.ContainsFunc(trusted, func(prefix netip.Prefix) bool { + return prefix.Contains(ipAddr) + }) } // trustedRealClientIP finds the client IP from the request assuming it is diff --git a/modules/caddyhttp/templates/frontmatter.go b/modules/caddyhttp/templates/frontmatter.go index 3f7bd0cc..fb62a418 100644 --- a/modules/caddyhttp/templates/frontmatter.go +++ b/modules/caddyhttp/templates/frontmatter.go @@ -40,6 +40,7 @@ func extractFrontMatter(input string) (map[string]any, string, error) { if firstLine == fmType.FenceOpen { closingFence = fmType.FenceClose fmParser = fmType.ParseFunc + break } } diff --git a/modules/caddytls/automation.go b/modules/caddytls/automation.go index e2e02221..1f1042ba 100644 --- a/modules/caddytls/automation.go +++ b/modules/caddytls/automation.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "net" + "slices" "strings" "github.com/caddyserver/certmagic" @@ -373,12 +374,9 @@ func (ap *AutomationPolicy) Subjects() []string { // AllInternalSubjects returns true if all the subjects on this policy are internal. func (ap *AutomationPolicy) AllInternalSubjects() bool { - for _, subj := range ap.subjects { - if !certmagic.SubjectIsInternal(subj) { - return false - } - } - return true + return !slices.ContainsFunc(ap.subjects, func(s string) bool { + return !certmagic.SubjectIsInternal(s) + }) } func (ap *AutomationPolicy) onlyInternalIssuer() bool { diff --git a/modules/caddytls/certselection.go b/modules/caddytls/certselection.go index 84ca2e11..a561e3a1 100644 --- a/modules/caddytls/certselection.go +++ b/modules/caddytls/certselection.go @@ -20,6 +20,7 @@ import ( "encoding/json" "fmt" "math/big" + "slices" "github.com/caddyserver/certmagic" @@ -72,15 +73,9 @@ nextChoice: } if len(p.SubjectOrganization) > 0 { - var found bool - for _, subjOrg := range p.SubjectOrganization { - for _, org := range cert.Leaf.Subject.Organization { - if subjOrg == org { - found = true - break - } - } - } + found := slices.ContainsFunc(p.SubjectOrganization, func(s string) bool { + return slices.Contains(cert.Leaf.Subject.Organization, s) + }) if !found { continue } diff --git a/modules/caddytls/matchers.go b/modules/caddytls/matchers.go index f44b4c02..a74d6ea8 100644 --- a/modules/caddytls/matchers.go +++ b/modules/caddytls/matchers.go @@ -20,6 +20,7 @@ import ( "net" "net/netip" "regexp" + "slices" "strconv" "strings" @@ -321,12 +322,9 @@ func (MatchRemoteIP) parseIPRange(str string) ([]netip.Prefix, error) { } func (MatchRemoteIP) matches(ip netip.Addr, ranges []netip.Prefix) bool { - for _, ipRange := range ranges { - if ipRange.Contains(ip) { - return true - } - } - return false + return slices.ContainsFunc(ranges, func(prefix netip.Prefix) bool { + return prefix.Contains(ip) + }) } // UnmarshalCaddyfile sets up the MatchRemoteIP from Caddyfile tokens. Syntax: @@ -439,12 +437,9 @@ func (MatchLocalIP) parseIPRange(str string) ([]netip.Prefix, error) { } func (MatchLocalIP) matches(ip netip.Addr, ranges []netip.Prefix) bool { - for _, ipRange := range ranges { - if ipRange.Contains(ip) { - return true - } - } - return false + return slices.ContainsFunc(ranges, func(prefix netip.Prefix) bool { + return prefix.Contains(ip) + }) } // UnmarshalCaddyfile sets up the MatchLocalIP from Caddyfile tokens. Syntax: