Merge branch 'master' into golangcilint-v2
commit
cf77755bec
14
admin.go
14
admin.go
|
@ -424,6 +424,13 @@ func replaceLocalAdminServer(cfg *Config, ctx Context) error {
|
||||||
|
|
||||||
handler := cfg.Admin.newAdminHandler(addr, false, ctx)
|
handler := cfg.Admin.newAdminHandler(addr, false, ctx)
|
||||||
|
|
||||||
|
// run the provisioners for loaded modules to make sure local
|
||||||
|
// state is properly re-initialized in the new admin server
|
||||||
|
err = cfg.Admin.provisionAdminRouters(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
ln, err := addr.Listen(context.TODO(), 0, net.ListenConfig{})
|
ln, err := addr.Listen(context.TODO(), 0, net.ListenConfig{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -545,6 +552,13 @@ func replaceRemoteAdminServer(ctx Context, cfg *Config) error {
|
||||||
// because we are using TLS authentication instead
|
// because we are using TLS authentication instead
|
||||||
handler := cfg.Admin.newAdminHandler(addr, true, ctx)
|
handler := cfg.Admin.newAdminHandler(addr, true, ctx)
|
||||||
|
|
||||||
|
// run the provisioners for loaded modules to make sure local
|
||||||
|
// state is properly re-initialized in the new admin server
|
||||||
|
err = cfg.Admin.provisionAdminRouters(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// create client certificate pool for TLS mutual auth, and extract public keys
|
// create client certificate pool for TLS mutual auth, and extract public keys
|
||||||
// so that we can enforce access controls at the application layer
|
// so that we can enforce access controls at the application layer
|
||||||
clientCertPool := x509.NewCertPool()
|
clientCertPool := x509.NewCertPool()
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -335,9 +336,7 @@ func TestAdminHandlerBuiltinRouteErrors(t *testing.T) {
|
||||||
|
|
||||||
func testGetMetricValue(labels map[string]string) float64 {
|
func testGetMetricValue(labels map[string]string) float64 {
|
||||||
promLabels := prometheus.Labels{}
|
promLabels := prometheus.Labels{}
|
||||||
for k, v := range labels {
|
maps.Copy(promLabels, labels)
|
||||||
promLabels[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
metric, err := adminMetrics.requestErrors.GetMetricWith(promLabels)
|
metric, err := adminMetrics.requestErrors.GetMetricWith(promLabels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -377,9 +376,7 @@ func (m *mockModule) CaddyModule() ModuleInfo {
|
||||||
|
|
||||||
func TestNewAdminHandlerRouterRegistration(t *testing.T) {
|
func TestNewAdminHandlerRouterRegistration(t *testing.T) {
|
||||||
originalModules := make(map[string]ModuleInfo)
|
originalModules := make(map[string]ModuleInfo)
|
||||||
for k, v := range modules {
|
maps.Copy(originalModules, modules)
|
||||||
originalModules[k] = v
|
|
||||||
}
|
|
||||||
defer func() {
|
defer func() {
|
||||||
modules = originalModules
|
modules = originalModules
|
||||||
}()
|
}()
|
||||||
|
@ -479,9 +476,7 @@ func TestAdminRouterProvisioning(t *testing.T) {
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
originalModules := make(map[string]ModuleInfo)
|
originalModules := make(map[string]ModuleInfo)
|
||||||
for k, v := range modules {
|
maps.Copy(originalModules, modules)
|
||||||
originalModules[k] = v
|
|
||||||
}
|
|
||||||
defer func() {
|
defer func() {
|
||||||
modules = originalModules
|
modules = originalModules
|
||||||
}()
|
}()
|
||||||
|
@ -774,9 +769,7 @@ func (m *mockIssuerModule) CaddyModule() ModuleInfo {
|
||||||
|
|
||||||
func TestManageIdentity(t *testing.T) {
|
func TestManageIdentity(t *testing.T) {
|
||||||
originalModules := make(map[string]ModuleInfo)
|
originalModules := make(map[string]ModuleInfo)
|
||||||
for k, v := range modules {
|
maps.Copy(originalModules, modules)
|
||||||
originalModules[k] = v
|
|
||||||
}
|
|
||||||
defer func() {
|
defer func() {
|
||||||
modules = originalModules
|
modules = originalModules
|
||||||
}()
|
}()
|
||||||
|
|
16
caddy.go
16
caddy.go
|
@ -505,14 +505,6 @@ func provisionContext(newCfg *Config, replaceAdminServer bool) (Context, error)
|
||||||
return ctx, err
|
return ctx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// start the admin endpoint (and stop any prior one)
|
|
||||||
if replaceAdminServer {
|
|
||||||
err = replaceLocalAdminServer(newCfg, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return ctx, fmt.Errorf("starting caddy administration endpoint: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the new filesystem map
|
// create the new filesystem map
|
||||||
newCfg.fileSystems = &filesystems.FileSystemMap{}
|
newCfg.fileSystems = &filesystems.FileSystemMap{}
|
||||||
|
|
||||||
|
@ -544,6 +536,14 @@ func provisionContext(newCfg *Config, replaceAdminServer bool) (Context, error)
|
||||||
return ctx, err
|
return ctx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start the admin endpoint (and stop any prior one)
|
||||||
|
if replaceAdminServer {
|
||||||
|
err = replaceLocalAdminServer(newCfg, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return ctx, fmt.Errorf("starting caddy administration endpoint: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load and Provision each app and their submodules
|
// Load and Provision each app and their submodules
|
||||||
err = func() error {
|
err = func() error {
|
||||||
for appName := range newCfg.AppsRaw {
|
for appName := range newCfg.AppsRaw {
|
||||||
|
|
|
@ -16,6 +16,7 @@ package httpcaddyfile
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"maps"
|
||||||
"net"
|
"net"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -367,9 +368,7 @@ func parseSegmentAsConfig(h Helper) ([]ConfigValue, error) {
|
||||||
// copy existing matcher definitions so we can augment
|
// copy existing matcher definitions so we can augment
|
||||||
// new ones that are defined only in this scope
|
// new ones that are defined only in this scope
|
||||||
matcherDefs := make(map[string]caddy.ModuleMap, len(h.matcherDefs))
|
matcherDefs := make(map[string]caddy.ModuleMap, len(h.matcherDefs))
|
||||||
for key, val := range h.matcherDefs {
|
maps.Copy(matcherDefs, h.matcherDefs)
|
||||||
matcherDefs[key] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
// find and extract any embedded matcher definitions in this scope
|
// find and extract any embedded matcher definitions in this scope
|
||||||
for i := 0; i < len(segments); i++ {
|
for i := 0; i < len(segments); i++ {
|
||||||
|
@ -485,12 +484,29 @@ func sortRoutes(routes []ConfigValue) {
|
||||||
// we can only confidently compare path lengths if both
|
// we can only confidently compare path lengths if both
|
||||||
// directives have a single path to match (issue #5037)
|
// directives have a single path to match (issue #5037)
|
||||||
if iPathLen > 0 && jPathLen > 0 {
|
if iPathLen > 0 && jPathLen > 0 {
|
||||||
|
// trim the trailing wildcard if there is one
|
||||||
|
iPathTrimmed := strings.TrimSuffix(iPM[0], "*")
|
||||||
|
jPathTrimmed := strings.TrimSuffix(jPM[0], "*")
|
||||||
|
|
||||||
// if both paths are the same except for a trailing wildcard,
|
// if both paths are the same except for a trailing wildcard,
|
||||||
// sort by the shorter path first (which is more specific)
|
// sort by the shorter path first (which is more specific)
|
||||||
if strings.TrimSuffix(iPM[0], "*") == strings.TrimSuffix(jPM[0], "*") {
|
if iPathTrimmed == jPathTrimmed {
|
||||||
return iPathLen < jPathLen
|
return iPathLen < jPathLen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we use the trimmed length to compare the paths
|
||||||
|
// https://github.com/caddyserver/caddy/issues/7012#issuecomment-2870142195
|
||||||
|
// credit to https://github.com/Hellio404
|
||||||
|
// for sorts with many items, mixing matchers w/ and w/o wildcards will confuse the sort and result in incorrect orders
|
||||||
|
iPathLen = len(iPathTrimmed)
|
||||||
|
jPathLen = len(jPathTrimmed)
|
||||||
|
|
||||||
|
// if both paths have the same length, sort lexically
|
||||||
|
// https://github.com/caddyserver/caddy/pull/7015#issuecomment-2871993588
|
||||||
|
if iPathLen == jPathLen {
|
||||||
|
return iPathTrimmed < jPathTrimmed
|
||||||
|
}
|
||||||
|
|
||||||
// sort most-specific (longest) path first
|
// sort most-specific (longest) path first
|
||||||
return iPathLen > jPathLen
|
return iPathLen > jPathLen
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
{
|
||||||
|
pki {
|
||||||
|
ca custom-ca {
|
||||||
|
name "Custom CA"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acme.example.com {
|
||||||
|
acme_server {
|
||||||
|
ca custom-ca
|
||||||
|
allow {
|
||||||
|
domains host-1.internal.example.com host-2.internal.example.com
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----------
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"servers": {
|
||||||
|
"srv0": {
|
||||||
|
"listen": [
|
||||||
|
":443"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": [
|
||||||
|
"acme.example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "subroute",
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"ca": "custom-ca",
|
||||||
|
"handler": "acme_server",
|
||||||
|
"policy": {
|
||||||
|
"allow": {
|
||||||
|
"domains": [
|
||||||
|
"host-1.internal.example.com",
|
||||||
|
"host-2.internal.example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pki": {
|
||||||
|
"certificate_authorities": {
|
||||||
|
"custom-ca": {
|
||||||
|
"name": "Custom CA"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
{
|
||||||
|
pki {
|
||||||
|
ca custom-ca {
|
||||||
|
name "Custom CA"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acme.example.com {
|
||||||
|
acme_server {
|
||||||
|
ca custom-ca
|
||||||
|
allow {
|
||||||
|
domains host-1.internal.example.com host-2.internal.example.com
|
||||||
|
}
|
||||||
|
deny {
|
||||||
|
domains dc.internal.example.com
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----------
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"servers": {
|
||||||
|
"srv0": {
|
||||||
|
"listen": [
|
||||||
|
":443"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": [
|
||||||
|
"acme.example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "subroute",
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"ca": "custom-ca",
|
||||||
|
"handler": "acme_server",
|
||||||
|
"policy": {
|
||||||
|
"allow": {
|
||||||
|
"domains": [
|
||||||
|
"host-1.internal.example.com",
|
||||||
|
"host-2.internal.example.com"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"deny": {
|
||||||
|
"domains": [
|
||||||
|
"dc.internal.example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pki": {
|
||||||
|
"certificate_authorities": {
|
||||||
|
"custom-ca": {
|
||||||
|
"name": "Custom CA"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
{
|
||||||
|
pki {
|
||||||
|
ca custom-ca {
|
||||||
|
name "Custom CA"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acme.example.com {
|
||||||
|
acme_server {
|
||||||
|
ca custom-ca
|
||||||
|
deny {
|
||||||
|
domains dc.internal.example.com
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----------
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"servers": {
|
||||||
|
"srv0": {
|
||||||
|
"listen": [
|
||||||
|
":443"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": [
|
||||||
|
"acme.example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "subroute",
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"ca": "custom-ca",
|
||||||
|
"handler": "acme_server",
|
||||||
|
"policy": {
|
||||||
|
"deny": {
|
||||||
|
"domains": [
|
||||||
|
"dc.internal.example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pki": {
|
||||||
|
"certificate_authorities": {
|
||||||
|
"custom-ca": {
|
||||||
|
"name": "Custom CA"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
|
"maps"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
@ -703,9 +704,7 @@ func AdminAPIRequest(adminAddr, method, uri string, headers http.Header, body io
|
||||||
if body != nil {
|
if body != nil {
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
}
|
}
|
||||||
for k, v := range headers {
|
maps.Copy(req.Header, headers)
|
||||||
req.Header[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// make an HTTP client that dials our network type, since admin
|
// make an HTTP client that dials our network type, since admin
|
||||||
// endpoints aren't always TCP, which is what the default transport
|
// endpoints aren't always TCP, which is what the default transport
|
||||||
|
|
|
@ -162,7 +162,9 @@ func (logging *Logging) setupNewDefault(ctx Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("setting up default log: %v", err)
|
return fmt.Errorf("setting up default log: %v", err)
|
||||||
}
|
}
|
||||||
newDefault.logger = zap.New(newDefault.CustomLog.core, options...)
|
|
||||||
|
filteringCore := &filteringCore{newDefault.CustomLog.core, newDefault.CustomLog}
|
||||||
|
newDefault.logger = zap.New(filteringCore, options...)
|
||||||
|
|
||||||
// redirect the default caddy logs
|
// redirect the default caddy logs
|
||||||
defaultLoggerMu.Lock()
|
defaultLoggerMu.Lock()
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package caddy
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestCustomLog_loggerAllowed(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
BaseLog BaseLog
|
||||||
|
Include []string
|
||||||
|
Exclude []string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
name string
|
||||||
|
isModule bool
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "include",
|
||||||
|
fields: fields{
|
||||||
|
Include: []string{"foo"},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
name: "foo",
|
||||||
|
isModule: true,
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "exclude",
|
||||||
|
fields: fields{
|
||||||
|
Exclude: []string{"foo"},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
name: "foo",
|
||||||
|
isModule: true,
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "include and exclude",
|
||||||
|
fields: fields{
|
||||||
|
Include: []string{"foo"},
|
||||||
|
Exclude: []string{"foo"},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
name: "foo",
|
||||||
|
isModule: true,
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "include and exclude (longer namespace)",
|
||||||
|
fields: fields{
|
||||||
|
Include: []string{"foo.bar"},
|
||||||
|
Exclude: []string{"foo"},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
name: "foo.bar",
|
||||||
|
isModule: true,
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "excluded module is not printed",
|
||||||
|
fields: fields{
|
||||||
|
Include: []string{"admin.api.load"},
|
||||||
|
Exclude: []string{"admin.api"},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
name: "admin.api",
|
||||||
|
isModule: false,
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
cl := &CustomLog{
|
||||||
|
BaseLog: tt.fields.BaseLog,
|
||||||
|
Include: tt.fields.Include,
|
||||||
|
Exclude: tt.fields.Exclude,
|
||||||
|
}
|
||||||
|
if got := cl.loggerAllowed(tt.args.name, tt.args.isModule); got != tt.want {
|
||||||
|
t.Errorf("CustomLog.loggerAllowed() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -300,8 +300,10 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
|
||||||
info, err := fs.Stat(fileSystem, filename)
|
info, err := fs.Stat(fileSystem, filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fsrv.mapDirOpenError(fileSystem, err, filename)
|
err = fsrv.mapDirOpenError(fileSystem, err, filename)
|
||||||
if errors.Is(err, fs.ErrNotExist) || errors.Is(err, fs.ErrInvalid) {
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
return fsrv.notFound(w, r, next)
|
return fsrv.notFound(w, r, next)
|
||||||
|
} else if errors.Is(err, fs.ErrInvalid) {
|
||||||
|
return caddyhttp.Error(http.StatusBadRequest, err)
|
||||||
} else if errors.Is(err, fs.ErrPermission) {
|
} else if errors.Is(err, fs.ErrPermission) {
|
||||||
return caddyhttp.Error(http.StatusForbidden, err)
|
return caddyhttp.Error(http.StatusForbidden, err)
|
||||||
}
|
}
|
||||||
|
@ -611,6 +613,11 @@ func (fsrv *FileServer) mapDirOpenError(fileSystem fs.FS, originalErr error, nam
|
||||||
return originalErr
|
return originalErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pathErr *fs.PathError
|
||||||
|
if errors.As(originalErr, &pathErr) {
|
||||||
|
return fs.ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
parts := strings.Split(name, separator)
|
parts := strings.Split(name, separator)
|
||||||
for i := range parts {
|
for i := range parts {
|
||||||
if parts[i] == "" {
|
if parts[i] == "" {
|
||||||
|
|
|
@ -118,6 +118,11 @@ func (irh interceptedResponseHandler) WriteHeader(statusCode int) {
|
||||||
irh.ResponseRecorder.WriteHeader(statusCode)
|
irh.ResponseRecorder.WriteHeader(statusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EXPERIMENTAL: Subject to change or removal.
|
||||||
|
func (irh interceptedResponseHandler) Unwrap() http.ResponseWriter {
|
||||||
|
return irh.ResponseRecorder
|
||||||
|
}
|
||||||
|
|
||||||
// EXPERIMENTAL: Subject to change or removal.
|
// EXPERIMENTAL: Subject to change or removal.
|
||||||
func (ir Intercept) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
|
func (ir Intercept) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
|
||||||
buf := bufPool.Get().(*bytes.Buffer)
|
buf := bufPool.Get().(*bytes.Buffer)
|
||||||
|
|
|
@ -17,6 +17,7 @@ package fastcgi
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -314,7 +315,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
||||||
|
|
||||||
// if the index is turned off, we skip the redirect and try_files
|
// if the index is turned off, we skip the redirect and try_files
|
||||||
if indexFile != "off" {
|
if indexFile != "off" {
|
||||||
dirRedir := false
|
var dirRedir bool
|
||||||
dirIndex := "{http.request.uri.path}/" + indexFile
|
dirIndex := "{http.request.uri.path}/" + indexFile
|
||||||
tryPolicy := "first_exist_fallback"
|
tryPolicy := "first_exist_fallback"
|
||||||
|
|
||||||
|
@ -328,13 +329,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
||||||
tryPolicy = ""
|
tryPolicy = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tf := range tryFiles {
|
dirRedir = slices.Contains(tryFiles, dirIndex)
|
||||||
if tf == dirIndex {
|
|
||||||
dirRedir = true
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if dirRedir {
|
if dirRedir {
|
||||||
|
|
|
@ -528,13 +528,7 @@ func (h *HTTPTransport) shouldUseTLS(req *http.Request) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
port := req.URL.Port()
|
port := req.URL.Port()
|
||||||
for i := range h.TLS.ExceptPorts {
|
return !slices.Contains(h.TLS.ExceptPorts, port)
|
||||||
if h.TLS.ExceptPorts[i] == port {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TLSEnabled returns true if TLS is enabled.
|
// TLSEnabled returns true if TLS is enabled.
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"os"
|
"os"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
@ -323,13 +324,7 @@ func cmdRespond(fl caddycmd.Flags) (int, error) {
|
||||||
|
|
||||||
// figure out if status code was explicitly specified; this lets
|
// figure out if status code was explicitly specified; this lets
|
||||||
// us set a non-zero value as the default but is a little hacky
|
// us set a non-zero value as the default but is a little hacky
|
||||||
var statusCodeFlagSpecified bool
|
statusCodeFlagSpecified := slices.Contains(os.Args, "--status")
|
||||||
for _, fl := range os.Args {
|
|
||||||
if fl == "--status" {
|
|
||||||
statusCodeFlagSpecified = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to determine what kind of parameter the unnamed argument is
|
// try to determine what kind of parameter the unnamed argument is
|
||||||
if arg != "" {
|
if arg != "" {
|
||||||
|
|
|
@ -91,19 +91,17 @@ func parseACMEServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
||||||
acmeServer.Policy.AllowWildcardNames = true
|
acmeServer.Policy.AllowWildcardNames = true
|
||||||
case "allow":
|
case "allow":
|
||||||
r := &RuleSet{}
|
r := &RuleSet{}
|
||||||
for h.Next() {
|
for nesting := h.Nesting(); h.NextBlock(nesting); {
|
||||||
for h.NextBlock(h.Nesting() - 1) {
|
if h.CountRemainingArgs() == 0 {
|
||||||
if h.CountRemainingArgs() == 0 {
|
return nil, h.ArgErr() // TODO:
|
||||||
return nil, h.ArgErr() // TODO:
|
}
|
||||||
}
|
switch h.Val() {
|
||||||
switch h.Val() {
|
case "domains":
|
||||||
case "domains":
|
r.Domains = append(r.Domains, h.RemainingArgs()...)
|
||||||
r.Domains = append(r.Domains, h.RemainingArgs()...)
|
case "ip_ranges":
|
||||||
case "ip_ranges":
|
r.IPRanges = append(r.IPRanges, h.RemainingArgs()...)
|
||||||
r.IPRanges = append(r.IPRanges, h.RemainingArgs()...)
|
default:
|
||||||
default:
|
return nil, h.Errf("unrecognized 'allow' subdirective: %s", h.Val())
|
||||||
return nil, h.Errf("unrecognized 'allow' subdirective: %s", h.Val())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if acmeServer.Policy == nil {
|
if acmeServer.Policy == nil {
|
||||||
|
@ -112,19 +110,17 @@ func parseACMEServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
||||||
acmeServer.Policy.Allow = r
|
acmeServer.Policy.Allow = r
|
||||||
case "deny":
|
case "deny":
|
||||||
r := &RuleSet{}
|
r := &RuleSet{}
|
||||||
for h.Next() {
|
for nesting := h.Nesting(); h.NextBlock(nesting); {
|
||||||
for h.NextBlock(h.Nesting() - 1) {
|
if h.CountRemainingArgs() == 0 {
|
||||||
if h.CountRemainingArgs() == 0 {
|
return nil, h.ArgErr() // TODO:
|
||||||
return nil, h.ArgErr() // TODO:
|
}
|
||||||
}
|
switch h.Val() {
|
||||||
switch h.Val() {
|
case "domains":
|
||||||
case "domains":
|
r.Domains = append(r.Domains, h.RemainingArgs()...)
|
||||||
r.Domains = append(r.Domains, h.RemainingArgs()...)
|
case "ip_ranges":
|
||||||
case "ip_ranges":
|
r.IPRanges = append(r.IPRanges, h.RemainingArgs()...)
|
||||||
r.IPRanges = append(r.IPRanges, h.RemainingArgs()...)
|
default:
|
||||||
default:
|
return nil, h.Errf("unrecognized 'deny' subdirective: %s", h.Val())
|
||||||
return nil, h.Errf("unrecognized 'deny' subdirective: %s", h.Val())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if acmeServer.Policy == nil {
|
if acmeServer.Policy == nil {
|
||||||
|
|
|
@ -87,13 +87,7 @@ nextChoice:
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(p.AnyTag) > 0 {
|
if len(p.AnyTag) > 0 {
|
||||||
var found bool
|
found := slices.ContainsFunc(p.AnyTag, cert.HasTag)
|
||||||
for _, tag := range p.AnyTag {
|
|
||||||
if cert.HasTag(tag) {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
if !found {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mholt/acmez/v3"
|
"github.com/mholt/acmez/v3"
|
||||||
|
@ -369,13 +370,7 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure ALPN includes the ACME TLS-ALPN protocol
|
// ensure ALPN includes the ACME TLS-ALPN protocol
|
||||||
var alpnFound bool
|
alpnFound := slices.Contains(p.ALPN, acmez.ACMETLS1Protocol)
|
||||||
for _, a := range p.ALPN {
|
|
||||||
if a == acmez.ACMETLS1Protocol {
|
|
||||||
alpnFound = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !alpnFound && (cfg.NextProtos == nil || len(cfg.NextProtos) > 0) {
|
if !alpnFound && (cfg.NextProtos == nil || len(cfg.NextProtos) > 0) {
|
||||||
cfg.NextProtos = append(cfg.NextProtos, acmez.ACMETLS1Protocol)
|
cfg.NextProtos = append(cfg.NextProtos, acmez.ACMETLS1Protocol)
|
||||||
}
|
}
|
||||||
|
@ -1004,10 +999,8 @@ func (l LeafCertClientAuth) VerifyClientCertificate(rawCerts [][]byte, _ [][]*x5
|
||||||
return fmt.Errorf("can't parse the given certificate: %s", err.Error())
|
return fmt.Errorf("can't parse the given certificate: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, trustedLeafCert := range l.trustedLeafCerts {
|
if slices.ContainsFunc(l.trustedLeafCerts, remoteLeafCert.Equal) {
|
||||||
if remoteLeafCert.Equal(trustedLeafCert) {
|
return nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("client leaf certificate failed validation")
|
return fmt.Errorf("client leaf certificate failed validation")
|
||||||
|
|
Loading…
Reference in New Issue