summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--caddyconfig/httpcaddyfile/addresses.go8
-rw-r--r--caddyconfig/httpcaddyfile/httptype.go55
-rw-r--r--caddyconfig/httpcaddyfile/options.go5
-rw-r--r--caddyconfig/httpcaddyfile/serveroptions.go235
-rw-r--r--caddytest/integration/caddyfile_adapt/global_server_options_multi.txt83
-rw-r--r--caddytest/integration/caddyfile_adapt/global_server_options_single.txt62
-rw-r--r--caddytest/integration/caddyfile_adapt/handle_path.txt102
-rw-r--r--caddytest/integration/caddyfile_adapt/handle_path_sorting.txt208
-rw-r--r--caddytest/integration/caddyfile_adapt/import_args_file.txt96
-rw-r--r--caddytest/integration/caddyfile_adapt/import_args_snippet.txt164
-rw-r--r--caddytest/integration/caddyfile_adapt/log_filters.txt136
-rw-r--r--caddytest/integration/caddyfile_adapt/php_fastcgi_expanded_form.txt262
-rw-r--r--caddytest/integration/caddyfile_adapt/php_fastcgi_matcher.txt222
-rw-r--r--caddytest/integration/caddyfile_adapt/sort_directives_with_any_matcher_first.txt100
-rw-r--r--modules/caddyhttp/caddyhttp.go4
15 files changed, 1084 insertions, 658 deletions
diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go
index 51411a9..7105320 100644
--- a/caddyconfig/httpcaddyfile/addresses.go
+++ b/caddyconfig/httpcaddyfile/addresses.go
@@ -18,6 +18,7 @@ import (
"fmt"
"net"
"reflect"
+ "sort"
"strconv"
"strings"
"unicode"
@@ -163,6 +164,13 @@ func (st *ServerType) consolidateAddrMappings(addrToServerBlocks map[string][]se
sbaddrs = append(sbaddrs, a)
}
+
+ // sort them by their first address (we know there will always be at least one)
+ // to avoid problems with non-deterministic ordering (makes tests flaky)
+ sort.Slice(sbaddrs, func(i, j int) bool {
+ return sbaddrs[i].addresses[0] < sbaddrs[j].addresses[0]
+ })
+
return sbaddrs
}
diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go
index 35eab90..e4e40b2 100644
--- a/caddyconfig/httpcaddyfile/httptype.go
+++ b/caddyconfig/httpcaddyfile/httptype.go
@@ -218,13 +218,6 @@ func (st ServerType) Setup(inputServerBlocks []caddyfile.ServerBlock,
return nil, warnings, err
}
- // if experimental HTTP/3 is enabled, enable it on each server
- if enableH3, ok := options["experimental_http3"].(bool); ok && enableH3 {
- for _, srv := range httpApp.Servers {
- srv.ExperimentalHTTP3 = true
- }
- }
-
// extract any custom logs, and enforce configured levels
var customLogs []namedCustomLog
var hasDefaultLog bool
@@ -311,23 +304,54 @@ func (ServerType) evaluateGlobalOptionsBlock(serverBlocks []serverBlock, options
}
for _, segment := range serverBlocks[0].block.Segments {
- dir := segment.Directive()
+ opt := segment.Directive()
var val interface{}
var err error
disp := caddyfile.NewDispenser(segment)
- dirFunc, ok := registeredGlobalOptions[dir]
+ optFunc, ok := registeredGlobalOptions[opt]
if !ok {
tkn := segment[0]
- return nil, fmt.Errorf("%s:%d: unrecognized global option: %s", tkn.File, tkn.Line, dir)
+ return nil, fmt.Errorf("%s:%d: unrecognized global option: %s", tkn.File, tkn.Line, opt)
}
- val, err = dirFunc(disp)
+ val, err = optFunc(disp)
if err != nil {
- return nil, fmt.Errorf("parsing caddyfile tokens for '%s': %v", dir, err)
+ return nil, fmt.Errorf("parsing caddyfile tokens for '%s': %v", opt, err)
+ }
+
+ // As a special case, fold multiple "servers" options together
+ // in an array instead of overwriting a possible existing value
+ if opt == "servers" {
+ existingOpts, ok := options[opt].([]serverOptions)
+ if !ok {
+ existingOpts = []serverOptions{}
+ }
+ serverOpts, ok := val.(serverOptions)
+ if !ok {
+ return nil, fmt.Errorf("unexpected type from 'servers' global options")
+ }
+ options[opt] = append(existingOpts, serverOpts)
+ continue
}
- options[dir] = val
+ options[opt] = val
+ }
+
+ // If we got "servers" options, we'll sort them by their listener address
+ if serverOpts, ok := options["servers"].([]serverOptions); ok {
+ sort.Slice(serverOpts, func(i, j int) bool {
+ return len(serverOpts[i].ListenerAddress) > len(serverOpts[j].ListenerAddress)
+ })
+
+ // Reject the config if there are duplicate listener address
+ seen := make(map[string]bool)
+ for _, entry := range serverOpts {
+ if _, alreadySeen := seen[entry.ListenerAddress]; alreadySeen {
+ return nil, fmt.Errorf("cannot have 'servers' global options with duplicate listener addresses: %s", entry.ListenerAddress)
+ }
+ seen[entry.ListenerAddress] = true
+ }
}
return serverBlocks[1:], nil
@@ -602,6 +626,11 @@ func (st *ServerType) serversFromPairings(
servers[fmt.Sprintf("srv%d", i)] = srv
}
+ err := applyServerOptions(servers, options, warnings)
+ if err != nil {
+ return nil, err
+ }
+
return servers, nil
}
diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go
index 7d34805..5001974 100644
--- a/caddyconfig/httpcaddyfile/options.go
+++ b/caddyconfig/httpcaddyfile/options.go
@@ -43,6 +43,7 @@ func init() {
RegisterGlobalOption("local_certs", parseOptTrue)
RegisterGlobalOption("key_type", parseOptSingleString)
RegisterGlobalOption("auto_https", parseOptAutoHTTPS)
+ RegisterGlobalOption("servers", parseServerOptions)
}
func parseOptTrue(d *caddyfile.Dispenser) (interface{}, error) {
@@ -361,3 +362,7 @@ func parseOptAutoHTTPS(d *caddyfile.Dispenser) (interface{}, error) {
}
return val, nil
}
+
+func parseServerOptions(d *caddyfile.Dispenser) (interface{}, error) {
+ return unmarshalCaddyfileServerOptions(d)
+}
diff --git a/caddyconfig/httpcaddyfile/serveroptions.go b/caddyconfig/httpcaddyfile/serveroptions.go
new file mode 100644
index 0000000..38fa0f1
--- /dev/null
+++ b/caddyconfig/httpcaddyfile/serveroptions.go
@@ -0,0 +1,235 @@
+// 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 httpcaddyfile
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "github.com/caddyserver/caddy/v2"
+ "github.com/caddyserver/caddy/v2/caddyconfig"
+ "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
+ "github.com/caddyserver/caddy/v2/modules/caddyhttp"
+ "github.com/dustin/go-humanize"
+)
+
+// serverOptions collects server config overrides parsed from Caddyfile global options
+type serverOptions struct {
+ // If set, will only apply these options to servers that contain a
+ // listener address that matches exactly. If empty, will apply to all
+ // servers that were not already matched by another serverOptions.
+ ListenerAddress string
+
+ // These will all map 1:1 to the caddyhttp.Server struct
+ ListenerWrappersRaw []json.RawMessage
+ ReadTimeout caddy.Duration
+ ReadHeaderTimeout caddy.Duration
+ WriteTimeout caddy.Duration
+ IdleTimeout caddy.Duration
+ MaxHeaderBytes int
+ AllowH2C bool
+ ExperimentalHTTP3 bool
+ StrictSNIHost *bool
+}
+
+func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (interface{}, error) {
+ serverOpts := serverOptions{}
+ for d.Next() {
+ if d.NextArg() {
+ serverOpts.ListenerAddress = d.Val()
+ if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ }
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ switch d.Val() {
+ case "listener_wrappers":
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ mod, err := caddy.GetModule("caddy.listeners." + d.Val())
+ if err != nil {
+ return nil, fmt.Errorf("finding listener module '%s': %v", d.Val(), err)
+ }
+ unm, ok := mod.New().(caddyfile.Unmarshaler)
+ if !ok {
+ return nil, fmt.Errorf("listener module '%s' is not a Caddyfile unmarshaler", mod)
+ }
+ err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
+ if err != nil {
+ return nil, err
+ }
+ listenerWrapper, ok := unm.(caddy.ListenerWrapper)
+ if !ok {
+ return nil, fmt.Errorf("module %s is not a listener wrapper", mod)
+ }
+ jsonListenerWrapper := caddyconfig.JSONModuleObject(
+ listenerWrapper,
+ "wrapper",
+ listenerWrapper.(caddy.Module).CaddyModule().ID.Name(),
+ nil,
+ )
+ serverOpts.ListenerWrappersRaw = append(serverOpts.ListenerWrappersRaw, jsonListenerWrapper)
+ }
+
+ case "timeouts":
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ switch d.Val() {
+ case "read_body":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ dur, err := caddy.ParseDuration(d.Val())
+ if err != nil {
+ return nil, d.Errf("parsing read_body timeout duration: %v", err)
+ }
+ serverOpts.ReadTimeout = caddy.Duration(dur)
+
+ case "read_header":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ dur, err := caddy.ParseDuration(d.Val())
+ if err != nil {
+ return nil, d.Errf("parsing read_header timeout duration: %v", err)
+ }
+ serverOpts.ReadHeaderTimeout = caddy.Duration(dur)
+
+ case "write":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ dur, err := caddy.ParseDuration(d.Val())
+ if err != nil {
+ return nil, d.Errf("parsing write timeout duration: %v", err)
+ }
+ serverOpts.WriteTimeout = caddy.Duration(dur)
+
+ case "idle":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ dur, err := caddy.ParseDuration(d.Val())
+ if err != nil {
+ return nil, d.Errf("parsing idle timeout duration: %v", err)
+ }
+ serverOpts.IdleTimeout = caddy.Duration(dur)
+
+ default:
+ return nil, d.Errf("unrecognized timeouts option '%s'", d.Val())
+ }
+ }
+
+ case "max_header_size":
+ var sizeStr string
+ if !d.AllArgs(&sizeStr) {
+ return nil, d.ArgErr()
+ }
+ size, err := humanize.ParseBytes(sizeStr)
+ if err != nil {
+ return nil, d.Errf("parsing max_header_size: %v", err)
+ }
+ serverOpts.MaxHeaderBytes = int(size)
+
+ case "protocol":
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ switch d.Val() {
+ case "allow_h2c":
+ if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ serverOpts.AllowH2C = true
+
+ case "experimental_http3":
+ if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ serverOpts.ExperimentalHTTP3 = true
+
+ case "strict_sni_host":
+ if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ trueBool := true
+ serverOpts.StrictSNIHost = &trueBool
+
+ default:
+ return nil, d.Errf("unrecognized protocol option '%s'", d.Val())
+ }
+ }
+
+ default:
+ return nil, d.Errf("unrecognized servers option '%s'", d.Val())
+ }
+ }
+ }
+ return serverOpts, nil
+}
+
+// applyServerOptions sets the server options on the appropriate servers
+func applyServerOptions(
+ servers map[string]*caddyhttp.Server,
+ options map[string]interface{},
+ warnings *[]caddyconfig.Warning,
+) error {
+ // If experimental HTTP/3 is enabled, enable it on each server.
+ // We already know there won't be a conflict with serverOptions because
+ // we validated earlier that "experimental_http3" cannot be set at the same
+ // time as "servers"
+ if enableH3, ok := options["experimental_http3"].(bool); ok && enableH3 {
+ *warnings = append(*warnings, caddyconfig.Warning{Message: "the 'experimental_http3' global option is deprecated, please use the 'servers > protocol > experimental_http3' option instead"})
+ for _, srv := range servers {
+ srv.ExperimentalHTTP3 = true
+ }
+ }
+
+ serverOpts, ok := options["servers"].([]serverOptions)
+ if !ok {
+ return nil
+ }
+
+ for _, 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
+ }()
+
+ // if none apply, then move to the next server
+ if opts == nil {
+ continue
+ }
+
+ // set all the options
+ server.ListenerWrappersRaw = opts.ListenerWrappersRaw
+ server.ReadTimeout = opts.ReadTimeout
+ server.ReadHeaderTimeout = opts.ReadHeaderTimeout
+ server.WriteTimeout = opts.WriteTimeout
+ server.IdleTimeout = opts.IdleTimeout
+ server.MaxHeaderBytes = opts.MaxHeaderBytes
+ server.AllowH2C = opts.AllowH2C
+ server.ExperimentalHTTP3 = opts.ExperimentalHTTP3
+ server.StrictSNIHost = opts.StrictSNIHost
+ }
+
+ return nil
+}
diff --git a/caddytest/integration/caddyfile_adapt/global_server_options_multi.txt b/caddytest/integration/caddyfile_adapt/global_server_options_multi.txt
new file mode 100644
index 0000000..653eee5
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/global_server_options_multi.txt
@@ -0,0 +1,83 @@
+{
+ servers {
+ timeouts {
+ idle 90s
+ }
+ }
+ servers :80 {
+ timeouts {
+ idle 60s
+ }
+ }
+ servers :443 {
+ timeouts {
+ idle 30s
+ }
+ }
+}
+
+foo.com {
+}
+
+http://bar.com {
+}
+
+:8080 {
+}
+
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "idle_timeout": 30000000000,
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "foo.com"
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ },
+ "srv1": {
+ "listen": [
+ ":80"
+ ],
+ "idle_timeout": 60000000000,
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "bar.com"
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ],
+ "automatic_https": {
+ "skip": [
+ "bar.com"
+ ]
+ }
+ },
+ "srv2": {
+ "listen": [
+ ":8080"
+ ],
+ "idle_timeout": 90000000000
+ }
+ }
+ }
+ }
+}
diff --git a/caddytest/integration/caddyfile_adapt/global_server_options_single.txt b/caddytest/integration/caddyfile_adapt/global_server_options_single.txt
new file mode 100644
index 0000000..5a5c64c
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/global_server_options_single.txt
@@ -0,0 +1,62 @@
+{
+ servers {
+ listener_wrappers {
+ tls
+ }
+ timeouts {
+ read_body 30s
+ read_header 30s
+ write 30s
+ idle 30s
+ }
+ max_header_size 100MB
+ protocol {
+ allow_h2c
+ experimental_http3
+ strict_sni_host
+ }
+ }
+}
+
+foo.com {
+}
+
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "listener_wrappers": [
+ {
+ "wrapper": "tls"
+ }
+ ],
+ "read_timeout": 30000000000,
+ "read_header_timeout": 30000000000,
+ "write_timeout": 30000000000,
+ "idle_timeout": 30000000000,
+ "max_header_bytes": 100000000,
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "foo.com"
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ],
+ "strict_sni_host": true,
+ "experimental_http3": true,
+ "allow_h2c": true
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/handle_path.txt b/caddytest/integration/caddyfile_adapt/handle_path.txt
index 7f40fcf..f881743 100644
--- a/caddytest/integration/caddyfile_adapt/handle_path.txt
+++ b/caddytest/integration/caddyfile_adapt/handle_path.txt
@@ -1,52 +1,52 @@
-:80
-handle_path /api/v1/* {
- respond "API v1"
-}
-----------
-{
- "apps": {
- "http": {
- "servers": {
- "srv0": {
- "listen": [
- ":80"
- ],
- "routes": [
- {
- "match": [
- {
- "path": [
- "/api/v1/*"
- ]
- }
- ],
- "handle": [
- {
- "handler": "subroute",
- "routes": [
- {
- "handle": [
- {
- "handler": "rewrite",
- "strip_path_prefix": "/api/v1"
- }
- ]
- },
- {
- "handle": [
- {
- "body": "API v1",
- "handler": "static_response"
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- }
- }
- }
- }
+:80
+handle_path /api/v1/* {
+ respond "API v1"
+}
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":80"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "path": [
+ "/api/v1/*"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "rewrite",
+ "strip_path_prefix": "/api/v1"
+ }
+ ]
+ },
+ {
+ "handle": [
+ {
+ "body": "API v1",
+ "handler": "static_response"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/handle_path_sorting.txt b/caddytest/integration/caddyfile_adapt/handle_path_sorting.txt
index 3258dc9..0a89f2a 100644
--- a/caddytest/integration/caddyfile_adapt/handle_path_sorting.txt
+++ b/caddytest/integration/caddyfile_adapt/handle_path_sorting.txt
@@ -1,105 +1,105 @@
-:80 {
- handle /api/* {
- respond "api"
- }
-
- handle_path /static/* {
- respond "static"
- }
-
- handle {
- respond "handle"
- }
-}
-----------
-{
- "apps": {
- "http": {
- "servers": {
- "srv0": {
- "listen": [
- ":80"
- ],
- "routes": [
- {
- "group": "group3",
- "match": [
- {
- "path": [
- "/static/*"
- ]
- }
- ],
- "handle": [
- {
- "handler": "subroute",
- "routes": [
- {
- "handle": [
- {
- "handler": "rewrite",
- "strip_path_prefix": "/static"
- }
- ]
- },
- {
- "handle": [
- {
- "body": "static",
- "handler": "static_response"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "group": "group3",
- "match": [
- {
- "path": [
- "/api/*"
- ]
- }
- ],
- "handle": [
- {
- "handler": "subroute",
- "routes": [
- {
- "handle": [
- {
- "body": "api",
- "handler": "static_response"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "group": "group3",
- "handle": [
- {
- "handler": "subroute",
- "routes": [
- {
- "handle": [
- {
- "body": "handle",
- "handler": "static_response"
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- }
- }
- }
- }
+:80 {
+ handle /api/* {
+ respond "api"
+ }
+
+ handle_path /static/* {
+ respond "static"
+ }
+
+ handle {
+ respond "handle"
+ }
+}
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":80"
+ ],
+ "routes": [
+ {
+ "group": "group3",
+ "match": [
+ {
+ "path": [
+ "/static/*"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "rewrite",
+ "strip_path_prefix": "/static"
+ }
+ ]
+ },
+ {
+ "handle": [
+ {
+ "body": "static",
+ "handler": "static_response"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "group": "group3",
+ "match": [
+ {
+ "path": [
+ "/api/*"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "body": "api",
+ "handler": "static_response"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "group": "group3",
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "body": "handle",
+ "handler": "static_response"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/import_args_file.txt b/caddytest/integration/caddyfile_adapt/import_args_file.txt
index 6947f68..1eb78f1 100644
--- a/caddytest/integration/caddyfile_adapt/import_args_file.txt
+++ b/caddytest/integration/caddyfile_adapt/import_args_file.txt
@@ -1,49 +1,49 @@
-example.com
-
-import testdata/import_respond.txt Groot Rocket
-import testdata/import_respond.txt you "the confused man"
-----------
-{
- "apps": {
- "http": {
- "servers": {
- "srv0": {
- "listen": [
- ":443"
- ],
- "routes": [
- {
- "match": [
- {
- "host": [
- "example.com"
- ]
- }
- ],
- "handle": [
- {
- "handler": "subroute",
- "routes": [
- {
- "handle": [
- {
- "body": "'I am Groot', hears Rocket",
- "handler": "static_response"
- },
- {
- "body": "'I am you', hears the confused man",
- "handler": "static_response"
- }
- ]
- }
- ]
- }
- ],
- "terminal": true
- }
- ]
- }
- }
- }
- }
+example.com
+
+import testdata/import_respond.txt Groot Rocket
+import testdata/import_respond.txt you "the confused man"
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "example.com"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "body": "'I am Groot', hears Rocket",
+ "handler": "static_response"
+ },
+ {
+ "body": "'I am you', hears the confused man",
+ "handler": "static_response"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ]
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/import_args_snippet.txt b/caddytest/integration/caddyfile_adapt/import_args_snippet.txt
index 8d2ff34..9fce9ab 100644
--- a/caddytest/integration/caddyfile_adapt/import_args_snippet.txt
+++ b/caddytest/integration/caddyfile_adapt/import_args_snippet.txt
@@ -1,83 +1,83 @@
-(logging) {
- log {
- output file /var/log/caddy/{args.0}.access.log
- }
-}
-
-a.example.com {
- import logging a.example.com
-}
-
-b.example.com {
- import logging b.example.com
-}
-----------
-{
- "logging": {
- "logs": {
- "default": {
- "exclude": [
- "http.log.access.log0",
- "http.log.access.log1"
- ]
- },
- "log0": {
- "writer": {
- "filename": "/var/log/caddy/a.example.com.access.log",
- "output": "file"
- },
- "include": [
- "http.log.access.log0"
- ]
- },
- "log1": {
- "writer": {
- "filename": "/var/log/caddy/b.example.com.access.log",
- "output": "file"
- },
- "include": [
- "http.log.access.log1"
- ]
- }
- }
- },
- "apps": {
- "http": {
- "servers": {
- "srv0": {
- "listen": [
- ":443"
- ],
- "routes": [
- {
- "match": [
- {
- "host": [
- "a.example.com"
- ]
- }
- ],
- "terminal": true
- },
- {
- "match": [
- {
- "host": [
- "b.example.com"
- ]
- }
- ],
- "terminal": true
- }
- ],
- "logs": {
- "logger_names": {
- "a.example.com": "log0",
- "b.example.com": "log1"
- }
- }
- }
- }
- }
- }
+(logging) {
+ log {
+ output file /var/log/caddy/{args.0}.access.log
+ }
+}
+
+a.example.com {
+ import logging a.example.com
+}
+
+b.example.com {
+ import logging b.example.com
+}
+----------
+{
+ "logging": {
+ "logs": {
+ "default": {
+ "exclude": [
+ "http.log.access.log0",
+ "http.log.access.log1"
+ ]
+ },
+ "log0": {
+ "writer": {
+ "filename": "/var/log/caddy/a.example.com.access.log",
+ "output": "file"
+ },
+ "include": [
+ "http.log.access.log0"
+ ]
+ },
+ "log1": {
+ "writer": {
+ "filename": "/var/log/caddy/b.example.com.access.log",
+ "output": "file"
+ },
+ "include": [
+ "http.log.access.log1"
+ ]
+ }
+ }
+ },
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":443"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "a.example.com"
+ ]
+ }
+ ],
+ "terminal": true
+ },
+ {
+ "match": [
+ {
+ "host": [
+ "b.example.com"
+ ]
+ }
+ ],
+ "terminal": true
+ }
+ ],
+ "logs": {
+ "logger_names": {
+ "a.example.com": "log0",
+ "b.example.com": "log1"
+ }
+ }
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/log_filters.txt b/caddytest/integration/caddyfile_adapt/log_filters.txt
index 549f4e6..ab11807 100644
--- a/caddytest/integration/caddyfile_adapt/log_filters.txt
+++ b/caddytest/integration/caddyfile_adapt/log_filters.txt
@@ -1,69 +1,69 @@
-:80
-
-log {
- output stdout
- format filter {
- wrap console
- fields {
- request>headers>Authorization delete
- request>headers>Server delete
- request>remote_addr ip_mask {
- ipv4 24
- ipv6 32
- }
- }
- }
-}
-----------
-{
- "logging": {
- "logs": {
- "default": {
- "exclude": [
- "http.log.access.log0"
- ]
- },
- "log0": {
- "writer": {
- "output": "stdout"
- },
- "encoder": {
- "fields": {
- "request\u003eheaders\u003eAuthorization": {
- "filter": "delete"
- },
- "request\u003eheaders\u003eServer": {
- "filter": "delete"
- },
- "request\u003eremote_addr": {
- "filter": "ip_mask",
- "ipv4_cidr": 24,
- "ipv6_cidr": 32
- }
- },
- "format": "filter",
- "wrap": {
- "format": "console"
- }
- },
- "include": [
- "http.log.access.log0"
- ]
- }
- }
- },
- "apps": {
- "http": {
- "servers": {
- "srv0": {
- "listen": [
- ":80"
- ],
- "logs": {
- "default_logger_name": "log0"
- }
- }
- }
- }
- }
+:80
+
+log {
+ output stdout
+ format filter {
+ wrap console
+ fields {
+ request>headers>Authorization delete
+ request>headers>Server delete
+ request>remote_addr ip_mask {
+ ipv4 24
+ ipv6 32
+ }
+ }
+ }
+}
+----------
+{
+ "logging": {
+ "logs": {
+ "default": {
+ "exclude": [
+ "http.log.access.log0"
+ ]
+ },
+ "log0": {
+ "writer": {
+ "output": "stdout"
+ },
+ "encoder": {
+ "fields": {
+ "request\u003eheaders\u003eAuthorization": {
+ "filter": "delete"
+ },
+ "request\u003eheaders\u003eServer": {
+ "filter": "delete"
+ },
+ "request\u003eremote_addr": {
+ "filter": "ip_mask",
+ "ipv4_cidr": 24,
+ "ipv6_cidr": 32
+ }
+ },
+ "format": "filter",
+ "wrap": {
+ "format": "console"
+ }
+ },
+ "include": [
+ "http.log.access.log0"
+ ]
+ }
+ }
+ },
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":80"
+ ],
+ "logs": {
+ "default_logger_name": "log0"
+ }
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/php_fastcgi_expanded_form.txt b/caddytest/integration/caddyfile_adapt/php_fastcgi_expanded_form.txt
index d453128..bb7c7f7 100644
--- a/caddytest/integration/caddyfile_adapt/php_fastcgi_expanded_form.txt
+++ b/caddytest/integration/caddyfile_adapt/php_fastcgi_expanded_form.txt
@@ -1,132 +1,132 @@
-:8886
-
-route {
- # Add trailing slash for directory requests
- @canonicalPath {
- file {
- try_files {path}/index.php
- }
- not path */
- }
- redir @canonicalPath {path}/ 308
-
- # If the requested file does not exist, try index files
- @indexFiles {
- file {
- try_files {path} {path}/index.php index.php
- split_path .php
- }
- }
- rewrite @indexFiles {http.matchers.file.relative}
-
- # Proxy PHP files to the FastCGI responder
- @phpFiles {
- path *.php
- }
- reverse_proxy @phpFiles 127.0.0.1:9000 {
- transport fastcgi {
- split .php
- }
- }
-}
-----------
-{
- "apps": {
- "http": {
- "servers": {
- "srv0": {
- "listen": [
- ":8886"
- ],
- "routes": [
- {
- "handle": [
- {
- "handler": "subroute",
- "routes": [
- {
- "handle": [
- {
- "handler": "static_response",
- "headers": {
- "Location": [
- "{http.request.uri.path}/"
- ]
- },
- "status_code": 308
- }
- ],
- "match": [
- {
- "file": {
- "try_files": [
- "{http.request.uri.path}/index.php"
- ]
- },
- "not": [
- {
- "path": [
- "*/"
- ]
- }
- ]
- }
- ]
- },
- {
- "handle": [
- {
- "handler": "rewrite",
- "uri": "{http.matchers.file.relative}"
- }
- ],
- "match": [
- {
- "file": {
- "split_path": [
- ".php"
- ],
- "try_files": [
- "{http.request.uri.path}",
- "{http.request.uri.path}/index.php",
- "index.php"
- ]
- }
- }
- ]
- },
- {
- "handle": [
- {
- "handler": "reverse_proxy",
- "transport": {
- "protocol": "fastcgi",
- "split_path": [
- ".php"
- ]
- },
- "upstreams": [
- {
- "dial": "127.0.0.1:9000"
- }
- ]
- }
- ],
- "match": [
- {
- "path": [
- "*.php"
- ]
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- }
- }
- }
- }
+:8886
+
+route {
+ # Add trailing slash for directory requests
+ @canonicalPath {
+ file {
+ try_files {path}/index.php
+ }
+ not path */
+ }
+ redir @canonicalPath {path}/ 308
+
+ # If the requested file does not exist, try index files
+ @indexFiles {
+ file {
+ try_files {path} {path}/index.php index.php
+ split_path .php
+ }
+ }
+ rewrite @indexFiles {http.matchers.file.relative}
+
+ # Proxy PHP files to the FastCGI responder
+ @phpFiles {
+ path *.php
+ }
+ reverse_proxy @phpFiles 127.0.0.1:9000 {
+ transport fastcgi {
+ split .php
+ }
+ }
+}
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":8886"
+ ],
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "static_response",
+ "headers": {
+ "Location": [
+ "{http.request.uri.path}/"
+ ]
+ },
+ "status_code": 308
+ }
+ ],
+ "match": [
+ {
+ "file": {
+ "try_files": [
+ "{http.request.uri.path}/index.php"
+ ]
+ },
+ "not": [
+ {
+ "path": [
+ "*/"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "handle": [
+ {
+ "handler": "rewrite",
+ "uri": "{http.matchers.file.relative}"
+ }
+ ],
+ "match": [
+ {
+ "file": {
+ "split_path": [
+ ".php"
+ ],
+ "try_files": [
+ "{http.request.uri.path}",
+ "{http.request.uri.path}/index.php",
+ "index.php"
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "transport": {
+ "protocol": "fastcgi",
+ "split_path": [
+ ".php"
+ ]
+ },
+ "upstreams": [
+ {
+ "dial": "127.0.0.1:9000"
+ }
+ ]
+ }
+ ],
+ "match": [
+ {
+ "path": [
+ "*.php"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/php_fastcgi_matcher.txt b/caddytest/integration/caddyfile_adapt/php_fastcgi_matcher.txt
index 2f4e6fe..488c525 100644
--- a/caddytest/integration/caddyfile_adapt/php_fastcgi_matcher.txt
+++ b/caddytest/integration/caddyfile_adapt/php_fastcgi_matcher.txt
@@ -1,112 +1,112 @@
-:8884
-
-@api host example.com
-php_fastcgi @api localhost:9000
-----------
-{
- "apps": {
- "http": {
- "servers": {
- "srv0": {
- "listen": [
- ":8884"
- ],
- "routes": [
- {
- "match": [
- {
- "host": [
- "example.com"
- ]
- }
- ],
- "handle": [
- {
- "handler": "subroute",
- "routes": [
- {
- "handle": [
- {
- "handler": "static_response",
- "headers": {
- "Location": [
- "{http.request.uri.path}/"
- ]
- },
- "status_code": 308
- }
- ],
- "match": [
- {
- "file": {
- "try_files": [
- "{http.request.uri.path}/index.php"
- ]
- },
- "not": [
- {
- "path": [
- "*/"
- ]
- }
- ]
- }
- ]
- },
- {
- "handle": [
- {
- "handler": "rewrite",
- "uri": "{http.matchers.file.relative}"
- }
- ],
- "match": [
- {
- "file": {
- "split_path": [
- ".php"
- ],
- "try_files": [
- "{http.request.uri.path}",
- "{http.request.uri.path}/index.php",
- "index.php"
- ]
- }
- }
- ]
- },
- {
- "handle": [
- {
- "handler": "reverse_proxy",
- "transport": {
- "protocol": "fastcgi",
- "split_path": [
- ".php"
- ]
- },
- "upstreams": [
- {
- "dial": "localhost:9000"
- }
- ]
- }
- ],
- "match": [
- {
- "path": [
- "*.php"
- ]
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- }
- }
- }
- }
+:8884
+
+@api host example.com
+php_fastcgi @api localhost:9000
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":8884"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "host": [
+ "example.com"
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "subroute",
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "static_response",
+ "headers": {
+ "Location": [
+ "{http.request.uri.path}/"
+ ]
+ },
+ "status_code": 308
+ }
+ ],
+ "match": [
+ {
+ "file": {
+ "try_files": [
+ "{http.request.uri.path}/index.php"
+ ]
+ },
+ "not": [
+ {
+ "path": [
+ "*/"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "handle": [
+ {
+ "handler": "rewrite",
+ "uri": "{http.matchers.file.relative}"
+ }
+ ],
+ "match": [
+ {
+ "file": {
+ "split_path": [
+ ".php"
+ ],
+ "try_files": [
+ "{http.request.uri.path}",
+ "{http.request.uri.path}/index.php",
+ "index.php"
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "transport": {
+ "protocol": "fastcgi",
+ "split_path": [
+ ".php"
+ ]
+ },
+ "upstreams": [
+ {
+ "dial": "localhost:9000"
+ }
+ ]
+ }
+ ],
+ "match": [
+ {
+ "path": [
+ "*.php"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/caddytest/integration/caddyfile_adapt/sort_directives_with_any_matcher_first.txt b/caddytest/integration/caddyfile_adapt/sort_directives_with_any_matcher_first.txt
index 6203a89..3859a7e 100644
--- a/caddytest/integration/caddyfile_adapt/sort_directives_with_any_matcher_first.txt
+++ b/caddytest/integration/caddyfile_adapt/sort_directives_with_any_matcher_first.txt
@@ -1,51 +1,51 @@
-:80
-
-respond 200
-
-@untrusted not remote_ip 10.1.1.0/24
-respond @untrusted 401
-----------
-{
- "apps": {
- "http": {
- "servers": {
- "srv0": {
- "listen": [
- ":80"
- ],
- "routes": [
- {
- "match": [
- {
- "not": [
- {
- "remote_ip": {
- "ranges": [
- "10.1.1.0/24"
- ]
- }
- }
- ]
- }
- ],
- "handle": [
- {
- "handler": "static_response",
- "status_code": 401
- }
- ]
- },
- {
- "handle": [
- {
- "handler": "static_response",
- "status_code": 200
- }
- ]
- }
- ]
- }
- }
- }
- }
+:80
+
+respond 200
+
+@untrusted not remote_ip 10.1.1.0/24
+respond @untrusted 401
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":80"
+ ],
+ "routes": [
+ {
+ "match": [
+ {
+ "not": [
+ {
+ "remote_ip": {
+ "ranges": [
+ "10.1.1.0/24"
+ ]
+ }
+ }
+ ]
+ }
+ ],
+ "handle": [
+ {
+ "handler": "static_response",
+ "status_code": 401
+ }
+ ]
+ },
+ {
+ "handle": [
+ {
+ "handler": "static_response",
+ "status_code": 200
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/modules/caddyhttp/caddyhttp.go b/modules/caddyhttp/caddyhttp.go
index 485afe0..d93a5c8 100644
--- a/modules/caddyhttp/caddyhttp.go
+++ b/modules/caddyhttp/caddyhttp.go
@@ -23,6 +23,7 @@ import (
"strconv"
"github.com/caddyserver/caddy/v2"
+ "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
)
func init() {
@@ -231,6 +232,8 @@ func (tlsPlaceholderWrapper) CaddyModule() caddy.ModuleInfo {
func (tlsPlaceholderWrapper) WrapListener(ln net.Listener) net.Listener { return ln }
+func (tlsPlaceholderWrapper) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { return nil }
+
const (
// DefaultHTTPPort is the default port for HTTP.
DefaultHTTPPort = 80
@@ -241,3 +244,4 @@ const (
// Interface guard
var _ caddy.ListenerWrapper = (*tlsPlaceholderWrapper)(nil)
+var _ caddyfile.Unmarshaler = (*tlsPlaceholderWrapper)(nil)