Skip to content

Commit

Permalink
Merge branch 'master' into transfer-encoding-match
Browse files Browse the repository at this point in the history
  • Loading branch information
mholt authored Dec 20, 2024
2 parents 130c868 + ed1c594 commit 86da4e8
Show file tree
Hide file tree
Showing 98 changed files with 2,424 additions and 687 deletions.
10 changes: 5 additions & 5 deletions .github/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ The Caddy project would like to make sure that it stays on top of all practicall

## Supported Versions

| Version | Supported |
| ------- | ------------------ |
| 2.x | ✔️ |
| 1.x | :x: |
| < 1.x | :x: |
| Version | Supported |
| -------- | ----------|
| 2.latest | ✔️ |
| 1.x | :x: |
| < 1.x | :x: |


## Acceptable Scope
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ jobs:
s390x-test:
name: test (s390x on IBM Z)
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]'
if: github.event.pull_request.head.repo.full_name == 'caddyserver/caddy' && github.actor != 'dependabot[bot]'
continue-on-error: true # August 2020: s390x VM is down due to weather and power issues
steps:
- name: Checkout code
Expand Down Expand Up @@ -194,6 +194,7 @@ jobs:

goreleaser-check:
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == 'caddyserver/caddy' && github.actor != 'dependabot[bot]'
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -216,4 +217,4 @@ jobs:
version: latest
args: build --single-target --snapshot
env:
TAG: "master"
TAG: ${{ github.head_ref || github.ref_name }}
2 changes: 1 addition & 1 deletion .github/workflows/cross-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,4 @@ jobs:
continue-on-error: true
working-directory: ./cmd/caddy
run: |
GOOS=$GOOS GOARCH=$GOARCH go build -tags nobadger -trimpath -o caddy-"$GOOS"-$GOARCH 2> /dev/null
GOOS=$GOOS GOARCH=$GOARCH go build -tags=nobadger,nomysql,nopgx -trimpath -o caddy-"$GOOS"-$GOARCH 2> /dev/null
5 changes: 5 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ builds:
- -s -w
tags:
- nobadger
- nomysql
- nopgx

signs:
- cmd: cosign
Expand Down Expand Up @@ -190,6 +192,9 @@ nfpms:
preremove: ./caddy-dist/scripts/preremove.sh
postremove: ./caddy-dist/scripts/postremove.sh

provides:
- httpd

release:
github:
owner: caddyserver
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ $ xcaddy build
4. Initialize a Go module: `go mod init caddy`
5. (Optional) Pin Caddy version: `go get github.com/caddyserver/caddy/v2@version` replacing `version` with a git tag, commit, or branch name.
6. (Optional) Add plugins by adding their import: `_ "import/path/here"`
7. Compile: `go build`
7. Compile: `go build -tags=nobadger,nomysql,nopgx`



Expand Down
2 changes: 1 addition & 1 deletion admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ type AdminPermissions struct {

// newAdminHandler reads admin's config and returns an http.Handler suitable
// for use in an admin endpoint server, which will be listening on listenAddr.
func (admin *AdminConfig) newAdminHandler(addr NetworkAddress, remote bool, ctx Context) adminHandler {
func (admin *AdminConfig) newAdminHandler(addr NetworkAddress, remote bool, _ Context) adminHandler {
muxWrap := adminHandler{mux: http.NewServeMux()}

// secure the local or remote endpoint respectively
Expand Down
4 changes: 2 additions & 2 deletions caddyconfig/caddyfile/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ func (p *parser) doImport(nesting int) error {
// make path relative to the file of the _token_ being processed rather
// than current working directory (issue #867) and then use glob to get
// list of matching filenames
absFile, err := filepath.Abs(p.Dispenser.File())
absFile, err := caddy.FastAbs(p.Dispenser.File())
if err != nil {
return p.Errf("Failed to get absolute path of file: %s: %v", p.Dispenser.File(), err)
}
Expand Down Expand Up @@ -622,7 +622,7 @@ func (p *parser) doSingleImport(importFile string) ([]Token, error) {

// Tack the file path onto these tokens so errors show the imported file's name
// (we use full, absolute path to avoid bugs: issue #1892)
filename, err := filepath.Abs(importFile)
filename, err := caddy.FastAbs(importFile)
if err != nil {
return nil, p.Errf("Failed to get absolute path of file: %s: %v", importFile, err)
}
Expand Down
10 changes: 7 additions & 3 deletions caddyconfig/httpcaddyfile/addresses.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
)

// mapAddressToServerBlocks returns a map of listener address to list of server
// mapAddressToProtocolToServerBlocks returns a map of listener address to list of server
// blocks that will be served on that address. To do this, each server block is
// expanded so that each one is considered individually, although keys of a
// server block that share the same address stay grouped together so the config
Expand Down Expand Up @@ -329,8 +329,12 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad
// use a map to prevent duplication
listeners := map[string]map[string]struct{}{}
for _, lnCfgVal := range lnCfgVals {
for _, lnHost := range lnCfgVal.addresses {
networkAddr, err := caddy.ParseNetworkAddressFromHostPort(lnHost, lnPort)
for _, lnAddr := range lnCfgVal.addresses {
lnNetw, lnHost, _, err := caddy.SplitNetworkAddress(lnAddr)
if err != nil {
return nil, fmt.Errorf("splitting listener address: %v", err)
}
networkAddr, err := caddy.ParseNetworkAddress(caddy.JoinNetworkAddress(lnNetw, lnHost, lnPort))
if err != nil {
return nil, fmt.Errorf("parsing network address: %v", err)
}
Expand Down
46 changes: 45 additions & 1 deletion caddyconfig/httpcaddyfile/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"time"

"github.com/caddyserver/certmagic"
"github.com/mholt/acmez/v2/acme"
"github.com/mholt/acmez/v3/acme"
"go.uber.org/zap/zapcore"

"github.com/caddyserver/caddy/v2"
Expand Down Expand Up @@ -981,6 +981,50 @@ func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue
}
cl.WriterRaw = caddyconfig.JSONModuleObject(wo, "output", moduleName, h.warnings)

case "sampling":
d := h.Dispenser.NewFromNextSegment()
for d.NextArg() {
// consume any tokens on the same line, if any.
}

sampling := &caddy.LogSampling{}
for nesting := d.Nesting(); d.NextBlock(nesting); {
subdir := d.Val()
switch subdir {
case "interval":
if !d.NextArg() {
return nil, d.ArgErr()
}
interval, err := time.ParseDuration(d.Val() + "ns")
if err != nil {
return nil, d.Errf("failed to parse interval: %v", err)
}
sampling.Interval = interval
case "first":
if !d.NextArg() {
return nil, d.ArgErr()
}
first, err := strconv.Atoi(d.Val())
if err != nil {
return nil, d.Errf("failed to parse first: %v", err)
}
sampling.First = first
case "thereafter":
if !d.NextArg() {
return nil, d.ArgErr()
}
thereafter, err := strconv.Atoi(d.Val())
if err != nil {
return nil, d.Errf("failed to parse thereafter: %v", err)
}
sampling.Thereafter = thereafter
default:
return nil, d.Errf("unrecognized subdirective: %s", subdir)
}
}

cl.Sampling = sampling

case "core":
if !h.NextArg() {
return nil, h.ArgErr()
Expand Down
14 changes: 14 additions & 0 deletions caddyconfig/httpcaddyfile/builtins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ func TestLogDirectiveSyntax(t *testing.T) {
output: `{"logging":{"logs":{"default":{"exclude":["http.log.access.name-override"]},"name-override":{"writer":{"filename":"foo.log","output":"file"},"core":{"module":"mock"},"include":["http.log.access.name-override"]}}},"apps":{"http":{"servers":{"srv0":{"listen":[":8080"],"logs":{"default_logger_name":"name-override"}}}}}}`,
expectError: false,
},
{
input: `:8080 {
log {
sampling {
interval 2
first 3
thereafter 4
}
}
}
`,
output: `{"logging":{"logs":{"default":{"exclude":["http.log.access.log0"]},"log0":{"sampling":{"interval":2,"first":3,"thereafter":4},"include":["http.log.access.log0"]}}},"apps":{"http":{"servers":{"srv0":{"listen":[":8080"],"logs":{"default_logger_name":"log0"}}}}}}`,
expectError: false,
},
} {

adapter := caddyfile.Adapter{
Expand Down
77 changes: 50 additions & 27 deletions caddyconfig/httpcaddyfile/httptype.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package httpcaddyfile

import (
"cmp"
"encoding/json"
"fmt"
"net"
Expand Down Expand Up @@ -186,12 +187,25 @@ func (st ServerType) Setup(
return nil, warnings, err
}

// hoist the metrics config from per-server to global
metrics, _ := options["metrics"].(*caddyhttp.Metrics)
for _, s := range servers {
if s.Metrics != nil {
metrics = cmp.Or[*caddyhttp.Metrics](metrics, &caddyhttp.Metrics{})
metrics = &caddyhttp.Metrics{
PerHost: metrics.PerHost || s.Metrics.PerHost,
}
s.Metrics = nil // we don't need it anymore
}
}

// now that each server is configured, make the HTTP app
httpApp := caddyhttp.App{
HTTPPort: tryInt(options["http_port"], &warnings),
HTTPSPort: tryInt(options["https_port"], &warnings),
GracePeriod: tryDuration(options["grace_period"], &warnings),
ShutdownDelay: tryDuration(options["shutdown_delay"], &warnings),
Metrics: metrics,
Servers: servers,
}

Expand Down Expand Up @@ -692,6 +706,16 @@ func (st *ServerType) serversFromPairings(
return specificity(iLongestHost) > specificity(jLongestHost)
})

// collect all hosts that have a wildcard in them
wildcardHosts := []string{}
for _, sblock := range p.serverBlocks {
for _, addr := range sblock.parsedKeys {
if strings.HasPrefix(addr.Host, "*.") {
wildcardHosts = append(wildcardHosts, addr.Host[2:])
}
}
}

var hasCatchAllTLSConnPolicy, addressQualifiesForTLS bool
autoHTTPSWillAddConnPolicy := srv.AutoHTTPS == nil || !srv.AutoHTTPS.Disabled

Expand Down Expand Up @@ -777,13 +801,6 @@ func (st *ServerType) serversFromPairings(
}
}

wildcardHosts := []string{}
for _, addr := range sblock.parsedKeys {
if strings.HasPrefix(addr.Host, "*.") {
wildcardHosts = append(wildcardHosts, addr.Host[2:])
}
}

for _, addr := range sblock.parsedKeys {
// if server only uses HTTP port, auto-HTTPS will not apply
if listenersUseAnyPortOtherThan(srv.Listen, httpPort) {
Expand All @@ -799,18 +816,6 @@ func (st *ServerType) serversFromPairings(
}
}

// If prefer wildcard is enabled, then we add hosts that are
// already covered by the wildcard to the skip list
if srv.AutoHTTPS != nil && srv.AutoHTTPS.PreferWildcard && addr.Scheme == "https" {
baseDomain := addr.Host
if idx := strings.Index(baseDomain, "."); idx != -1 {
baseDomain = baseDomain[idx+1:]
}
if !strings.HasPrefix(addr.Host, "*.") && slices.Contains(wildcardHosts, baseDomain) {
srv.AutoHTTPS.Skip = append(srv.AutoHTTPS.Skip, addr.Host)
}
}

// If TLS is specified as directive, it will also result in 1 or more connection policy being created
// Thus, catch-all address with non-standard port, e.g. :8443, can have TLS enabled without
// specifying prefix "https://"
Expand All @@ -827,6 +832,19 @@ func (st *ServerType) serversFromPairings(
(addr.Scheme != "http" && addr.Port != httpPort && hasTLSEnabled) {
addressQualifiesForTLS = true
}

// If prefer wildcard is enabled, then we add hosts that are
// already covered by the wildcard to the skip list
if addressQualifiesForTLS && srv.AutoHTTPS != nil && srv.AutoHTTPS.PreferWildcard {
baseDomain := addr.Host
if idx := strings.Index(baseDomain, "."); idx != -1 {
baseDomain = baseDomain[idx+1:]
}
if !strings.HasPrefix(addr.Host, "*.") && slices.Contains(wildcardHosts, baseDomain) {
srv.AutoHTTPS.SkipCerts = append(srv.AutoHTTPS.SkipCerts, addr.Host)
}
}

// predict whether auto-HTTPS will add the conn policy for us; if so, we
// may not need to add one for this server
autoHTTPSWillAddConnPolicy = autoHTTPSWillAddConnPolicy &&
Expand Down Expand Up @@ -1448,9 +1466,9 @@ func (st *ServerType) compileEncodedMatcherSets(sblock serverBlock) ([]caddy.Mod

// iterate each pairing of host and path matchers and
// put them into a map for JSON encoding
var matcherSets []map[string]caddyhttp.RequestMatcher
var matcherSets []map[string]caddyhttp.RequestMatcherWithError
for _, mp := range matcherPairs {
matcherSet := make(map[string]caddyhttp.RequestMatcher)
matcherSet := make(map[string]caddyhttp.RequestMatcherWithError)
if len(mp.hostm) > 0 {
matcherSet["host"] = mp.hostm
}
Expand Down Expand Up @@ -1509,12 +1527,17 @@ func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.M
if err != nil {
return err
}
rm, ok := unm.(caddyhttp.RequestMatcher)
if !ok {
return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)

if rm, ok := unm.(caddyhttp.RequestMatcherWithError); ok {
matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
return nil
}
matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
return nil
// nolint:staticcheck
if rm, ok := unm.(caddyhttp.RequestMatcher); ok {
matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
return nil
}
return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
}

// if the next token is quoted, we can assume it's not a matcher name
Expand Down Expand Up @@ -1558,7 +1581,7 @@ func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.M
return nil
}

func encodeMatcherSet(matchers map[string]caddyhttp.RequestMatcher) (caddy.ModuleMap, error) {
func encodeMatcherSet(matchers map[string]caddyhttp.RequestMatcherWithError) (caddy.ModuleMap, error) {
msEncoded := make(caddy.ModuleMap)
for matcherName, val := range matchers {
jsonBytes, err := json.Marshal(val)
Expand Down
Loading

0 comments on commit 86da4e8

Please sign in to comment.