From e7a534d0a311d9fa75b5981879c755281c4c9fba Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Sun, 11 Feb 2024 13:30:14 -0500 Subject: [PATCH 01/14] caddyfile: Reject long heredoc markers (#6098) Co-authored-by: Mohammed Al Sahaf --- caddyconfig/caddyfile/formatter.go | 5 +++ caddyconfig/caddyfile/formatter_test.go | 41 +++++++++++++----- caddyconfig/caddyfile/lexer.go | 4 ++ ...ase-minimized-fuzz-format-5806400649363456 | Bin 0 -> 139348 bytes 4 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 caddyconfig/caddyfile/testdata/clusterfuzz-testcase-minimized-fuzz-format-5806400649363456 diff --git a/caddyconfig/caddyfile/formatter.go b/caddyconfig/caddyfile/formatter.go index 764f7911..423de542 100644 --- a/caddyconfig/caddyfile/formatter.go +++ b/caddyconfig/caddyfile/formatter.go @@ -16,6 +16,7 @@ package caddyfile import ( "bytes" + "fmt" "io" "unicode" @@ -118,6 +119,10 @@ func Format(input []byte) []byte { heredoc = heredocClosed } else { heredocMarker = append(heredocMarker, ch) + if len(heredocMarker) > 32 { + errorString := fmt.Sprintf("heredoc marker too long: <<%s", string(heredocMarker)) + panic(errorString) + } write(ch) continue } diff --git a/caddyconfig/caddyfile/formatter_test.go b/caddyconfig/caddyfile/formatter_test.go index 6eec822f..5ea29c33 100644 --- a/caddyconfig/caddyfile/formatter_test.go +++ b/caddyconfig/caddyfile/formatter_test.go @@ -15,6 +15,8 @@ package caddyfile import ( + "fmt" + "os" "strings" "testing" ) @@ -24,6 +26,7 @@ func TestFormatter(t *testing.T) { description string input string expect string + panics bool }{ { description: "very simple", @@ -434,18 +437,36 @@ block2 { } `, }, + { + description: "very long heredoc from fuzzer", + input: func() string { + bs, _ := os.ReadFile("testdata/clusterfuzz-testcase-minimized-fuzz-format-5806400649363456") + return string(bs) + }(), + panics: true, + }, } { - // the formatter should output a trailing newline, - // even if the tests aren't written to expect that - if !strings.HasSuffix(tc.expect, "\n") { - tc.expect += "\n" - } + t.Run(fmt.Sprintf("test case %d: %s", i, tc.description), func(t *testing.T) { + if tc.panics { + defer func() { + if r := recover(); r == nil { + t.Errorf("[TEST %d: %s] Expected panic, but got none", i, tc.description) + } + }() + } - actual := Format([]byte(tc.input)) + // the formatter should output a trailing newline, + // even if the tests aren't written to expect that + if !strings.HasSuffix(tc.expect, "\n") { + tc.expect += "\n" + } - if string(actual) != tc.expect { - t.Errorf("\n[TEST %d: %s]\n====== EXPECTED ======\n%s\n====== ACTUAL ======\n%s^^^^^^^^^^^^^^^^^^^^^", - i, tc.description, string(tc.expect), string(actual)) - } + actual := Format([]byte(tc.input)) + + if !tc.panics && string(actual) != tc.expect { + t.Errorf("\n[TEST %d: %s]\n====== EXPECTED ======\n%s\n====== ACTUAL ======\n%s^^^^^^^^^^^^^^^^^^^^^", + i, tc.description, string(tc.expect), string(actual)) + } + }) } } diff --git a/caddyconfig/caddyfile/lexer.go b/caddyconfig/caddyfile/lexer.go index 4db63749..a59f0fc4 100644 --- a/caddyconfig/caddyfile/lexer.go +++ b/caddyconfig/caddyfile/lexer.go @@ -149,6 +149,10 @@ func (l *lexer) next() (bool, error) { continue } + if len(val) > 32 { + return false, fmt.Errorf("heredoc marker too long on line #%d: %s", l.line, string(val)) + } + // after hitting a newline, we know that the heredoc marker // is the characters after the two << and the newline. // we reset the val because the heredoc is syntax we don't diff --git a/caddyconfig/caddyfile/testdata/clusterfuzz-testcase-minimized-fuzz-format-5806400649363456 b/caddyconfig/caddyfile/testdata/clusterfuzz-testcase-minimized-fuzz-format-5806400649363456 new file mode 100644 index 0000000000000000000000000000000000000000..94b70919c4b59df0f1fa3740aa6f20577ac3d74a GIT binary patch literal 139348 zcmeI*J8s)R5CBlt3tz!U2*CY_Tn2lSRH=Og-NivJ=_ZB3k7N;!3pYj}>!}!xM%>xm zr(V-qd<>zr{9}prPk4D~Ep<;Vuam6 zN$ReZeZDn}ySDo+mbK^ZYx6n(=|zA50RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXFd|81ITC2w;=3QJXU-r%} zMt}eT0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZ;7$a7JwN}xldHNW0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZ;3D8J87~sv2@oJafB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ;HCw>-}LDno&W&? z1PBlyK!5-N0-q)jLTmN7#Jr1JWsBt)T4?q4!?NHMULIOY-P7CUsk>J8`F@LC^G~~$ z#smluAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBngF#*#fZ|nziTml3L5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5O`m}^vL&JR0$9uK!5-N0t5&UxO;)?u*d%~J@P!ba+@ca*7234 zrm2=VPN(H)^XSTLTIKQ<$3B)AYc4}yhAHJZ<~Y&mRpW4=LUEhwt z{J;#%T>4Z~9_F3;Dc3U0`{q2(n~!DQdZ;PJav0bC|4zz$ec-S@@U7M%ma!kEG7UAZ Jm+QOG{RP*)&zS%K literal 0 HcmV?d00001 From 91ec75441ab5b95deec4ee6794f00b3880ec6336 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Mon, 12 Feb 2024 12:15:35 -0500 Subject: [PATCH 02/14] logging: Inline Caddyfile syntax for `ip_mask` filter (#6094) --- .../caddyfile_adapt/log_filters.txt | 6 ++++++ modules/logging/filters.go | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/caddytest/integration/caddyfile_adapt/log_filters.txt b/caddytest/integration/caddyfile_adapt/log_filters.txt index 776fa68d..28524a34 100644 --- a/caddytest/integration/caddyfile_adapt/log_filters.txt +++ b/caddytest/integration/caddyfile_adapt/log_filters.txt @@ -21,6 +21,7 @@ log { ipv4 24 ipv6 32 } + request>client_ip ip_mask 16 32 request>headers>Regexp regexp secret REDACTED request>headers>Hash hash } @@ -41,6 +42,11 @@ log { }, "encoder": { "fields": { + "request\u003eclient_ip": { + "filter": "ip_mask", + "ipv4_cidr": 16, + "ipv6_cidr": 32 + }, "request\u003eheaders\u003eAuthorization": { "filter": "replace", "value": "REDACTED" diff --git a/modules/logging/filters.go b/modules/logging/filters.go index f38f8c18..79d908fc 100644 --- a/modules/logging/filters.go +++ b/modules/logging/filters.go @@ -169,6 +169,27 @@ func (IPMaskFilter) CaddyModule() caddy.ModuleInfo { // UnmarshalCaddyfile sets up the module from Caddyfile tokens. func (m *IPMaskFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { d.Next() // consume filter name + + args := d.RemainingArgs() + if len(args) > 2 { + return d.Errf("too many arguments") + } + if len(args) > 0 { + val, err := strconv.Atoi(args[0]) + if err != nil { + return d.Errf("error parsing %s: %v", args[0], err) + } + m.IPv4MaskRaw = val + + if len(args) > 1 { + val, err := strconv.Atoi(args[1]) + if err != nil { + return d.Errf("error parsing %s: %v", args[1], err) + } + m.IPv6MaskRaw = val + } + } + for d.NextBlock(0) { switch d.Val() { case "ipv4": From f9e11158bc139294804cba99e9fea408f1fb00d6 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Mon, 12 Feb 2024 12:34:23 -0500 Subject: [PATCH 03/14] caddyauth: Rename `basicauth` to `basic_auth` (#6092) --- caddyconfig/caddyfile/parse_test.go | 8 ++++---- caddyconfig/httpcaddyfile/directives.go | 3 ++- modules/caddyhttp/caddyauth/caddyfile.go | 10 ++++++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/caddyconfig/caddyfile/parse_test.go b/caddyconfig/caddyfile/parse_test.go index 90f5095d..eec94e3a 100644 --- a/caddyconfig/caddyfile/parse_test.go +++ b/caddyconfig/caddyfile/parse_test.go @@ -801,7 +801,7 @@ func TestImportedFilesIgnoreNonDirectiveImportTokens(t *testing.T) { fileName := writeStringToTempFileOrDie(t, ` http://example.com { # This isn't an import directive, it's just an arg with value 'import' - basicauth / import password + basic_auth / import password } `) // Parse the root file that imports the other one. @@ -812,12 +812,12 @@ func TestImportedFilesIgnoreNonDirectiveImportTokens(t *testing.T) { } auth := blocks[0].Segments[0] line := auth[0].Text + " " + auth[1].Text + " " + auth[2].Text + " " + auth[3].Text - if line != "basicauth / import password" { + if line != "basic_auth / import password" { // Previously, it would be changed to: - // basicauth / import /path/to/test/dir/password + // basic_auth / import /path/to/test/dir/password // referencing a file that (probably) doesn't exist and changing the // password! - t.Errorf("Expected basicauth tokens to be 'basicauth / import password' but got %#q", line) + t.Errorf("Expected basic_auth tokens to be 'basic_auth / import password' but got %#q", line) } } diff --git a/caddyconfig/httpcaddyfile/directives.go b/caddyconfig/httpcaddyfile/directives.go index 6e5241c7..9a549a18 100644 --- a/caddyconfig/httpcaddyfile/directives.go +++ b/caddyconfig/httpcaddyfile/directives.go @@ -58,7 +58,8 @@ var directiveOrder = []string{ "try_files", // middleware handlers; some wrap responses - "basicauth", + "basicauth", // TODO: deprecated, renamed to basic_auth + "basic_auth", "forward_auth", "request_header", "encode", diff --git a/modules/caddyhttp/caddyauth/caddyfile.go b/modules/caddyhttp/caddyauth/caddyfile.go index 66201dd9..d46a2a88 100644 --- a/modules/caddyhttp/caddyauth/caddyfile.go +++ b/modules/caddyhttp/caddyauth/caddyfile.go @@ -22,12 +22,13 @@ import ( ) func init() { - httpcaddyfile.RegisterHandlerDirective("basicauth", parseCaddyfile) + httpcaddyfile.RegisterHandlerDirective("basicauth", parseCaddyfile) // deprecated + httpcaddyfile.RegisterHandlerDirective("basic_auth", parseCaddyfile) } // parseCaddyfile sets up the handler from Caddyfile tokens. Syntax: // -// basicauth [] [ []] { +// basic_auth [] [ []] { // [] // ... // } @@ -36,6 +37,11 @@ func init() { func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { h.Next() // consume directive name + // "basicauth" is deprecated, replaced by "basic_auth" + if h.Val() == "basicauth" { + caddy.Log().Named("config.adapter.caddyfile").Warn("the 'basicauth' directive is deprecated, please use 'basic_auth' instead!") + } + var ba HTTPBasicAuth ba.HashCache = new(Cache) From 21744b6c4cabbdeaa81f645c3068c92dffa856e0 Mon Sep 17 00:00:00 2001 From: Mohammed Al Sahaf Date: Mon, 12 Feb 2024 21:06:22 +0300 Subject: [PATCH 04/14] Revert "caddyfile: Reject long heredoc markers (#6098)" (#6100) This reverts commit e7a534d0a311d9fa75b5981879c755281c4c9fba. --- caddyconfig/caddyfile/formatter.go | 5 --- caddyconfig/caddyfile/formatter_test.go | 41 +++++------------- caddyconfig/caddyfile/lexer.go | 4 -- ...ase-minimized-fuzz-format-5806400649363456 | Bin 139348 -> 0 bytes 4 files changed, 10 insertions(+), 40 deletions(-) delete mode 100644 caddyconfig/caddyfile/testdata/clusterfuzz-testcase-minimized-fuzz-format-5806400649363456 diff --git a/caddyconfig/caddyfile/formatter.go b/caddyconfig/caddyfile/formatter.go index 423de542..764f7911 100644 --- a/caddyconfig/caddyfile/formatter.go +++ b/caddyconfig/caddyfile/formatter.go @@ -16,7 +16,6 @@ package caddyfile import ( "bytes" - "fmt" "io" "unicode" @@ -119,10 +118,6 @@ func Format(input []byte) []byte { heredoc = heredocClosed } else { heredocMarker = append(heredocMarker, ch) - if len(heredocMarker) > 32 { - errorString := fmt.Sprintf("heredoc marker too long: <<%s", string(heredocMarker)) - panic(errorString) - } write(ch) continue } diff --git a/caddyconfig/caddyfile/formatter_test.go b/caddyconfig/caddyfile/formatter_test.go index 5ea29c33..6eec822f 100644 --- a/caddyconfig/caddyfile/formatter_test.go +++ b/caddyconfig/caddyfile/formatter_test.go @@ -15,8 +15,6 @@ package caddyfile import ( - "fmt" - "os" "strings" "testing" ) @@ -26,7 +24,6 @@ func TestFormatter(t *testing.T) { description string input string expect string - panics bool }{ { description: "very simple", @@ -437,36 +434,18 @@ block2 { } `, }, - { - description: "very long heredoc from fuzzer", - input: func() string { - bs, _ := os.ReadFile("testdata/clusterfuzz-testcase-minimized-fuzz-format-5806400649363456") - return string(bs) - }(), - panics: true, - }, } { - t.Run(fmt.Sprintf("test case %d: %s", i, tc.description), func(t *testing.T) { - if tc.panics { - defer func() { - if r := recover(); r == nil { - t.Errorf("[TEST %d: %s] Expected panic, but got none", i, tc.description) - } - }() - } + // the formatter should output a trailing newline, + // even if the tests aren't written to expect that + if !strings.HasSuffix(tc.expect, "\n") { + tc.expect += "\n" + } - // the formatter should output a trailing newline, - // even if the tests aren't written to expect that - if !strings.HasSuffix(tc.expect, "\n") { - tc.expect += "\n" - } + actual := Format([]byte(tc.input)) - actual := Format([]byte(tc.input)) - - if !tc.panics && string(actual) != tc.expect { - t.Errorf("\n[TEST %d: %s]\n====== EXPECTED ======\n%s\n====== ACTUAL ======\n%s^^^^^^^^^^^^^^^^^^^^^", - i, tc.description, string(tc.expect), string(actual)) - } - }) + if string(actual) != tc.expect { + t.Errorf("\n[TEST %d: %s]\n====== EXPECTED ======\n%s\n====== ACTUAL ======\n%s^^^^^^^^^^^^^^^^^^^^^", + i, tc.description, string(tc.expect), string(actual)) + } } } diff --git a/caddyconfig/caddyfile/lexer.go b/caddyconfig/caddyfile/lexer.go index a59f0fc4..4db63749 100644 --- a/caddyconfig/caddyfile/lexer.go +++ b/caddyconfig/caddyfile/lexer.go @@ -149,10 +149,6 @@ func (l *lexer) next() (bool, error) { continue } - if len(val) > 32 { - return false, fmt.Errorf("heredoc marker too long on line #%d: %s", l.line, string(val)) - } - // after hitting a newline, we know that the heredoc marker // is the characters after the two << and the newline. // we reset the val because the heredoc is syntax we don't diff --git a/caddyconfig/caddyfile/testdata/clusterfuzz-testcase-minimized-fuzz-format-5806400649363456 b/caddyconfig/caddyfile/testdata/clusterfuzz-testcase-minimized-fuzz-format-5806400649363456 deleted file mode 100644 index 94b70919c4b59df0f1fa3740aa6f20577ac3d74a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 139348 zcmeI*J8s)R5CBlt3tz!U2*CY_Tn2lSRH=Og-NivJ=_ZB3k7N;!3pYj}>!}!xM%>xm zr(V-qd<>zr{9}prPk4D~Ep<;Vuam6 zN$ReZeZDn}ySDo+mbK^ZYx6n(=|zA50RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXFd|81ITC2w;=3QJXU-r%} zMt}eT0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZ;7$a7JwN}xldHNW0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZ;3D8J87~sv2@oJafB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ;HCw>-}LDno&W&? z1PBlyK!5-N0-q)jLTmN7#Jr1JWsBt)T4?q4!?NHMULIOY-P7CUsk>J8`F@LC^G~~$ z#smluAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBngF#*#fZ|nziTml3L5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5O`m}^vL&JR0$9uK!5-N0t5&UxO;)?u*d%~J@P!ba+@ca*7234 zrm2=VPN(H)^XSTLTIKQ<$3B)AYc4}yhAHJZ<~Y&mRpW4=LUEhwt z{J;#%T>4Z~9_F3;Dc3U0`{q2(n~!DQdZ;PJav0bC|4zz$ec-S@@U7M%ma!kEG7UAZ Jm+QOG{RP*)&zS%K From 30d63648f526c1f994173ce24ccf7fe71ca24365 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Mon, 12 Feb 2024 14:33:54 -0500 Subject: [PATCH 05/14] caddyauth: Drop support for `scrypt` (#6091) --- modules/caddyhttp/caddyauth/basicauth.go | 36 +++------ modules/caddyhttp/caddyauth/caddyfile.go | 9 +-- modules/caddyhttp/caddyauth/command.go | 20 +---- modules/caddyhttp/caddyauth/hashes.go | 99 +----------------------- 4 files changed, 22 insertions(+), 142 deletions(-) diff --git a/modules/caddyhttp/caddyauth/basicauth.go b/modules/caddyhttp/caddyauth/basicauth.go index f30a8691..52a5a08c 100644 --- a/modules/caddyhttp/caddyauth/basicauth.go +++ b/modules/caddyhttp/caddyauth/basicauth.go @@ -108,7 +108,6 @@ func (hba *HTTPBasicAuth) Provision(ctx caddy.Context) error { acct.Username = repl.ReplaceAll(acct.Username, "") acct.Password = repl.ReplaceAll(acct.Password, "") - acct.Salt = repl.ReplaceAll(acct.Salt, "") if acct.Username == "" || acct.Password == "" { return fmt.Errorf("account %d: username and password are required", i) @@ -127,13 +126,6 @@ func (hba *HTTPBasicAuth) Provision(ctx caddy.Context) error { } } - if acct.Salt != "" { - acct.salt, err = base64.StdEncoding.DecodeString(acct.Salt) - if err != nil { - return fmt.Errorf("base64-decoding salt: %v", err) - } - } - hba.Accounts[acct.Username] = acct } hba.AccountList = nil // allow GC to deallocate @@ -172,7 +164,7 @@ func (hba HTTPBasicAuth) Authenticate(w http.ResponseWriter, req *http.Request) func (hba HTTPBasicAuth) correctPassword(account Account, plaintextPassword []byte) (bool, error) { compare := func() (bool, error) { - return hba.Hash.Compare(account.password, plaintextPassword, account.salt) + return hba.Hash.Compare(account.password, plaintextPassword) } // if no caching is enabled, simply return the result of hashing + comparing @@ -181,7 +173,7 @@ func (hba HTTPBasicAuth) correctPassword(account Account, plaintextPassword []by } // compute a cache key that is unique for these input parameters - cacheKey := hex.EncodeToString(append(append(account.password, account.salt...), plaintextPassword...)) + cacheKey := hex.EncodeToString(append(account.password, plaintextPassword...)) // fast track: if the result of the input is already cached, use it hba.HashCache.mu.RLock() @@ -231,7 +223,7 @@ type Cache struct { mu *sync.RWMutex g *singleflight.Group - // map of concatenated hashed password + plaintext password + salt, to result + // map of concatenated hashed password + plaintext password, to result cache map[string]bool } @@ -274,37 +266,33 @@ func (c *Cache) makeRoom() { // comparison. type Comparer interface { // Compare returns true if the result of hashing - // plaintextPassword with salt is hashedPassword, - // false otherwise. An error is returned only if + // plaintextPassword is hashedPassword, false + // otherwise. An error is returned only if // there is a technical/configuration error. - Compare(hashedPassword, plaintextPassword, salt []byte) (bool, error) + Compare(hashedPassword, plaintextPassword []byte) (bool, error) } // Hasher is a type that can generate a secure hash -// given a plaintext and optional salt (for algorithms -// that require a salt). Hashing modules which implement +// given a plaintext. Hashing modules which implement // this interface can be used with the hash-password // subcommand as well as benefitting from anti-timing // features. A hasher also returns a fake hash which // can be used for timing side-channel mitigation. type Hasher interface { - Hash(plaintext, salt []byte) ([]byte, error) + Hash(plaintext []byte) ([]byte, error) FakeHash() []byte } -// Account contains a username, password, and salt (if applicable). +// Account contains a username and password. type Account struct { // A user's username. Username string `json:"username"` - // The user's hashed password, base64-encoded. + // The user's hashed password, in Modular Crypt Format (with `$` prefix) + // or base64-encoded. Password string `json:"password"` - // The user's password salt, base64-encoded; for - // algorithms where external salt is needed. - Salt string `json:"salt,omitempty"` - - password, salt []byte + password []byte } // Interface guards diff --git a/modules/caddyhttp/caddyauth/caddyfile.go b/modules/caddyhttp/caddyauth/caddyfile.go index d46a2a88..cc92477e 100644 --- a/modules/caddyhttp/caddyauth/caddyfile.go +++ b/modules/caddyhttp/caddyauth/caddyfile.go @@ -29,7 +29,7 @@ func init() { // parseCaddyfile sets up the handler from Caddyfile tokens. Syntax: // // basic_auth [] [ []] { -// [] +// // ... // } // @@ -64,8 +64,6 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) switch hashName { case "bcrypt": cmp = BcryptHash{} - case "scrypt": - cmp = ScryptHash{} default: return nil, h.Errf("unrecognized hash algorithm: %s", hashName) } @@ -75,8 +73,8 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) for h.NextBlock(0) { username := h.Val() - var b64Pwd, b64Salt string - h.Args(&b64Pwd, &b64Salt) + var b64Pwd string + h.Args(&b64Pwd) if h.NextArg() { return nil, h.ArgErr() } @@ -88,7 +86,6 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) ba.AccountList = append(ba.AccountList, Account{ Username: username, Password: b64Pwd, - Salt: b64Salt, }) } diff --git a/modules/caddyhttp/caddyauth/command.go b/modules/caddyhttp/caddyauth/command.go index b93b7a40..c9f44006 100644 --- a/modules/caddyhttp/caddyauth/command.go +++ b/modules/caddyhttp/caddyauth/command.go @@ -17,7 +17,6 @@ package caddyauth import ( "bufio" "bytes" - "encoding/base64" "fmt" "os" "os/signal" @@ -33,7 +32,7 @@ import ( func init() { caddycmd.RegisterCommand(caddycmd.Command{ Name: "hash-password", - Usage: "[--algorithm ] [--salt ] [--plaintext ]", + Usage: "[--plaintext ] [--algorithm ]", Short: "Hashes a password and writes base64", Long: ` Convenient way to hash a plaintext password. The resulting @@ -43,17 +42,10 @@ hash is written to stdout as a base64 string. Caddy is attached to a controlling tty, the plaintext will not be echoed. ---algorithm may be bcrypt or scrypt. If scrypt, the default -parameters are used. - -Use the --salt flag for algorithms which require a salt to -be provided (scrypt). - -Note that scrypt is deprecated. Please use 'bcrypt' instead. +--algorithm currently only supports 'bcrypt', and is the default. `, CobraFunc: func(cmd *cobra.Command) { cmd.Flags().StringP("plaintext", "p", "", "The plaintext password") - cmd.Flags().StringP("salt", "s", "", "The password salt") cmd.Flags().StringP("algorithm", "a", "bcrypt", "Name of the hash algorithm") cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdHashPassword) }, @@ -65,7 +57,6 @@ func cmdHashPassword(fs caddycmd.Flags) (int, error) { algorithm := fs.String("algorithm") plaintext := []byte(fs.String("plaintext")) - salt := []byte(fs.String("salt")) if len(plaintext) == 0 { fd := int(os.Stdin.Fd()) @@ -117,13 +108,8 @@ func cmdHashPassword(fs caddycmd.Flags) (int, error) { var hashString string switch algorithm { case "bcrypt": - hash, err = BcryptHash{}.Hash(plaintext, nil) + hash, err = BcryptHash{}.Hash(plaintext) hashString = string(hash) - case "scrypt": - def := ScryptHash{} - def.SetDefaults() - hash, err = def.Hash(plaintext, salt) - hashString = base64.StdEncoding.EncodeToString(hash) default: return caddy.ExitCodeFailedStartup, fmt.Errorf("unrecognized hash algorithm: %s", algorithm) } diff --git a/modules/caddyhttp/caddyauth/hashes.go b/modules/caddyhttp/caddyauth/hashes.go index 324cf1e1..ce3df901 100644 --- a/modules/caddyhttp/caddyauth/hashes.go +++ b/modules/caddyhttp/caddyauth/hashes.go @@ -15,18 +15,13 @@ package caddyauth import ( - "crypto/subtle" - "encoding/base64" - "golang.org/x/crypto/bcrypt" - "golang.org/x/crypto/scrypt" "github.com/caddyserver/caddy/v2" ) func init() { caddy.RegisterModule(BcryptHash{}) - caddy.RegisterModule(ScryptHash{}) } // BcryptHash implements the bcrypt hash. @@ -41,7 +36,7 @@ func (BcryptHash) CaddyModule() caddy.ModuleInfo { } // Compare compares passwords. -func (BcryptHash) Compare(hashed, plaintext, _ []byte) (bool, error) { +func (BcryptHash) Compare(hashed, plaintext []byte) (bool, error) { err := bcrypt.CompareHashAndPassword(hashed, plaintext) if err == bcrypt.ErrMismatchedHashAndPassword { return false, nil @@ -53,7 +48,7 @@ func (BcryptHash) Compare(hashed, plaintext, _ []byte) (bool, error) { } // Hash hashes plaintext using a random salt. -func (BcryptHash) Hash(plaintext, _ []byte) ([]byte, error) { +func (BcryptHash) Hash(plaintext []byte) ([]byte, error) { return bcrypt.GenerateFromPassword(plaintext, 14) } @@ -64,94 +59,8 @@ func (BcryptHash) FakeHash() []byte { return []byte("$2a$14$X3ulqf/iGxnf1k6oMZ.RZeJUoqI9PX2PM4rS5lkIKJXduLGXGPrt6") } -// ScryptHash implements the scrypt KDF as a hash. -// -// DEPRECATED, please use 'bcrypt' instead. -type ScryptHash struct { - // scrypt's N parameter. If unset or 0, a safe default is used. - N int `json:"N,omitempty"` - - // scrypt's r parameter. If unset or 0, a safe default is used. - R int `json:"r,omitempty"` - - // scrypt's p parameter. If unset or 0, a safe default is used. - P int `json:"p,omitempty"` - - // scrypt's key length parameter (in bytes). If unset or 0, a - // safe default is used. - KeyLength int `json:"key_length,omitempty"` -} - -// CaddyModule returns the Caddy module information. -func (ScryptHash) CaddyModule() caddy.ModuleInfo { - return caddy.ModuleInfo{ - ID: "http.authentication.hashes.scrypt", - New: func() caddy.Module { return new(ScryptHash) }, - } -} - -// Provision sets up s. -func (s *ScryptHash) Provision(ctx caddy.Context) error { - s.SetDefaults() - ctx.Logger().Warn("use of 'scrypt' is deprecated, please use 'bcrypt' instead") - return nil -} - -// SetDefaults sets safe default parameters, but does -// not overwrite existing values. Each default parameter -// is set independently; it does not check to ensure -// that r*p < 2^30. The defaults chosen are those as -// recommended in 2019 by -// https://godoc.org/golang.org/x/crypto/scrypt. -func (s *ScryptHash) SetDefaults() { - if s.N == 0 { - s.N = 32768 - } - if s.R == 0 { - s.R = 8 - } - if s.P == 0 { - s.P = 1 - } - if s.KeyLength == 0 { - s.KeyLength = 32 - } -} - -// Compare compares passwords. -func (s ScryptHash) Compare(hashed, plaintext, salt []byte) (bool, error) { - ourHash, err := scrypt.Key(plaintext, salt, s.N, s.R, s.P, s.KeyLength) - if err != nil { - return false, err - } - if hashesMatch(hashed, ourHash) { - return true, nil - } - return false, nil -} - -// Hash hashes plaintext using the given salt. -func (s ScryptHash) Hash(plaintext, salt []byte) ([]byte, error) { - return scrypt.Key(plaintext, salt, s.N, s.R, s.P, s.KeyLength) -} - -// FakeHash returns a fake hash. -func (ScryptHash) FakeHash() []byte { - // hashed with the following command: - // caddy hash-password --plaintext "antitiming" --salt "fakesalt" --algorithm "scrypt" - bytes, _ := base64.StdEncoding.DecodeString("kFbjiVemlwK/ZS0tS6/UQqEDeaNMigyCs48KEsGUse8=") - return bytes -} - -func hashesMatch(pwdHash1, pwdHash2 []byte) bool { - return subtle.ConstantTimeCompare(pwdHash1, pwdHash2) == 1 -} - // Interface guards var ( - _ Comparer = (*BcryptHash)(nil) - _ Comparer = (*ScryptHash)(nil) - _ Hasher = (*BcryptHash)(nil) - _ Hasher = (*ScryptHash)(nil) - _ caddy.Provisioner = (*ScryptHash)(nil) + _ Comparer = (*BcryptHash)(nil) + _ Hasher = (*BcryptHash)(nil) ) From 2c48dda109d213be0012743d8afb2d1f017ff878 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Tue, 13 Feb 2024 13:45:38 -0500 Subject: [PATCH 06/14] caddyhttp: Only attempt to enable full duplex for HTTP/1.x (#6102) --- modules/caddyhttp/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index 1dec6079..77af3136 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -301,11 +301,11 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // enable full-duplex for HTTP/1, ensuring the entire // request body gets consumed before writing the response - if s.EnableFullDuplex { + if s.EnableFullDuplex && r.ProtoMajor == 1 { //nolint:bodyclose err := http.NewResponseController(w).EnableFullDuplex() if err != nil { - s.accessLogger.Warn("failed to enable full duplex", zap.Error(err)) + s.logger.Warn("failed to enable full duplex", zap.Error(err)) } } From 127788807fdc32feb48a7f24a7e89f954ad3a049 Mon Sep 17 00:00:00 2001 From: Matt Holt Date: Wed, 14 Feb 2024 21:21:23 -0700 Subject: [PATCH 07/14] caddyhttp: Register post-shutdown callbacks (#5948) --- modules/caddyhttp/app.go | 9 +++++++++ modules/caddyhttp/server.go | 10 +++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/caddyhttp/app.go b/modules/caddyhttp/app.go index 0ae0af39..cdb368c4 100644 --- a/modules/caddyhttp/app.go +++ b/modules/caddyhttp/app.go @@ -642,6 +642,15 @@ func (app *App) Stop() error { finishedShutdown.Wait() } + // run stop callbacks now that the server shutdowns are complete + for name, s := range app.Servers { + for _, stopHook := range s.onStopFuncs { + if err := stopHook(ctx); err != nil { + app.logger.Error("server stop hook", zap.String("server", name), zap.Error(err)) + } + } + } + return nil } diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index 77af3136..9ea04acb 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -253,6 +253,7 @@ type Server struct { connStateFuncs []func(net.Conn, http.ConnState) connContextFuncs []func(ctx context.Context, c net.Conn) context.Context onShutdownFuncs []func() + onStopFuncs []func(context.Context) error // TODO: Experimental (Nov. 2023) } // ServeHTTP is the entry point for all HTTP requests. @@ -630,11 +631,18 @@ func (s *Server) RegisterConnContext(f func(ctx context.Context, c net.Conn) con s.connContextFuncs = append(s.connContextFuncs, f) } -// RegisterOnShutdown registers f to be invoked on server shutdown. +// RegisterOnShutdown registers f to be invoked when the server begins to shut down. func (s *Server) RegisterOnShutdown(f func()) { s.onShutdownFuncs = append(s.onShutdownFuncs, f) } +// RegisterOnStop registers f to be invoked after the server has shut down completely. +// +// EXPERIMENTAL: Subject to change or removal. +func (s *Server) RegisterOnStop(f func(context.Context) error) { + s.onStopFuncs = append(s.onStopFuncs, f) +} + // HTTPErrorConfig determines how to handle errors // from the HTTP handlers. type HTTPErrorConfig struct { From b893c8c5f856ba7399ed05c8de82fa5c8158ff00 Mon Sep 17 00:00:00 2001 From: Aziz Rmadi <46684200+armadi1809@users.noreply.github.com> Date: Sun, 18 Feb 2024 18:22:48 -0600 Subject: [PATCH 08/14] caddyfile: Reject directives in the place of site addresses (#6104) Co-authored-by: Francis Lavoie --- caddyconfig/caddyfile/parse.go | 52 +++++++++++-------- caddyconfig/caddyfile/parse_test.go | 18 ++++--- caddyconfig/httpcaddyfile/addresses.go | 10 ++-- caddyconfig/httpcaddyfile/httptype.go | 13 +++-- caddytest/integration/acme_test.go | 2 +- ...http_valid_directive_like_site_address.txt | 46 ++++++++++++++++ caddytest/integration/caddyfile_test.go | 28 ++++++++++ caddytest/integration/pki_test.go | 6 +++ 8 files changed, 135 insertions(+), 40 deletions(-) create mode 100644 caddytest/integration/caddyfile_adapt/http_valid_directive_like_site_address.txt diff --git a/caddyconfig/caddyfile/parse.go b/caddyconfig/caddyfile/parse.go index 65d6ee92..9f79d913 100644 --- a/caddyconfig/caddyfile/parse.go +++ b/caddyconfig/caddyfile/parse.go @@ -160,14 +160,14 @@ func (p *parser) begin() error { } if ok, name := p.isNamedRoute(); ok { - // named routes only have one key, the route name - p.block.Keys = []string{name} - p.block.IsNamedRoute = true - // we just need a dummy leading token to ease parsing later nameToken := p.Token() nameToken.Text = name + // named routes only have one key, the route name + p.block.Keys = []Token{nameToken} + p.block.IsNamedRoute = true + // get all the tokens from the block, including the braces tokens, err := p.blockTokens(true) if err != nil { @@ -211,10 +211,11 @@ func (p *parser) addresses() error { var expectingAnother bool for { - tkn := p.Val() + value := p.Val() + token := p.Token() // special case: import directive replaces tokens during parse-time - if tkn == "import" && p.isNewLine() { + if value == "import" && p.isNewLine() { err := p.doImport(0) if err != nil { return err @@ -223,9 +224,9 @@ func (p *parser) addresses() error { } // Open brace definitely indicates end of addresses - if tkn == "{" { + if value == "{" { if expectingAnother { - return p.Errf("Expected another address but had '%s' - check for extra comma", tkn) + return p.Errf("Expected another address but had '%s' - check for extra comma", value) } // Mark this server block as being defined with braces. // This is used to provide a better error message when @@ -237,15 +238,15 @@ func (p *parser) addresses() error { } // Users commonly forget to place a space between the address and the '{' - if strings.HasSuffix(tkn, "{") { - return p.Errf("Site addresses cannot end with a curly brace: '%s' - put a space between the token and the brace", tkn) + if strings.HasSuffix(value, "{") { + return p.Errf("Site addresses cannot end with a curly brace: '%s' - put a space between the token and the brace", value) } - if tkn != "" { // empty token possible if user typed "" + if value != "" { // empty token possible if user typed "" // Trailing comma indicates another address will follow, which // may possibly be on the next line - if tkn[len(tkn)-1] == ',' { - tkn = tkn[:len(tkn)-1] + if value[len(value)-1] == ',' { + value = value[:len(value)-1] expectingAnother = true } else { expectingAnother = false // but we may still see another one on this line @@ -254,11 +255,12 @@ func (p *parser) addresses() error { // If there's a comma here, it's probably because they didn't use a space // between their two domains, e.g. "foo.com,bar.com", which would not be // parsed as two separate site addresses. - if strings.Contains(tkn, ",") { - return p.Errf("Site addresses cannot contain a comma ',': '%s' - put a space after the comma to separate site addresses", tkn) + if strings.Contains(value, ",") { + return p.Errf("Site addresses cannot contain a comma ',': '%s' - put a space after the comma to separate site addresses", value) } - p.block.Keys = append(p.block.Keys, tkn) + token.Text = value + p.block.Keys = append(p.block.Keys, token) } // Advance token and possibly break out of loop or return error @@ -637,8 +639,8 @@ func (p *parser) closeCurlyBrace() error { func (p *parser) isNamedRoute() (bool, string) { keys := p.block.Keys // A named route block is a single key with parens, prefixed with &. - if len(keys) == 1 && strings.HasPrefix(keys[0], "&(") && strings.HasSuffix(keys[0], ")") { - return true, strings.TrimSuffix(keys[0][2:], ")") + if len(keys) == 1 && strings.HasPrefix(keys[0].Text, "&(") && strings.HasSuffix(keys[0].Text, ")") { + return true, strings.TrimSuffix(keys[0].Text[2:], ")") } return false, "" } @@ -646,8 +648,8 @@ func (p *parser) isNamedRoute() (bool, string) { func (p *parser) isSnippet() (bool, string) { keys := p.block.Keys // A snippet block is a single key with parens. Nothing else qualifies. - if len(keys) == 1 && strings.HasPrefix(keys[0], "(") && strings.HasSuffix(keys[0], ")") { - return true, strings.TrimSuffix(keys[0][1:], ")") + if len(keys) == 1 && strings.HasPrefix(keys[0].Text, "(") && strings.HasSuffix(keys[0].Text, ")") { + return true, strings.TrimSuffix(keys[0].Text[1:], ")") } return false, "" } @@ -691,11 +693,19 @@ func (p *parser) blockTokens(retainCurlies bool) ([]Token, error) { // grouped by segments. type ServerBlock struct { HasBraces bool - Keys []string + Keys []Token Segments []Segment IsNamedRoute bool } +func (sb ServerBlock) GetKeysText() []string { + res := []string{} + for _, k := range sb.Keys { + res = append(res, k.Text) + } + return res +} + // DispenseDirective returns a dispenser that contains // all the tokens in the server block. func (sb ServerBlock) DispenseDirective(dir string) *Dispenser { diff --git a/caddyconfig/caddyfile/parse_test.go b/caddyconfig/caddyfile/parse_test.go index eec94e3a..6daded1c 100644 --- a/caddyconfig/caddyfile/parse_test.go +++ b/caddyconfig/caddyfile/parse_test.go @@ -347,7 +347,7 @@ func TestParseOneAndImport(t *testing.T) { i, len(test.keys), len(result.Keys)) continue } - for j, addr := range result.Keys { + for j, addr := range result.GetKeysText() { if addr != test.keys[j] { t.Errorf("Test %d, key %d: Expected '%s', but was '%s'", i, j, test.keys[j], addr) @@ -379,8 +379,9 @@ func TestRecursiveImport(t *testing.T) { } isExpected := func(got ServerBlock) bool { - if len(got.Keys) != 1 || got.Keys[0] != "localhost" { - t.Errorf("got keys unexpected: expect localhost, got %v", got.Keys) + textKeys := got.GetKeysText() + if len(textKeys) != 1 || textKeys[0] != "localhost" { + t.Errorf("got keys unexpected: expect localhost, got %v", textKeys) return false } if len(got.Segments) != 2 { @@ -474,8 +475,9 @@ func TestDirectiveImport(t *testing.T) { } isExpected := func(got ServerBlock) bool { - if len(got.Keys) != 1 || got.Keys[0] != "localhost" { - t.Errorf("got keys unexpected: expect localhost, got %v", got.Keys) + textKeys := got.GetKeysText() + if len(textKeys) != 1 || textKeys[0] != "localhost" { + t.Errorf("got keys unexpected: expect localhost, got %v", textKeys) return false } if len(got.Segments) != 2 { @@ -616,7 +618,7 @@ func TestParseAll(t *testing.T) { i, len(test.keys[j]), j, len(block.Keys)) continue } - for k, addr := range block.Keys { + for k, addr := range block.GetKeysText() { if addr != test.keys[j][k] { t.Errorf("Test %d, block %d, key %d: Expected '%s', but got '%s'", i, j, k, test.keys[j][k], addr) @@ -769,7 +771,7 @@ func TestSnippets(t *testing.T) { if len(blocks) != 1 { t.Fatalf("Expect exactly one server block. Got %d.", len(blocks)) } - if actual, expected := blocks[0].Keys[0], "http://example.com"; expected != actual { + if actual, expected := blocks[0].GetKeysText()[0], "http://example.com"; expected != actual { t.Errorf("Expected server name to be '%s' but was '%s'", expected, actual) } if len(blocks[0].Segments) != 2 { @@ -844,7 +846,7 @@ func TestSnippetAcrossMultipleFiles(t *testing.T) { if len(blocks) != 1 { t.Fatalf("Expect exactly one server block. Got %d.", len(blocks)) } - if actual, expected := blocks[0].Keys[0], "http://example.com"; expected != actual { + if actual, expected := blocks[0].GetKeysText()[0], "http://example.com"; expected != actual { t.Errorf("Expected server name to be '%s' but was '%s'", expected, actual) } if len(blocks[0].Segments) != 1 { diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go index 658da48e..da51fe9b 100644 --- a/caddyconfig/httpcaddyfile/addresses.go +++ b/caddyconfig/httpcaddyfile/addresses.go @@ -88,15 +88,15 @@ func (st *ServerType) mapAddressToServerBlocks(originalServerBlocks []serverBloc // will be served by them; this has the effect of treating each // key of a server block as its own, but without having to repeat its // contents in cases where multiple keys really can be served together - addrToKeys := make(map[string][]string) + addrToKeys := make(map[string][]caddyfile.Token) for j, key := range sblock.block.Keys { // a key can have multiple listener addresses if there are multiple // arguments to the 'bind' directive (although they will all have // the same port, since the port is defined by the key or is implicit // through automatic HTTPS) - addrs, err := st.listenerAddrsForServerBlockKey(sblock, key, options) + addrs, err := st.listenerAddrsForServerBlockKey(sblock, key.Text, options) if err != nil { - return nil, fmt.Errorf("server block %d, key %d (%s): determining listener address: %v", i, j, key, err) + return nil, fmt.Errorf("server block %d, key %d (%s): determining listener address: %v", i, j, key.Text, err) } // associate this key with each listener address it is served on @@ -122,9 +122,9 @@ func (st *ServerType) mapAddressToServerBlocks(originalServerBlocks []serverBloc // parse keys so that we only have to do it once parsedKeys := make([]Address, 0, len(keys)) for _, key := range keys { - addr, err := ParseAddress(key) + addr, err := ParseAddress(key.Text) if err != nil { - return nil, fmt.Errorf("parsing key '%s': %v", key, err) + return nil, fmt.Errorf("parsing key '%s': %v", key.Text, err) } parsedKeys = append(parsedKeys, addr.Normalize()) } diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go index 54e78111..da5557aa 100644 --- a/caddyconfig/httpcaddyfile/httptype.go +++ b/caddyconfig/httpcaddyfile/httptype.go @@ -65,8 +65,11 @@ func (st ServerType) Setup( originalServerBlocks := make([]serverBlock, 0, len(inputServerBlocks)) for _, sblock := range inputServerBlocks { for j, k := range sblock.Keys { - if j == 0 && strings.HasPrefix(k, "@") { - return nil, warnings, fmt.Errorf("cannot define a matcher outside of a site block: '%s'", k) + if j == 0 && strings.HasPrefix(k.Text, "@") { + return nil, warnings, fmt.Errorf("%s:%d: cannot define a matcher outside of a site block: '%s'", k.File, k.Line, k.Text) + } + if _, ok := registeredDirectives[k.Text]; ok { + return nil, warnings, fmt.Errorf("%s:%d: parsed '%s' as a site address, but it is a known directive; directives must appear in a site block", k.File, k.Line, k.Text) } } originalServerBlocks = append(originalServerBlocks, serverBlock{ @@ -490,7 +493,7 @@ func (ServerType) extractNamedRoutes( route.HandlersRaw = []json.RawMessage{caddyconfig.JSONModuleObject(handler, "handler", subroute.CaddyModule().ID.Name(), h.warnings)} } - namedRoutes[sb.block.Keys[0]] = &route + namedRoutes[sb.block.GetKeysText()[0]] = &route } options["named_routes"] = namedRoutes @@ -528,12 +531,12 @@ func (st *ServerType) serversFromPairings( // address), otherwise their routes will improperly be added // to the same server (see issue #4635) for j, sblock1 := range p.serverBlocks { - for _, key := range sblock1.block.Keys { + for _, key := range sblock1.block.GetKeysText() { for k, sblock2 := range p.serverBlocks { if k == j { continue } - if sliceContains(sblock2.block.Keys, key) { + if sliceContains(sblock2.block.GetKeysText(), key) { return nil, fmt.Errorf("ambiguous site definition: %s", key) } } diff --git a/caddytest/integration/acme_test.go b/caddytest/integration/acme_test.go index 00a3a6c4..45db8f01 100644 --- a/caddytest/integration/acme_test.go +++ b/caddytest/integration/acme_test.go @@ -23,7 +23,7 @@ import ( "go.uber.org/zap" ) -const acmeChallengePort = 8080 +const acmeChallengePort = 9081 // Test the basic functionality of Caddy's ACME server func TestACMEServerWithDefaults(t *testing.T) { diff --git a/caddytest/integration/caddyfile_adapt/http_valid_directive_like_site_address.txt b/caddytest/integration/caddyfile_adapt/http_valid_directive_like_site_address.txt new file mode 100644 index 00000000..675523a5 --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/http_valid_directive_like_site_address.txt @@ -0,0 +1,46 @@ +http://handle { + file_server +} +---------- +{ + "apps": { + "http": { + "servers": { + "srv0": { + "listen": [ + ":80" + ], + "routes": [ + { + "match": [ + { + "host": [ + "handle" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "handler": "file_server", + "hide": [ + "./Caddyfile" + ] + } + ] + } + ] + } + ], + "terminal": true + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/caddytest/integration/caddyfile_test.go b/caddytest/integration/caddyfile_test.go index f9a98fb3..959783be 100644 --- a/caddytest/integration/caddyfile_test.go +++ b/caddytest/integration/caddyfile_test.go @@ -496,6 +496,7 @@ func TestUriReplace(t *testing.T) { tester.AssertGetResponse("http://localhost:9080/endpoint?test={%20content%20}", 200, "test=%7B%20content%20%7D") } + func TestHandleErrorSimpleCodes(t *testing.T) { tester := caddytest.NewTester(t) tester.InitServer(`{ @@ -584,3 +585,30 @@ func TestHandleErrorRangeAndCodes(t *testing.T) { tester.AssertGetResponse("http://localhost:9080/threehundred", 301, "Error code is equal to 500 or in the [300..399] range") tester.AssertGetResponse("http://localhost:9080/private", 410, "Error in the [400 .. 499] range") } + +func TestInvalidSiteAddressesAsDirectives(t *testing.T) { + type testCase struct { + config, expectedError string + } + + failureCases := []testCase{ + { + config: ` + handle { + file_server + }`, + expectedError: `Caddyfile:2: parsed 'handle' as a site address, but it is a known directive; directives must appear in a site block`, + }, + { + config: ` + reverse_proxy localhost:9000 localhost:9001 { + file_server + }`, + expectedError: `Caddyfile:2: parsed 'reverse_proxy' as a site address, but it is a known directive; directives must appear in a site block`, + }, + } + + for _, failureCase := range failureCases { + caddytest.AssertLoadError(t, failureCase.config, "caddyfile", failureCase.expectedError) + } +} diff --git a/caddytest/integration/pki_test.go b/caddytest/integration/pki_test.go index 5e9928c0..84679820 100644 --- a/caddytest/integration/pki_test.go +++ b/caddytest/integration/pki_test.go @@ -9,6 +9,9 @@ import ( func TestLeafCertLifetimeLessThanIntermediate(t *testing.T) { caddytest.AssertLoadError(t, ` { + "admin": { + "disabled": true + }, "apps": { "http": { "servers": { @@ -56,6 +59,9 @@ func TestLeafCertLifetimeLessThanIntermediate(t *testing.T) { func TestIntermediateLifetimeLessThanRoot(t *testing.T) { caddytest.AssertLoadError(t, ` { + "admin": { + "disabled": true + }, "apps": { "http": { "servers": { From 53f7035299a6de0553349e3b5bcabcf422f07b94 Mon Sep 17 00:00:00 2001 From: WeidiDeng Date: Tue, 20 Feb 2024 11:25:02 +0800 Subject: [PATCH 09/14] reverseproxy: use context.WithoutCancel (#6116) --- .../caddyhttp/reverseproxy/reverseproxy.go | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/modules/caddyhttp/reverseproxy/reverseproxy.go b/modules/caddyhttp/reverseproxy/reverseproxy.go index 201ff638..1648b779 100644 --- a/modules/caddyhttp/reverseproxy/reverseproxy.go +++ b/modules/caddyhttp/reverseproxy/reverseproxy.go @@ -783,7 +783,7 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe // regardless, and we should expect client disconnection in low-latency streaming // scenarios (see issue #4922) if h.FlushInterval == -1 { - req = req.WithContext(ignoreClientGoneContext{req.Context()}) + req = req.WithContext(context.WithoutCancel(req.Context())) } // do the round-trip; emit debug log with values we know are @@ -1419,32 +1419,6 @@ type handleResponseContext struct { isFinalized bool } -// ignoreClientGoneContext is a special context.Context type -// intended for use when doing a RoundTrip where you don't -// want a client disconnection to cancel the request during -// the roundtrip. -// This context clears cancellation, error, and deadline methods, -// but still allows values to pass through from its embedded -// context. -// -// TODO: This can be replaced with context.WithoutCancel once -// the minimum required version of Go is 1.21. -type ignoreClientGoneContext struct { - context.Context -} - -func (c ignoreClientGoneContext) Deadline() (deadline time.Time, ok bool) { - return -} - -func (c ignoreClientGoneContext) Done() <-chan struct{} { - return nil -} - -func (c ignoreClientGoneContext) Err() error { - return nil -} - // proxyHandleResponseContextCtxKey is the context key for the active proxy handler // so that handle_response routes can inherit some config options // from the proxy handler. From 4284e39a1783b72225c7ac184205622fdbdec75a Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Tue, 20 Feb 2024 06:23:39 -0500 Subject: [PATCH 10/14] chore: Update Chroma to get the new Caddyfile lexer (#6118) --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 002db928..0d02c289 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ toolchain go1.21.4 require ( github.com/BurntSushi/toml v1.3.2 github.com/Masterminds/sprig/v3 v3.2.3 - github.com/alecthomas/chroma/v2 v2.9.1 + github.com/alecthomas/chroma/v2 v2.12.1-0.20240220090827-381050ba0001 github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b github.com/caddyserver/certmagic v0.20.0 github.com/dustin/go-humanize v1.0.1 diff --git a/go.sum b/go.sum index 1c3476f8..b4e081a3 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,8 @@ github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhk github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= github.com/alecthomas/chroma/v2 v2.9.1 h1:0O3lTQh9FxazJ4BYE/MOi/vDGuHn7B+6Bu902N2UZvU= github.com/alecthomas/chroma/v2 v2.9.1/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw= +github.com/alecthomas/chroma/v2 v2.12.1-0.20240220090827-381050ba0001 h1:Nl5Om7AhgtN3tML9kLn2/lr8IDVKxHT2t2+xWc4Q6Fs= +github.com/alecthomas/chroma/v2 v2.12.1-0.20240220090827-381050ba0001/go.mod h1:b6DmXsg5hSmn0AcHaTsU+UH0vO73VzhR+JrpFihjsXM= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= From 8bbf8ec6299de9967eac756510ee1d92d42a5610 Mon Sep 17 00:00:00 2001 From: bbaa Date: Tue, 20 Feb 2024 20:29:20 +0800 Subject: [PATCH 11/14] caddyfile: Assert having a space after heredoc marker to simply check (#6117) --- caddyconfig/caddyfile/formatter.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/caddyconfig/caddyfile/formatter.go b/caddyconfig/caddyfile/formatter.go index 764f7911..d506219c 100644 --- a/caddyconfig/caddyfile/formatter.go +++ b/caddyconfig/caddyfile/formatter.go @@ -124,18 +124,22 @@ func Format(input []byte) []byte { } // if we're in a heredoc, all characters are read&write as-is if heredoc == heredocOpened { - write(ch) heredocClosingMarker = append(heredocClosingMarker, ch) - if len(heredocClosingMarker) > len(heredocMarker) { + if len(heredocClosingMarker) > len(heredocMarker)+1 { // We assert that the heredocClosingMarker is followed by a unicode.Space heredocClosingMarker = heredocClosingMarker[1:] } // check if we're done - if slices.Equal(heredocClosingMarker, heredocMarker) { + if unicode.IsSpace(ch) && slices.Equal(heredocClosingMarker[:len(heredocClosingMarker)-1], heredocMarker) { heredocMarker = nil heredocClosingMarker = nil heredoc = heredocClosed + } else { + write(ch) + if ch == '\n' { + heredocClosingMarker = heredocClosingMarker[:0] + } + continue } - continue } if last == '<' && space { From f8143a3af15fb1042dc95791969105eb5b3e9cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Ch=C3=A1vez?= Date: Tue, 20 Feb 2024 23:04:14 +0100 Subject: [PATCH 12/14] tests: uses testing.TB interface for helper to be able to use test server in benchmarks. (#6103) --- caddytest/caddytest.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/caddytest/caddytest.go b/caddytest/caddytest.go index 66697514..deb567b3 100644 --- a/caddytest/caddytest.go +++ b/caddytest/caddytest.go @@ -60,11 +60,11 @@ var ( type Tester struct { Client *http.Client configLoaded bool - t *testing.T + t testing.TB } // NewTester will create a new testing client with an attached cookie jar -func NewTester(t *testing.T) *Tester { +func NewTester(t testing.TB) *Tester { jar, err := cookiejar.New(nil) if err != nil { t.Fatalf("failed to create cookiejar: %s", err) @@ -229,7 +229,7 @@ const initConfig = `{ // validateTestPrerequisites ensures the certificates are available in the // designated path and Caddy sub-process is running. -func validateTestPrerequisites(t *testing.T) error { +func validateTestPrerequisites(t testing.TB) error { // check certificates are found for _, certName := range Default.Certifcates { if _, err := os.Stat(getIntegrationDir() + certName); errors.Is(err, fs.ErrNotExist) { @@ -373,7 +373,7 @@ func (tc *Tester) AssertRedirect(requestURI string, expectedToLocation string, e } // CompareAdapt adapts a config and then compares it against an expected result -func CompareAdapt(t *testing.T, filename, rawConfig string, adapterName string, expectedResponse string) bool { +func CompareAdapt(t testing.TB, filename, rawConfig string, adapterName string, expectedResponse string) bool { cfgAdapter := caddyconfig.GetAdapter(adapterName) if cfgAdapter == nil { t.Logf("unrecognized config adapter '%s'", adapterName) @@ -432,7 +432,7 @@ func CompareAdapt(t *testing.T, filename, rawConfig string, adapterName string, } // AssertAdapt adapts a config and then tests it against an expected result -func AssertAdapt(t *testing.T, rawConfig string, adapterName string, expectedResponse string) { +func AssertAdapt(t testing.TB, rawConfig string, adapterName string, expectedResponse string) { ok := CompareAdapt(t, "Caddyfile", rawConfig, adapterName, expectedResponse) if !ok { t.Fail() @@ -441,7 +441,7 @@ func AssertAdapt(t *testing.T, rawConfig string, adapterName string, expectedRes // Generic request functions -func applyHeaders(t *testing.T, req *http.Request, requestHeaders []string) { +func applyHeaders(t testing.TB, req *http.Request, requestHeaders []string) { requestContentType := "" for _, requestHeader := range requestHeaders { arr := strings.SplitAfterN(requestHeader, ":", 2) From 4512be49a9fa55270e9afa632be9ff6c9560c455 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Tue, 20 Feb 2024 19:37:40 -0500 Subject: [PATCH 13/14] caddytest: Rename adapt tests to `*.caddyfiletest` extension (#6119) --- .editorconfig | 2 +- ...allenges.txt => acme_server_custom_challenges.caddyfiletest} | 0 ...llenges.txt => acme_server_default_challenges.caddyfiletest} | 0 ...e_server_lifetime.txt => acme_server_lifetime.caddyfiletest} | 0 ...es.txt => acme_server_multi_custom_challenges.caddyfiletest} | 0 ...redirects.txt => auto_https_disable_redirects.caddyfiletest} | 0 ...d_certs.txt => auto_https_ignore_loaded_certs.caddyfiletest} | 0 .../{auto_https_off.txt => auto_https_off.caddyfiletest} | 0 .../caddyfile_adapt/{bind_ipv6.txt => bind_ipv6.caddyfiletest} | 0 ...all_site.txt => enable_tls_for_catch_all_site.caddyfiletest} | 0 .../{encode_options.txt => encode_options.caddyfiletest} | 0 .../{error_example.txt => error_example.caddyfiletest} | 0 ...ti_site_blocks.txt => error_multi_site_blocks.caddyfiletest} | 0 .../{error_range_codes.txt => error_range_codes.caddyfiletest} | 0 ..._simple_codes.txt => error_range_simple_codes.caddyfiletest} | 0 ...{error_simple_codes.txt => error_simple_codes.caddyfiletest} | 0 .../{error_sort.txt => error_sort.caddyfiletest} | 0 .../{expression_quotes.txt => expression_quotes.caddyfiletest} | 0 ...ris.txt => file_server_disable_canonical_uris.caddyfiletest} | 0 ...server_pass_thru.txt => file_server_pass_thru.caddyfiletest} | 0 ...recompressed.txt => file_server_precompressed.caddyfiletest} | 0 ...{file_server_status.txt => file_server_status.caddyfiletest} | 0 ...rd_auth_authelia.txt => forward_auth_authelia.caddyfiletest} | 0 ...me_headers.txt => forward_auth_rename_headers.caddyfiletest} | 0 .../{global_options.txt => global_options.caddyfiletest} | 0 ...lobal_options_acme.txt => global_options_acme.caddyfiletest} | 0 ...bal_options_admin.txt => global_options_admin.caddyfiletest} | 0 ... global_options_admin_with_persist_config_off.caddyfiletest} | 0 ...g.txt => global_options_debug_with_access_log.caddyfiletest} | 0 ...fault_bind.txt => global_options_default_bind.caddyfiletest} | 0 ...g_and_site.txt => global_options_log_and_site.caddyfiletest} | 0 ...ons_log_basic.txt => global_options_log_basic.caddyfiletest} | 0 ...s_log_custom.txt => global_options_log_custom.caddyfiletest} | 0 ...ons_log_multi.txt => global_options_log_multi.caddyfiletest} | 0 ...t_config.txt => global_options_persist_config.caddyfiletest} | 0 ...chains.txt => global_options_preferred_chains.caddyfiletest} | 0 ...rust.txt => global_options_skip_install_trust.caddyfiletest} | 0 ...ions_multi.txt => global_server_options_multi.caddyfiletest} | 0 ...ns_single.txt => global_server_options_single.caddyfiletest} | 0 ...nested_in_route.txt => handle_nested_in_route.caddyfiletest} | 0 .../{handle_path.txt => handle_path.caddyfiletest} | 0 ...andle_path_sorting.txt => handle_path_sorting.caddyfiletest} | 0 .../caddyfile_adapt/{header.txt => header.caddyfiletest} | 0 .../caddyfile_adapt/{heredoc.txt => heredoc.caddyfiletest} | 0 ...ttp_only_hostnames.txt => http_only_hostnames.caddyfiletest} | 0 ...n_any_address.txt => http_only_on_any_address.caddyfiletest} | 0 ...ttp_only_on_domain.txt => http_only_on_domain.caddyfiletest} | 0 ...less_block.txt => http_only_on_hostless_block.caddyfiletest} | 0 ...ly_on_localhost.txt => http_only_on_localhost.caddyfiletest} | 0 ...rd_port.txt => http_only_on_non_standard_port.caddyfiletest} | 0 ...txt => http_valid_directive_like_site_address.caddyfiletest} | 0 .../{https_on_domain.txt => https_on_domain.caddyfiletest} | 0 .../{import_args_file.txt => import_args_file.caddyfiletest} | 0 ...mport_args_snippet.txt => import_args_snippet.caddyfiletest} | 0 ...er.txt => import_args_snippet_env_placeholder.caddyfiletest} | 0 ...nvoke_named_routes.txt => invoke_named_routes.caddyfiletest} | 0 ...hall_blocks.txt => log_except_catchall_blocks.caddyfiletest} | 0 ...{log_filter_no_wrap.txt => log_filter_no_wrap.caddyfiletest} | 0 .../{log_filters.txt => log_filters.caddyfiletest} | 0 ...verride_hostname.txt => log_override_hostname.caddyfiletest} | 0 ...tiaccess.txt => log_override_name_multiaccess.caddyfiletest} | 0 ...ug.txt => log_override_name_multiaccess_debug.caddyfiletest} | 0 .../{log_roll_days.txt => log_roll_days.caddyfiletest} | 0 .../{log_skip_hosts.txt => log_skip_hosts.caddyfiletest} | 0 ..._raw_types.txt => map_and_vars_with_raw_types.caddyfiletest} | 0 .../{matcher_syntax.txt => matcher_syntax.caddyfiletest} | 0 .../{matchers_in_route.txt => matchers_in_route.caddyfiletest} | 0 .../{method_directive.txt => method_directive.caddyfiletest} | 0 ...{metrics_disable_om.txt => metrics_disable_om.caddyfiletest} | 0 .../{metrics_syntax.txt => metrics_syntax.caddyfiletest} | 0 .../{not_block_merging.txt => not_block_merging.caddyfiletest} | 0 ...xpanded_form.txt => php_fastcgi_expanded_form.caddyfiletest} | 0 ...e_response.txt => php_fastcgi_handle_response.caddyfiletest} | 0 ...astcgi_index_off.txt => php_fastcgi_index_off.caddyfiletest} | 0 ...hp_fastcgi_matcher.txt => php_fastcgi_matcher.caddyfiletest} | 0 ...ubdirectives.txt => php_fastcgi_subdirectives.caddyfiletest} | 0 ...verride.txt => php_fastcgi_try_files_override.caddyfiletest} | 0 .../{portless_upstream.txt => portless_upstream.caddyfiletest} | 0 .../caddyfile_adapt/{push.txt => push.caddyfiletest} | 0 ...laceable_upstream.txt => replaceable_upstream.caddyfiletest} | 0 ...port.txt => replaceable_upstream_partial_port.caddyfiletest} | 0 ...pstream_port.txt => replaceable_upstream_port.caddyfiletest} | 0 .../{request_body.txt => request_body.caddyfiletest} | 0 .../{request_header.txt => request_header.caddyfiletest} | 0 ...se_proxy_buffers.txt => reverse_proxy_buffers.caddyfiletest} | 0 ...treams.txt => reverse_proxy_dynamic_upstreams.caddyfiletest} | 0 ...txt => reverse_proxy_empty_non_http_transport.caddyfiletest} | 0 ..._shorthand.txt => reverse_proxy_h2c_shorthand.caddyfiletest} | 0 ...response.txt => reverse_proxy_handle_response.caddyfiletest} | 0 ...h_headers.txt => reverse_proxy_health_headers.caddyfiletest} | 0 ..._query.txt => reverse_proxy_health_path_query.caddyfiletest} | 0 ...oad_balance.txt => reverse_proxy_load_balance.caddyfiletest} | 0 ...nce_wrr.txt => reverse_proxy_load_balance_wrr.caddyfiletest} | 0 ...se_proxy_options.txt => reverse_proxy_options.caddyfiletest} | 0 ...xy_port_range.txt => reverse_proxy_port_range.caddyfiletest} | 0 ..._proxies.txt => reverse_proxy_trusted_proxies.caddyfiletest} | 0 ...der.txt => reverse_proxy_upstream_placeholder.caddyfiletest} | 0 ...tations.txt => rewrite_directive_permutations.caddyfiletest} | 0 ...rmutations.txt => root_directive_permutations.caddyfiletest} | 0 .../{server_names.txt => server_names.caddyfiletest} | 0 ...s.txt => shorthand_parameterized_placeholders.caddyfiletest} | 0 ...{site_block_sorting.txt => site_block_sorting.caddyfiletest} | 0 ...txt => sort_directives_with_any_matcher_first.caddyfiletest} | 0 ...n_handle.txt => sort_directives_within_handle.caddyfiletest} | 0 ...t_vars_in_reverse.txt => sort_vars_in_reverse.caddyfiletest} | 0 ...erred_chains.txt => tls_acme_preferred_chains.caddyfiletest} | 0 ...n_policies_1.txt => tls_automation_policies_1.caddyfiletest} | 0 ...policies_10.txt => tls_automation_policies_10.caddyfiletest} | 0 ...policies_11.txt => tls_automation_policies_11.caddyfiletest} | 0 ...n_policies_2.txt => tls_automation_policies_2.caddyfiletest} | 0 ...n_policies_3.txt => tls_automation_policies_3.caddyfiletest} | 0 ...n_policies_4.txt => tls_automation_policies_4.caddyfiletest} | 0 ...n_policies_5.txt => tls_automation_policies_5.caddyfiletest} | 0 ...n_policies_6.txt => tls_automation_policies_6.caddyfiletest} | 0 ...n_policies_7.txt => tls_automation_policies_7.caddyfiletest} | 0 ...n_policies_8.txt => tls_automation_policies_8.caddyfiletest} | 0 ...n_policies_9.txt => tls_automation_policies_9.caddyfiletest} | 0 ...ls_automation_policies_global_email_localhost.caddyfiletest} | 0 ...egacy.txt => tls_client_auth_cert_file-legacy.caddyfiletest} | 0 ...th_cert_file.txt => tls_client_auth_cert_file.caddyfiletest} | 0 ...acy.txt => tls_client_auth_inline_cert-legacy.caddyfiletest} | 0 ...nline_cert.txt => tls_client_auth_inline_cert.caddyfiletest} | 0 ...> tls_client_auth_inline_cert_with_leaf_trust.caddyfiletest} | 0 ...onsolidate.txt => tls_conn_policy_consolidate.caddyfiletest} | 0 .../{tls_dns_ttl.txt => tls_dns_ttl.caddyfiletest} | 0 ...er_dns_ttl.txt => tls_explicit_issuer_dns_ttl.caddyfiletest} | 0 ...xt => tls_explicit_issuer_propagation_options.caddyfiletest} | 0 ..._internal_options.txt => tls_internal_options.caddyfiletest} | 0 ...gation_options.txt => tls_propagation_options.caddyfiletest} | 0 .../caddyfile_adapt/{tracing.txt => tracing.caddyfiletest} | 0 ..._brace_escape.txt => uri_replace_brace_escape.caddyfiletest} | 0 131 files changed, 1 insertion(+), 1 deletion(-) rename caddytest/integration/caddyfile_adapt/{acme_server_custom_challenges.txt => acme_server_custom_challenges.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{acme_server_default_challenges.txt => acme_server_default_challenges.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{acme_server_lifetime.txt => acme_server_lifetime.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{acme_server_multi_custom_challenges.txt => acme_server_multi_custom_challenges.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{auto_https_disable_redirects.txt => auto_https_disable_redirects.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{auto_https_ignore_loaded_certs.txt => auto_https_ignore_loaded_certs.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{auto_https_off.txt => auto_https_off.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{bind_ipv6.txt => bind_ipv6.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{enable_tls_for_catch_all_site.txt => enable_tls_for_catch_all_site.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{encode_options.txt => encode_options.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{error_example.txt => error_example.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{error_multi_site_blocks.txt => error_multi_site_blocks.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{error_range_codes.txt => error_range_codes.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{error_range_simple_codes.txt => error_range_simple_codes.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{error_simple_codes.txt => error_simple_codes.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{error_sort.txt => error_sort.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{expression_quotes.txt => expression_quotes.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{file_server_disable_canonical_uris.txt => file_server_disable_canonical_uris.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{file_server_pass_thru.txt => file_server_pass_thru.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{file_server_precompressed.txt => file_server_precompressed.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{file_server_status.txt => file_server_status.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{forward_auth_authelia.txt => forward_auth_authelia.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{forward_auth_rename_headers.txt => forward_auth_rename_headers.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options.txt => global_options.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_acme.txt => global_options_acme.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_admin.txt => global_options_admin.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_admin_with_persist_config_off.txt => global_options_admin_with_persist_config_off.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_debug_with_access_log.txt => global_options_debug_with_access_log.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_default_bind.txt => global_options_default_bind.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_log_and_site.txt => global_options_log_and_site.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_log_basic.txt => global_options_log_basic.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_log_custom.txt => global_options_log_custom.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_log_multi.txt => global_options_log_multi.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_persist_config.txt => global_options_persist_config.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_preferred_chains.txt => global_options_preferred_chains.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_options_skip_install_trust.txt => global_options_skip_install_trust.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_server_options_multi.txt => global_server_options_multi.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{global_server_options_single.txt => global_server_options_single.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{handle_nested_in_route.txt => handle_nested_in_route.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{handle_path.txt => handle_path.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{handle_path_sorting.txt => handle_path_sorting.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{header.txt => header.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{heredoc.txt => heredoc.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{http_only_hostnames.txt => http_only_hostnames.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{http_only_on_any_address.txt => http_only_on_any_address.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{http_only_on_domain.txt => http_only_on_domain.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{http_only_on_hostless_block.txt => http_only_on_hostless_block.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{http_only_on_localhost.txt => http_only_on_localhost.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{http_only_on_non_standard_port.txt => http_only_on_non_standard_port.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{http_valid_directive_like_site_address.txt => http_valid_directive_like_site_address.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{https_on_domain.txt => https_on_domain.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{import_args_file.txt => import_args_file.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{import_args_snippet.txt => import_args_snippet.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{import_args_snippet_env_placeholder.txt => import_args_snippet_env_placeholder.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{invoke_named_routes.txt => invoke_named_routes.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{log_except_catchall_blocks.txt => log_except_catchall_blocks.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{log_filter_no_wrap.txt => log_filter_no_wrap.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{log_filters.txt => log_filters.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{log_override_hostname.txt => log_override_hostname.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{log_override_name_multiaccess.txt => log_override_name_multiaccess.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{log_override_name_multiaccess_debug.txt => log_override_name_multiaccess_debug.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{log_roll_days.txt => log_roll_days.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{log_skip_hosts.txt => log_skip_hosts.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{map_and_vars_with_raw_types.txt => map_and_vars_with_raw_types.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{matcher_syntax.txt => matcher_syntax.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{matchers_in_route.txt => matchers_in_route.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{method_directive.txt => method_directive.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{metrics_disable_om.txt => metrics_disable_om.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{metrics_syntax.txt => metrics_syntax.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{not_block_merging.txt => not_block_merging.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{php_fastcgi_expanded_form.txt => php_fastcgi_expanded_form.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{php_fastcgi_handle_response.txt => php_fastcgi_handle_response.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{php_fastcgi_index_off.txt => php_fastcgi_index_off.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{php_fastcgi_matcher.txt => php_fastcgi_matcher.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{php_fastcgi_subdirectives.txt => php_fastcgi_subdirectives.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{php_fastcgi_try_files_override.txt => php_fastcgi_try_files_override.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{portless_upstream.txt => portless_upstream.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{push.txt => push.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{replaceable_upstream.txt => replaceable_upstream.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{replaceable_upstream_partial_port.txt => replaceable_upstream_partial_port.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{replaceable_upstream_port.txt => replaceable_upstream_port.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{request_body.txt => request_body.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{request_header.txt => request_header.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_buffers.txt => reverse_proxy_buffers.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_dynamic_upstreams.txt => reverse_proxy_dynamic_upstreams.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_empty_non_http_transport.txt => reverse_proxy_empty_non_http_transport.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_h2c_shorthand.txt => reverse_proxy_h2c_shorthand.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_handle_response.txt => reverse_proxy_handle_response.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_health_headers.txt => reverse_proxy_health_headers.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_health_path_query.txt => reverse_proxy_health_path_query.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_load_balance.txt => reverse_proxy_load_balance.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_load_balance_wrr.txt => reverse_proxy_load_balance_wrr.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_options.txt => reverse_proxy_options.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_port_range.txt => reverse_proxy_port_range.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_trusted_proxies.txt => reverse_proxy_trusted_proxies.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{reverse_proxy_upstream_placeholder.txt => reverse_proxy_upstream_placeholder.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{rewrite_directive_permutations.txt => rewrite_directive_permutations.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{root_directive_permutations.txt => root_directive_permutations.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{server_names.txt => server_names.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{shorthand_parameterized_placeholders.txt => shorthand_parameterized_placeholders.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{site_block_sorting.txt => site_block_sorting.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{sort_directives_with_any_matcher_first.txt => sort_directives_with_any_matcher_first.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{sort_directives_within_handle.txt => sort_directives_within_handle.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{sort_vars_in_reverse.txt => sort_vars_in_reverse.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_acme_preferred_chains.txt => tls_acme_preferred_chains.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_1.txt => tls_automation_policies_1.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_10.txt => tls_automation_policies_10.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_11.txt => tls_automation_policies_11.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_2.txt => tls_automation_policies_2.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_3.txt => tls_automation_policies_3.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_4.txt => tls_automation_policies_4.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_5.txt => tls_automation_policies_5.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_6.txt => tls_automation_policies_6.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_7.txt => tls_automation_policies_7.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_8.txt => tls_automation_policies_8.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_9.txt => tls_automation_policies_9.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_automation_policies_global_email_localhost.txt => tls_automation_policies_global_email_localhost.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_client_auth_cert_file-legacy.txt => tls_client_auth_cert_file-legacy.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_client_auth_cert_file.txt => tls_client_auth_cert_file.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_client_auth_inline_cert-legacy.txt => tls_client_auth_inline_cert-legacy.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_client_auth_inline_cert.txt => tls_client_auth_inline_cert.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_client_auth_inline_cert_with_leaf_trust.txt => tls_client_auth_inline_cert_with_leaf_trust.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_conn_policy_consolidate.txt => tls_conn_policy_consolidate.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_dns_ttl.txt => tls_dns_ttl.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_explicit_issuer_dns_ttl.txt => tls_explicit_issuer_dns_ttl.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_explicit_issuer_propagation_options.txt => tls_explicit_issuer_propagation_options.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_internal_options.txt => tls_internal_options.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tls_propagation_options.txt => tls_propagation_options.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{tracing.txt => tracing.caddyfiletest} (100%) rename caddytest/integration/caddyfile_adapt/{uri_replace_brace_escape.txt => uri_replace_brace_escape.caddyfiletest} (100%) diff --git a/.editorconfig b/.editorconfig index 7134bf7e..96948b9d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,5 @@ [*] end_of_line = lf -[caddytest/integration/caddyfile_adapt/*.txt] +[caddytest/integration/caddyfile_adapt/*.caddyfiletest] indent_style = tab \ No newline at end of file diff --git a/caddytest/integration/caddyfile_adapt/acme_server_custom_challenges.txt b/caddytest/integration/caddyfile_adapt/acme_server_custom_challenges.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/acme_server_custom_challenges.txt rename to caddytest/integration/caddyfile_adapt/acme_server_custom_challenges.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/acme_server_default_challenges.txt b/caddytest/integration/caddyfile_adapt/acme_server_default_challenges.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/acme_server_default_challenges.txt rename to caddytest/integration/caddyfile_adapt/acme_server_default_challenges.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/acme_server_lifetime.txt b/caddytest/integration/caddyfile_adapt/acme_server_lifetime.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/acme_server_lifetime.txt rename to caddytest/integration/caddyfile_adapt/acme_server_lifetime.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/acme_server_multi_custom_challenges.txt b/caddytest/integration/caddyfile_adapt/acme_server_multi_custom_challenges.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/acme_server_multi_custom_challenges.txt rename to caddytest/integration/caddyfile_adapt/acme_server_multi_custom_challenges.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/auto_https_disable_redirects.txt b/caddytest/integration/caddyfile_adapt/auto_https_disable_redirects.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/auto_https_disable_redirects.txt rename to caddytest/integration/caddyfile_adapt/auto_https_disable_redirects.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/auto_https_ignore_loaded_certs.txt b/caddytest/integration/caddyfile_adapt/auto_https_ignore_loaded_certs.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/auto_https_ignore_loaded_certs.txt rename to caddytest/integration/caddyfile_adapt/auto_https_ignore_loaded_certs.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/auto_https_off.txt b/caddytest/integration/caddyfile_adapt/auto_https_off.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/auto_https_off.txt rename to caddytest/integration/caddyfile_adapt/auto_https_off.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/bind_ipv6.txt b/caddytest/integration/caddyfile_adapt/bind_ipv6.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/bind_ipv6.txt rename to caddytest/integration/caddyfile_adapt/bind_ipv6.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/enable_tls_for_catch_all_site.txt b/caddytest/integration/caddyfile_adapt/enable_tls_for_catch_all_site.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/enable_tls_for_catch_all_site.txt rename to caddytest/integration/caddyfile_adapt/enable_tls_for_catch_all_site.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/encode_options.txt b/caddytest/integration/caddyfile_adapt/encode_options.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/encode_options.txt rename to caddytest/integration/caddyfile_adapt/encode_options.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/error_example.txt b/caddytest/integration/caddyfile_adapt/error_example.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/error_example.txt rename to caddytest/integration/caddyfile_adapt/error_example.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/error_multi_site_blocks.txt b/caddytest/integration/caddyfile_adapt/error_multi_site_blocks.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/error_multi_site_blocks.txt rename to caddytest/integration/caddyfile_adapt/error_multi_site_blocks.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/error_range_codes.txt b/caddytest/integration/caddyfile_adapt/error_range_codes.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/error_range_codes.txt rename to caddytest/integration/caddyfile_adapt/error_range_codes.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/error_range_simple_codes.txt b/caddytest/integration/caddyfile_adapt/error_range_simple_codes.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/error_range_simple_codes.txt rename to caddytest/integration/caddyfile_adapt/error_range_simple_codes.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/error_simple_codes.txt b/caddytest/integration/caddyfile_adapt/error_simple_codes.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/error_simple_codes.txt rename to caddytest/integration/caddyfile_adapt/error_simple_codes.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/error_sort.txt b/caddytest/integration/caddyfile_adapt/error_sort.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/error_sort.txt rename to caddytest/integration/caddyfile_adapt/error_sort.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/expression_quotes.txt b/caddytest/integration/caddyfile_adapt/expression_quotes.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/expression_quotes.txt rename to caddytest/integration/caddyfile_adapt/expression_quotes.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/file_server_disable_canonical_uris.txt b/caddytest/integration/caddyfile_adapt/file_server_disable_canonical_uris.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/file_server_disable_canonical_uris.txt rename to caddytest/integration/caddyfile_adapt/file_server_disable_canonical_uris.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/file_server_pass_thru.txt b/caddytest/integration/caddyfile_adapt/file_server_pass_thru.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/file_server_pass_thru.txt rename to caddytest/integration/caddyfile_adapt/file_server_pass_thru.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/file_server_precompressed.txt b/caddytest/integration/caddyfile_adapt/file_server_precompressed.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/file_server_precompressed.txt rename to caddytest/integration/caddyfile_adapt/file_server_precompressed.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/file_server_status.txt b/caddytest/integration/caddyfile_adapt/file_server_status.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/file_server_status.txt rename to caddytest/integration/caddyfile_adapt/file_server_status.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/forward_auth_authelia.txt b/caddytest/integration/caddyfile_adapt/forward_auth_authelia.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/forward_auth_authelia.txt rename to caddytest/integration/caddyfile_adapt/forward_auth_authelia.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/forward_auth_rename_headers.txt b/caddytest/integration/caddyfile_adapt/forward_auth_rename_headers.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/forward_auth_rename_headers.txt rename to caddytest/integration/caddyfile_adapt/forward_auth_rename_headers.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options.txt b/caddytest/integration/caddyfile_adapt/global_options.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options.txt rename to caddytest/integration/caddyfile_adapt/global_options.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_acme.txt b/caddytest/integration/caddyfile_adapt/global_options_acme.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_acme.txt rename to caddytest/integration/caddyfile_adapt/global_options_acme.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_admin.txt b/caddytest/integration/caddyfile_adapt/global_options_admin.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_admin.txt rename to caddytest/integration/caddyfile_adapt/global_options_admin.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_admin_with_persist_config_off.txt b/caddytest/integration/caddyfile_adapt/global_options_admin_with_persist_config_off.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_admin_with_persist_config_off.txt rename to caddytest/integration/caddyfile_adapt/global_options_admin_with_persist_config_off.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_debug_with_access_log.txt b/caddytest/integration/caddyfile_adapt/global_options_debug_with_access_log.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_debug_with_access_log.txt rename to caddytest/integration/caddyfile_adapt/global_options_debug_with_access_log.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_default_bind.txt b/caddytest/integration/caddyfile_adapt/global_options_default_bind.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_default_bind.txt rename to caddytest/integration/caddyfile_adapt/global_options_default_bind.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_log_and_site.txt b/caddytest/integration/caddyfile_adapt/global_options_log_and_site.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_log_and_site.txt rename to caddytest/integration/caddyfile_adapt/global_options_log_and_site.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_log_basic.txt b/caddytest/integration/caddyfile_adapt/global_options_log_basic.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_log_basic.txt rename to caddytest/integration/caddyfile_adapt/global_options_log_basic.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_log_custom.txt b/caddytest/integration/caddyfile_adapt/global_options_log_custom.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_log_custom.txt rename to caddytest/integration/caddyfile_adapt/global_options_log_custom.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_log_multi.txt b/caddytest/integration/caddyfile_adapt/global_options_log_multi.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_log_multi.txt rename to caddytest/integration/caddyfile_adapt/global_options_log_multi.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_persist_config.txt b/caddytest/integration/caddyfile_adapt/global_options_persist_config.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_persist_config.txt rename to caddytest/integration/caddyfile_adapt/global_options_persist_config.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_preferred_chains.txt b/caddytest/integration/caddyfile_adapt/global_options_preferred_chains.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_preferred_chains.txt rename to caddytest/integration/caddyfile_adapt/global_options_preferred_chains.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_options_skip_install_trust.txt b/caddytest/integration/caddyfile_adapt/global_options_skip_install_trust.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_options_skip_install_trust.txt rename to caddytest/integration/caddyfile_adapt/global_options_skip_install_trust.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_server_options_multi.txt b/caddytest/integration/caddyfile_adapt/global_server_options_multi.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_server_options_multi.txt rename to caddytest/integration/caddyfile_adapt/global_server_options_multi.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/global_server_options_single.txt b/caddytest/integration/caddyfile_adapt/global_server_options_single.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/global_server_options_single.txt rename to caddytest/integration/caddyfile_adapt/global_server_options_single.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/handle_nested_in_route.txt b/caddytest/integration/caddyfile_adapt/handle_nested_in_route.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/handle_nested_in_route.txt rename to caddytest/integration/caddyfile_adapt/handle_nested_in_route.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/handle_path.txt b/caddytest/integration/caddyfile_adapt/handle_path.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/handle_path.txt rename to caddytest/integration/caddyfile_adapt/handle_path.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/handle_path_sorting.txt b/caddytest/integration/caddyfile_adapt/handle_path_sorting.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/handle_path_sorting.txt rename to caddytest/integration/caddyfile_adapt/handle_path_sorting.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/header.txt b/caddytest/integration/caddyfile_adapt/header.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/header.txt rename to caddytest/integration/caddyfile_adapt/header.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/heredoc.txt b/caddytest/integration/caddyfile_adapt/heredoc.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/heredoc.txt rename to caddytest/integration/caddyfile_adapt/heredoc.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/http_only_hostnames.txt b/caddytest/integration/caddyfile_adapt/http_only_hostnames.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/http_only_hostnames.txt rename to caddytest/integration/caddyfile_adapt/http_only_hostnames.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/http_only_on_any_address.txt b/caddytest/integration/caddyfile_adapt/http_only_on_any_address.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/http_only_on_any_address.txt rename to caddytest/integration/caddyfile_adapt/http_only_on_any_address.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/http_only_on_domain.txt b/caddytest/integration/caddyfile_adapt/http_only_on_domain.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/http_only_on_domain.txt rename to caddytest/integration/caddyfile_adapt/http_only_on_domain.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/http_only_on_hostless_block.txt b/caddytest/integration/caddyfile_adapt/http_only_on_hostless_block.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/http_only_on_hostless_block.txt rename to caddytest/integration/caddyfile_adapt/http_only_on_hostless_block.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/http_only_on_localhost.txt b/caddytest/integration/caddyfile_adapt/http_only_on_localhost.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/http_only_on_localhost.txt rename to caddytest/integration/caddyfile_adapt/http_only_on_localhost.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/http_only_on_non_standard_port.txt b/caddytest/integration/caddyfile_adapt/http_only_on_non_standard_port.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/http_only_on_non_standard_port.txt rename to caddytest/integration/caddyfile_adapt/http_only_on_non_standard_port.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/http_valid_directive_like_site_address.txt b/caddytest/integration/caddyfile_adapt/http_valid_directive_like_site_address.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/http_valid_directive_like_site_address.txt rename to caddytest/integration/caddyfile_adapt/http_valid_directive_like_site_address.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/https_on_domain.txt b/caddytest/integration/caddyfile_adapt/https_on_domain.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/https_on_domain.txt rename to caddytest/integration/caddyfile_adapt/https_on_domain.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/import_args_file.txt b/caddytest/integration/caddyfile_adapt/import_args_file.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/import_args_file.txt rename to caddytest/integration/caddyfile_adapt/import_args_file.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/import_args_snippet.txt b/caddytest/integration/caddyfile_adapt/import_args_snippet.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/import_args_snippet.txt rename to caddytest/integration/caddyfile_adapt/import_args_snippet.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/import_args_snippet_env_placeholder.txt b/caddytest/integration/caddyfile_adapt/import_args_snippet_env_placeholder.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/import_args_snippet_env_placeholder.txt rename to caddytest/integration/caddyfile_adapt/import_args_snippet_env_placeholder.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/invoke_named_routes.txt b/caddytest/integration/caddyfile_adapt/invoke_named_routes.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/invoke_named_routes.txt rename to caddytest/integration/caddyfile_adapt/invoke_named_routes.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/log_except_catchall_blocks.txt b/caddytest/integration/caddyfile_adapt/log_except_catchall_blocks.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/log_except_catchall_blocks.txt rename to caddytest/integration/caddyfile_adapt/log_except_catchall_blocks.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/log_filter_no_wrap.txt b/caddytest/integration/caddyfile_adapt/log_filter_no_wrap.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/log_filter_no_wrap.txt rename to caddytest/integration/caddyfile_adapt/log_filter_no_wrap.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/log_filters.txt b/caddytest/integration/caddyfile_adapt/log_filters.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/log_filters.txt rename to caddytest/integration/caddyfile_adapt/log_filters.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/log_override_hostname.txt b/caddytest/integration/caddyfile_adapt/log_override_hostname.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/log_override_hostname.txt rename to caddytest/integration/caddyfile_adapt/log_override_hostname.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/log_override_name_multiaccess.txt b/caddytest/integration/caddyfile_adapt/log_override_name_multiaccess.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/log_override_name_multiaccess.txt rename to caddytest/integration/caddyfile_adapt/log_override_name_multiaccess.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/log_override_name_multiaccess_debug.txt b/caddytest/integration/caddyfile_adapt/log_override_name_multiaccess_debug.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/log_override_name_multiaccess_debug.txt rename to caddytest/integration/caddyfile_adapt/log_override_name_multiaccess_debug.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/log_roll_days.txt b/caddytest/integration/caddyfile_adapt/log_roll_days.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/log_roll_days.txt rename to caddytest/integration/caddyfile_adapt/log_roll_days.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/log_skip_hosts.txt b/caddytest/integration/caddyfile_adapt/log_skip_hosts.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/log_skip_hosts.txt rename to caddytest/integration/caddyfile_adapt/log_skip_hosts.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt b/caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt rename to caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/matcher_syntax.txt b/caddytest/integration/caddyfile_adapt/matcher_syntax.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/matcher_syntax.txt rename to caddytest/integration/caddyfile_adapt/matcher_syntax.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/matchers_in_route.txt b/caddytest/integration/caddyfile_adapt/matchers_in_route.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/matchers_in_route.txt rename to caddytest/integration/caddyfile_adapt/matchers_in_route.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/method_directive.txt b/caddytest/integration/caddyfile_adapt/method_directive.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/method_directive.txt rename to caddytest/integration/caddyfile_adapt/method_directive.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/metrics_disable_om.txt b/caddytest/integration/caddyfile_adapt/metrics_disable_om.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/metrics_disable_om.txt rename to caddytest/integration/caddyfile_adapt/metrics_disable_om.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/metrics_syntax.txt b/caddytest/integration/caddyfile_adapt/metrics_syntax.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/metrics_syntax.txt rename to caddytest/integration/caddyfile_adapt/metrics_syntax.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/not_block_merging.txt b/caddytest/integration/caddyfile_adapt/not_block_merging.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/not_block_merging.txt rename to caddytest/integration/caddyfile_adapt/not_block_merging.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/php_fastcgi_expanded_form.txt b/caddytest/integration/caddyfile_adapt/php_fastcgi_expanded_form.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/php_fastcgi_expanded_form.txt rename to caddytest/integration/caddyfile_adapt/php_fastcgi_expanded_form.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/php_fastcgi_handle_response.txt b/caddytest/integration/caddyfile_adapt/php_fastcgi_handle_response.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/php_fastcgi_handle_response.txt rename to caddytest/integration/caddyfile_adapt/php_fastcgi_handle_response.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/php_fastcgi_index_off.txt b/caddytest/integration/caddyfile_adapt/php_fastcgi_index_off.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/php_fastcgi_index_off.txt rename to caddytest/integration/caddyfile_adapt/php_fastcgi_index_off.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/php_fastcgi_matcher.txt b/caddytest/integration/caddyfile_adapt/php_fastcgi_matcher.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/php_fastcgi_matcher.txt rename to caddytest/integration/caddyfile_adapt/php_fastcgi_matcher.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/php_fastcgi_subdirectives.txt b/caddytest/integration/caddyfile_adapt/php_fastcgi_subdirectives.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/php_fastcgi_subdirectives.txt rename to caddytest/integration/caddyfile_adapt/php_fastcgi_subdirectives.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/php_fastcgi_try_files_override.txt b/caddytest/integration/caddyfile_adapt/php_fastcgi_try_files_override.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/php_fastcgi_try_files_override.txt rename to caddytest/integration/caddyfile_adapt/php_fastcgi_try_files_override.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/portless_upstream.txt b/caddytest/integration/caddyfile_adapt/portless_upstream.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/portless_upstream.txt rename to caddytest/integration/caddyfile_adapt/portless_upstream.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/push.txt b/caddytest/integration/caddyfile_adapt/push.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/push.txt rename to caddytest/integration/caddyfile_adapt/push.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/replaceable_upstream.txt b/caddytest/integration/caddyfile_adapt/replaceable_upstream.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/replaceable_upstream.txt rename to caddytest/integration/caddyfile_adapt/replaceable_upstream.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/replaceable_upstream_partial_port.txt b/caddytest/integration/caddyfile_adapt/replaceable_upstream_partial_port.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/replaceable_upstream_partial_port.txt rename to caddytest/integration/caddyfile_adapt/replaceable_upstream_partial_port.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/replaceable_upstream_port.txt b/caddytest/integration/caddyfile_adapt/replaceable_upstream_port.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/replaceable_upstream_port.txt rename to caddytest/integration/caddyfile_adapt/replaceable_upstream_port.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/request_body.txt b/caddytest/integration/caddyfile_adapt/request_body.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/request_body.txt rename to caddytest/integration/caddyfile_adapt/request_body.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/request_header.txt b/caddytest/integration/caddyfile_adapt/request_header.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/request_header.txt rename to caddytest/integration/caddyfile_adapt/request_header.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_buffers.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_buffers.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_buffers.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_buffers.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_dynamic_upstreams.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_dynamic_upstreams.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_dynamic_upstreams.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_dynamic_upstreams.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_empty_non_http_transport.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_empty_non_http_transport.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_empty_non_http_transport.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_empty_non_http_transport.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_h2c_shorthand.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_h2c_shorthand.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_h2c_shorthand.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_h2c_shorthand.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_handle_response.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_handle_response.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_handle_response.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_handle_response.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_health_headers.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_health_headers.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_health_headers.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_health_headers.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_health_path_query.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_health_path_query.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_health_path_query.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_health_path_query.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance_wrr.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance_wrr.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance_wrr.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_load_balance_wrr.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_options.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_options.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_options.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_options.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_port_range.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_port_range.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_port_range.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_port_range.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_trusted_proxies.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_trusted_proxies.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_trusted_proxies.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_trusted_proxies.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_upstream_placeholder.txt b/caddytest/integration/caddyfile_adapt/reverse_proxy_upstream_placeholder.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/reverse_proxy_upstream_placeholder.txt rename to caddytest/integration/caddyfile_adapt/reverse_proxy_upstream_placeholder.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/rewrite_directive_permutations.txt b/caddytest/integration/caddyfile_adapt/rewrite_directive_permutations.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/rewrite_directive_permutations.txt rename to caddytest/integration/caddyfile_adapt/rewrite_directive_permutations.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/root_directive_permutations.txt b/caddytest/integration/caddyfile_adapt/root_directive_permutations.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/root_directive_permutations.txt rename to caddytest/integration/caddyfile_adapt/root_directive_permutations.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/server_names.txt b/caddytest/integration/caddyfile_adapt/server_names.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/server_names.txt rename to caddytest/integration/caddyfile_adapt/server_names.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/shorthand_parameterized_placeholders.txt b/caddytest/integration/caddyfile_adapt/shorthand_parameterized_placeholders.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/shorthand_parameterized_placeholders.txt rename to caddytest/integration/caddyfile_adapt/shorthand_parameterized_placeholders.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/site_block_sorting.txt b/caddytest/integration/caddyfile_adapt/site_block_sorting.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/site_block_sorting.txt rename to caddytest/integration/caddyfile_adapt/site_block_sorting.caddyfiletest 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.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/sort_directives_with_any_matcher_first.txt rename to caddytest/integration/caddyfile_adapt/sort_directives_with_any_matcher_first.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/sort_directives_within_handle.txt b/caddytest/integration/caddyfile_adapt/sort_directives_within_handle.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/sort_directives_within_handle.txt rename to caddytest/integration/caddyfile_adapt/sort_directives_within_handle.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/sort_vars_in_reverse.txt b/caddytest/integration/caddyfile_adapt/sort_vars_in_reverse.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/sort_vars_in_reverse.txt rename to caddytest/integration/caddyfile_adapt/sort_vars_in_reverse.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_acme_preferred_chains.txt b/caddytest/integration/caddyfile_adapt/tls_acme_preferred_chains.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_acme_preferred_chains.txt rename to caddytest/integration/caddyfile_adapt/tls_acme_preferred_chains.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_1.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_1.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_1.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_1.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_10.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_10.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_10.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_10.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_11.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_11.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_11.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_11.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_2.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_2.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_2.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_2.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_3.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_3.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_3.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_3.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_4.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_4.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_4.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_4.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_5.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_5.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_5.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_5.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_6.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_6.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_6.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_6.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_7.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_7.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_7.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_7.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_8.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_8.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_8.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_8.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_9.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_9.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_9.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_9.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_automation_policies_global_email_localhost.txt b/caddytest/integration/caddyfile_adapt/tls_automation_policies_global_email_localhost.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_automation_policies_global_email_localhost.txt rename to caddytest/integration/caddyfile_adapt/tls_automation_policies_global_email_localhost.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_client_auth_cert_file-legacy.txt b/caddytest/integration/caddyfile_adapt/tls_client_auth_cert_file-legacy.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_client_auth_cert_file-legacy.txt rename to caddytest/integration/caddyfile_adapt/tls_client_auth_cert_file-legacy.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_client_auth_cert_file.txt b/caddytest/integration/caddyfile_adapt/tls_client_auth_cert_file.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_client_auth_cert_file.txt rename to caddytest/integration/caddyfile_adapt/tls_client_auth_cert_file.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert-legacy.txt b/caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert-legacy.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert-legacy.txt rename to caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert-legacy.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert.txt b/caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert.txt rename to caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert_with_leaf_trust.txt b/caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert_with_leaf_trust.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert_with_leaf_trust.txt rename to caddytest/integration/caddyfile_adapt/tls_client_auth_inline_cert_with_leaf_trust.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_conn_policy_consolidate.txt b/caddytest/integration/caddyfile_adapt/tls_conn_policy_consolidate.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_conn_policy_consolidate.txt rename to caddytest/integration/caddyfile_adapt/tls_conn_policy_consolidate.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_dns_ttl.txt b/caddytest/integration/caddyfile_adapt/tls_dns_ttl.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_dns_ttl.txt rename to caddytest/integration/caddyfile_adapt/tls_dns_ttl.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_explicit_issuer_dns_ttl.txt b/caddytest/integration/caddyfile_adapt/tls_explicit_issuer_dns_ttl.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_explicit_issuer_dns_ttl.txt rename to caddytest/integration/caddyfile_adapt/tls_explicit_issuer_dns_ttl.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_explicit_issuer_propagation_options.txt b/caddytest/integration/caddyfile_adapt/tls_explicit_issuer_propagation_options.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_explicit_issuer_propagation_options.txt rename to caddytest/integration/caddyfile_adapt/tls_explicit_issuer_propagation_options.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_internal_options.txt b/caddytest/integration/caddyfile_adapt/tls_internal_options.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_internal_options.txt rename to caddytest/integration/caddyfile_adapt/tls_internal_options.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_propagation_options.txt b/caddytest/integration/caddyfile_adapt/tls_propagation_options.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tls_propagation_options.txt rename to caddytest/integration/caddyfile_adapt/tls_propagation_options.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tracing.txt b/caddytest/integration/caddyfile_adapt/tracing.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/tracing.txt rename to caddytest/integration/caddyfile_adapt/tracing.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/uri_replace_brace_escape.txt b/caddytest/integration/caddyfile_adapt/uri_replace_brace_escape.caddyfiletest similarity index 100% rename from caddytest/integration/caddyfile_adapt/uri_replace_brace_escape.txt rename to caddytest/integration/caddyfile_adapt/uri_replace_brace_escape.caddyfiletest From da6a569e859f4dfbbebfd084060e15d940de8861 Mon Sep 17 00:00:00 2001 From: Sam Ottenhoff Date: Fri, 23 Feb 2024 14:45:58 -0500 Subject: [PATCH 14/14] reverseproxy: cookie should be Secure and SameSite=None when TLS (#6115) * reverseproxy: cookie should be Secure and SameSite=None when TLS * Update modules/caddyhttp/reverseproxy/selectionpolicies_test.go Co-authored-by: Mohammed Al Sahaf --------- Co-authored-by: Mohammed Al Sahaf --- .../reverseproxy/selectionpolicies.go | 14 ++++- .../reverseproxy/selectionpolicies_test.go | 54 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/modules/caddyhttp/reverseproxy/selectionpolicies.go b/modules/caddyhttp/reverseproxy/selectionpolicies.go index b56c8074..b6f807c1 100644 --- a/modules/caddyhttp/reverseproxy/selectionpolicies.go +++ b/modules/caddyhttp/reverseproxy/selectionpolicies.go @@ -655,12 +655,22 @@ func (s CookieHashSelection) Select(pool UpstreamPool, req *http.Request, w http if err != nil { return upstream } - http.SetCookie(w, &http.Cookie{ + cookie := &http.Cookie{ Name: s.Name, Value: sha, Path: "/", Secure: false, - }) + } + isProxyHttps := false + if trusted, ok := caddyhttp.GetVar(req.Context(), caddyhttp.TrustedProxyVarKey).(bool); ok && trusted { + xfp, xfpOk, _ := lastHeaderValue(req.Header, "X-Forwarded-Proto") + isProxyHttps = xfpOk && xfp == "https" + } + if req.TLS != nil || isProxyHttps { + cookie.Secure = true + cookie.SameSite = http.SameSiteNoneMode + } + http.SetCookie(w, cookie) return upstream } diff --git a/modules/caddyhttp/reverseproxy/selectionpolicies_test.go b/modules/caddyhttp/reverseproxy/selectionpolicies_test.go index 9199f619..d7e79626 100644 --- a/modules/caddyhttp/reverseproxy/selectionpolicies_test.go +++ b/modules/caddyhttp/reverseproxy/selectionpolicies_test.go @@ -658,6 +658,9 @@ func TestCookieHashPolicy(t *testing.T) { if cookieServer1.Name != "lb" { t.Error("cookieHashPolicy should set a cookie with name lb") } + if cookieServer1.Secure { + t.Error("cookieHashPolicy should set cookie Secure attribute to false when request is not secure") + } if h != pool[0] { t.Error("Expected cookieHashPolicy host to be the first only available host.") } @@ -687,6 +690,57 @@ func TestCookieHashPolicy(t *testing.T) { } } +func TestCookieHashPolicyWithSecureRequest(t *testing.T) { + ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()}) + defer cancel() + cookieHashPolicy := CookieHashSelection{} + if err := cookieHashPolicy.Provision(ctx); err != nil { + t.Errorf("Provision error: %v", err) + t.FailNow() + } + + pool := testPool() + pool[0].Dial = "localhost:8080" + pool[1].Dial = "localhost:8081" + pool[2].Dial = "localhost:8082" + pool[0].setHealthy(true) + pool[1].setHealthy(false) + pool[2].setHealthy(false) + + // Create a test server that serves HTTPS requests + ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + h := cookieHashPolicy.Select(pool, r, w) + if h != pool[0] { + t.Error("Expected cookieHashPolicy host to be the first only available host.") + } + })) + defer ts.Close() + + // Make a new HTTPS request to the test server + client := ts.Client() + request, err := http.NewRequest(http.MethodGet, ts.URL+"/test", nil) + if err != nil { + t.Fatal(err) + } + response, err := client.Do(request) + if err != nil { + t.Fatal(err) + } + + // Check if the cookie set is Secure and has SameSiteNone mode + cookies := response.Cookies() + if len(cookies) == 0 { + t.Fatal("Expected a cookie to be set") + } + cookie := cookies[0] + if !cookie.Secure { + t.Error("Expected cookie Secure attribute to be true when request is secure") + } + if cookie.SameSite != http.SameSiteNoneMode { + t.Error("Expected cookie SameSite attribute to be None when request is secure") + } +} + func TestCookieHashPolicyWithFirstFallback(t *testing.T) { ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()}) defer cancel()