mirror of
https://github.com/caddyserver/caddy.git
synced 2025-04-24 22:04:04 +08:00
Merge branch 'master' into feat/test-admin-error-handling
This commit is contained in:
commit
8800fda829
@ -111,7 +111,7 @@ archives:
|
||||
- id: default
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
formats: zip
|
||||
name_template: >-
|
||||
{{ .ProjectName }}_
|
||||
{{- .Version }}_
|
||||
|
@ -176,7 +176,7 @@ The docs are also open source. You can contribute to them here: https://github.c
|
||||
|
||||
## Getting help
|
||||
|
||||
- We advise companies using Caddy to secure a support contract through [Ardan Labs](https://www.ardanlabs.com/my/contact-us?dd=caddy) before help is needed.
|
||||
- We advise companies using Caddy to secure a support contract through [Ardan Labs](https://www.ardanlabs.com) before help is needed.
|
||||
|
||||
- A [sponsorship](https://github.com/sponsors/mholt) goes a long way! We can offer private help to sponsors. If Caddy is benefitting your company, please consider a sponsorship. This not only helps fund full-time work to ensure the longevity of the project, it provides your company the resources, support, and discounts you need; along with being a great look for your company to your customers and potential customers!
|
||||
|
||||
|
23
cmd/main.go
23
cmd/main.go
@ -24,6 +24,7 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -33,10 +34,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/KimMachineGun/automemlimit/memlimit"
|
||||
"github.com/caddyserver/certmagic"
|
||||
"github.com/spf13/pflag"
|
||||
"go.uber.org/automaxprocs/maxprocs"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/exp/zapslog"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig"
|
||||
@ -66,12 +69,30 @@ func Main() {
|
||||
os.Exit(caddy.ExitCodeFailedStartup)
|
||||
}
|
||||
|
||||
undo, err := maxprocs.Set()
|
||||
logger := caddy.Log()
|
||||
|
||||
// Configure the maximum number of CPUs to use to match the Linux container quota (if any)
|
||||
// See https://pkg.go.dev/runtime#GOMAXPROCS
|
||||
undo, err := maxprocs.Set(maxprocs.Logger(logger.Sugar().Infof))
|
||||
defer undo()
|
||||
if err != nil {
|
||||
caddy.Log().Warn("failed to set GOMAXPROCS", zap.Error(err))
|
||||
}
|
||||
|
||||
// Configure the maximum memory to use to match the Linux container quota (if any) or system memory
|
||||
// See https://pkg.go.dev/runtime/debug#SetMemoryLimit
|
||||
_, _ = memlimit.SetGoMemLimitWithOpts(
|
||||
memlimit.WithLogger(
|
||||
slog.New(zapslog.NewHandler(logger.Core())),
|
||||
),
|
||||
memlimit.WithProvider(
|
||||
memlimit.ApplyFallback(
|
||||
memlimit.FromCgroup,
|
||||
memlimit.FromSystem,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
if err := defaultFactory.Build().Execute(); err != nil {
|
||||
var exitError *exitError
|
||||
if errors.As(err, &exitError) {
|
||||
|
4
go.mod
4
go.mod
@ -6,6 +6,7 @@ toolchain go1.23.0
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.4.0
|
||||
github.com/KimMachineGun/automemlimit v0.7.0
|
||||
github.com/Masterminds/sprig/v3 v3.3.0
|
||||
github.com/alecthomas/chroma/v2 v2.14.0
|
||||
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b
|
||||
@ -56,13 +57,14 @@ require (
|
||||
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
|
||||
github.com/go-kit/log v0.2.1 // indirect
|
||||
github.com/golang/glog v1.2.2 // indirect
|
||||
github.com/golang/glog v1.2.4 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.8-0.20240110162603-74a5dd331745 // indirect
|
||||
github.com/google/go-tpm v0.9.0 // indirect
|
||||
github.com/google/go-tspi v0.3.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.13.2 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935 // indirect
|
||||
|
8
go.sum
8
go.sum
@ -31,6 +31,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/KimMachineGun/automemlimit v0.7.0 h1:7G06p/dMSf7G8E6oq+f2uOPuVncFyIlDI/pBWK49u88=
|
||||
github.com/KimMachineGun/automemlimit v0.7.0/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
@ -186,8 +188,8 @@ github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPh
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
|
||||
github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc=
|
||||
github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
@ -366,6 +368,8 @@ github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe
|
||||
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
|
||||
github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterbourgon/diskv/v3 v3.0.1 h1:x06SQA46+PKIUftmEujdwSEpIx8kR+M9eLYsUxeYveU=
|
||||
github.com/peterbourgon/diskv/v3 v3.0.1/go.mod h1:kJ5Ny7vLdARGU3WUuy6uzO6T0nb/2gWcT1JiBvRmb5o=
|
||||
|
@ -154,16 +154,16 @@ func (rr *responseRecorder) WriteHeader(statusCode int) {
|
||||
// connections by manually setting headers and writing status 101
|
||||
rr.statusCode = statusCode
|
||||
|
||||
// decide whether we should buffer the response
|
||||
if rr.shouldBuffer == nil {
|
||||
rr.stream = true
|
||||
} else {
|
||||
rr.stream = !rr.shouldBuffer(rr.statusCode, rr.ResponseWriterWrapper.Header())
|
||||
}
|
||||
|
||||
// 1xx responses aren't final; just informational
|
||||
if statusCode < 100 || statusCode > 199 {
|
||||
rr.wroteHeader = true
|
||||
|
||||
// decide whether we should buffer the response
|
||||
if rr.shouldBuffer == nil {
|
||||
rr.stream = true
|
||||
} else {
|
||||
rr.stream = !rr.shouldBuffer(rr.statusCode, rr.ResponseWriterWrapper.Header())
|
||||
}
|
||||
}
|
||||
|
||||
// if informational or not buffered, immediately write header
|
||||
|
@ -2,26 +2,26 @@ package reverseproxy
|
||||
|
||||
import (
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
)
|
||||
|
||||
var reverseProxyMetrics = struct {
|
||||
init sync.Once
|
||||
upstreamsHealthy *prometheus.GaugeVec
|
||||
logger *zap.Logger
|
||||
}{}
|
||||
|
||||
func initReverseProxyMetrics(handler *Handler) {
|
||||
func initReverseProxyMetrics(handler *Handler, registry *prometheus.Registry) {
|
||||
const ns, sub = "caddy", "reverse_proxy"
|
||||
|
||||
upstreamsLabels := []string{"upstream"}
|
||||
reverseProxyMetrics.upstreamsHealthy = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
reverseProxyMetrics.upstreamsHealthy = promauto.With(registry).NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: ns,
|
||||
Subsystem: sub,
|
||||
Name: "upstreams_healthy",
|
||||
@ -35,17 +35,19 @@ type metricsUpstreamsHealthyUpdater struct {
|
||||
handler *Handler
|
||||
}
|
||||
|
||||
func newMetricsUpstreamsHealthyUpdater(handler *Handler) *metricsUpstreamsHealthyUpdater {
|
||||
reverseProxyMetrics.init.Do(func() {
|
||||
initReverseProxyMetrics(handler)
|
||||
})
|
||||
const upstreamsHealthyMetrics caddy.CtxKey = "reverse_proxy_upstreams_healthy"
|
||||
|
||||
func newMetricsUpstreamsHealthyUpdater(handler *Handler, ctx caddy.Context) *metricsUpstreamsHealthyUpdater {
|
||||
if set := ctx.Value(upstreamsHealthyMetrics); set == nil {
|
||||
initReverseProxyMetrics(handler, ctx.GetMetricsRegistry())
|
||||
ctx = ctx.WithValue(upstreamsHealthyMetrics, true)
|
||||
}
|
||||
reverseProxyMetrics.upstreamsHealthy.Reset()
|
||||
|
||||
return &metricsUpstreamsHealthyUpdater{handler}
|
||||
}
|
||||
|
||||
func (m *metricsUpstreamsHealthyUpdater) Init() {
|
||||
func (m *metricsUpstreamsHealthyUpdater) init() {
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
|
@ -382,8 +382,8 @@ func (h *Handler) Provision(ctx caddy.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
upstreamHealthyUpdater := newMetricsUpstreamsHealthyUpdater(h)
|
||||
upstreamHealthyUpdater.Init()
|
||||
upstreamHealthyUpdater := newMetricsUpstreamsHealthyUpdater(h, ctx)
|
||||
upstreamHealthyUpdater.init()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
package caddytls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
@ -55,7 +56,7 @@ func (MatchServerName) CaddyModule() caddy.ModuleInfo {
|
||||
|
||||
// Match matches hello based on SNI.
|
||||
func (m MatchServerName) Match(hello *tls.ClientHelloInfo) bool {
|
||||
repl := caddy.NewReplacer()
|
||||
var repl *caddy.Replacer
|
||||
// caddytls.TestServerNameMatcher calls this function without any context
|
||||
if ctx := hello.Context(); ctx != nil {
|
||||
// In some situations the existing context may have no replacer
|
||||
@ -64,6 +65,10 @@ func (m MatchServerName) Match(hello *tls.ClientHelloInfo) bool {
|
||||
}
|
||||
}
|
||||
|
||||
if repl == nil {
|
||||
repl = caddy.NewReplacer()
|
||||
}
|
||||
|
||||
for _, name := range m {
|
||||
rs := repl.ReplaceAll(name, "")
|
||||
if certmagic.MatchWildcard(hello.ServerName, rs) {
|
||||
@ -224,15 +229,28 @@ func (MatchServerNameRE) CaddyModule() caddy.ModuleInfo {
|
||||
|
||||
// Match matches hello based on SNI using a regular expression.
|
||||
func (m MatchServerNameRE) Match(hello *tls.ClientHelloInfo) bool {
|
||||
repl := caddy.NewReplacer()
|
||||
// caddytls.TestServerNameMatcher calls this function without any context
|
||||
if ctx := hello.Context(); ctx != nil {
|
||||
// Note: caddytls.TestServerNameMatcher calls this function without any context
|
||||
ctx := hello.Context()
|
||||
if ctx == nil {
|
||||
// layer4.Connection implements GetContext() to pass its context here,
|
||||
// since hello.Context() returns nil
|
||||
if mayHaveContext, ok := hello.Conn.(interface{ GetContext() context.Context }); ok {
|
||||
ctx = mayHaveContext.GetContext()
|
||||
}
|
||||
}
|
||||
|
||||
var repl *caddy.Replacer
|
||||
if ctx != nil {
|
||||
// In some situations the existing context may have no replacer
|
||||
if replAny := ctx.Value(caddy.ReplacerCtxKey); replAny != nil {
|
||||
repl = replAny.(*caddy.Replacer)
|
||||
}
|
||||
}
|
||||
|
||||
if repl == nil {
|
||||
repl = caddy.NewReplacer()
|
||||
}
|
||||
|
||||
return m.MatchRegexp.Match(hello.ServerName, repl)
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user