Skip to content

Commit

Permalink
Merge branch 'master' into hurl-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mohammed90 authored Dec 29, 2024
2 parents c718744 + afa778a commit df59b09
Show file tree
Hide file tree
Showing 88 changed files with 2,612 additions and 592 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 @@ -250,7 +250,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 @@ -301,6 +301,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 @@ -323,4 +324,4 @@ jobs:
version: latest
args: build --single-target --snapshot
env:
TAG: "master"
TAG: ${{ github.head_ref || github.ref_name }}
3 changes: 3 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,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 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
63 changes: 60 additions & 3 deletions 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 @@ -84,7 +84,7 @@ func parseBind(h Helper) ([]ConfigValue, error) {

// parseTLS parses the tls directive. Syntax:
//
// tls [<email>|internal]|[<cert_file> <key_file>] {
// tls [<email>|internal|force_automate]|[<cert_file> <key_file>] {
// protocols <min> [<max>]
// ciphers <cipher_suites...>
// curves <curves...>
Expand All @@ -107,6 +107,7 @@ func parseBind(h Helper) ([]ConfigValue, error) {
// dns_challenge_override_domain <domain>
// on_demand
// reuse_private_keys
// force_automate
// eab <key_id> <mac_key>
// issuer <module_name> [...]
// get_certificate <module_name> [...]
Expand All @@ -126,15 +127,18 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
var certManagers []certmagic.Manager
var onDemand bool
var reusePrivateKeys bool
var forceAutomate bool

firstLine := h.RemainingArgs()
switch len(firstLine) {
case 0:
case 1:
if firstLine[0] == "internal" {
internalIssuer = new(caddytls.InternalIssuer)
} else if firstLine[0] == "force_automate" {
forceAutomate = true
} else if !strings.Contains(firstLine[0], "@") {
return nil, h.Err("single argument must either be 'internal' or an email address")
return nil, h.Err("single argument must either be 'internal', 'force_automate', or an email address")
} else {
acmeIssuer = &caddytls.ACMEIssuer{
Email: firstLine[0],
Expand Down Expand Up @@ -569,6 +573,15 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
})
}

// if enabled, the names in the site addresses will be
// added to the automation policies
if forceAutomate {
configVals = append(configVals, ConfigValue{
Class: "tls.force_automate",
Value: true,
})
}

// custom certificate selection
if len(certSelector.AnyTag) > 0 {
cp.CertSelection = &certSelector
Expand Down Expand Up @@ -981,6 +994,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
85 changes: 57 additions & 28 deletions caddyconfig/httpcaddyfile/httptype.go
Original file line number Diff line number Diff line change
Expand Up @@ -706,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 @@ -753,6 +763,14 @@ func (st *ServerType) serversFromPairings(
}
}

// collect hosts that are forced to be automated
forceAutomatedNames := make(map[string]struct{})
if _, ok := sblock.pile["tls.force_automate"]; ok {
for _, host := range hosts {
forceAutomatedNames[host] = struct{}{}
}
}

// tls: connection policies
if cpVals, ok := sblock.pile["tls.connection_policy"]; ok {
// tls connection policies
Expand Down Expand Up @@ -784,20 +802,13 @@ func (st *ServerType) serversFromPairings(
}

// only append this policy if it actually changes something
if !cp.SettingsEmpty() {
if !cp.SettingsEmpty() || mapContains(forceAutomatedNames, hosts) {
srv.TLSConnPolicies = append(srv.TLSConnPolicies, cp)
hasCatchAllTLSConnPolicy = len(hosts) == 0
}
}
}

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 @@ -813,18 +824,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 @@ -841,6 +840,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 @@ -1462,9 +1474,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 @@ -1523,12 +1535,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 @@ -1572,7 +1589,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 Expand Up @@ -1652,6 +1669,18 @@ func listenersUseAnyPortOtherThan(addresses []string, otherPort string) bool {
return false
}

func mapContains[K comparable, V any](m map[K]V, keys []K) bool {
if len(m) == 0 || len(keys) == 0 {
return false
}
for _, key := range keys {
if _, ok := m[key]; ok {
return true
}
}
return false
}

// specificity returns len(s) minus any wildcards (*) and
// placeholders ({...}). Basically, it's a length count
// that penalizes the use of wildcards and placeholders.
Expand Down
Loading

0 comments on commit df59b09

Please sign in to comment.