mirror of
https://github.com/caddyserver/caddy.git
synced 2026-05-25 16:22:36 -04:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e7457b43e4 | |||
| f376a38b25 | |||
| 749e55c738 | |||
| 24fda7514d | |||
| 3385856966 | |||
| f73f55dba7 | |||
| 012d235314 | |||
| 997e41deae | |||
| 0ffb2229b0 | |||
| a21d5a001f | |||
| a2119c09e9 | |||
| 062657d0d8 | |||
| b092061591 | |||
| 64f8b557b1 | |||
| 95c035060f | |||
| c4790d7f9d | |||
| 837cdc566d | |||
| be5f77e84d | |||
| cbb045a121 | |||
| c48fadc4a7 | |||
| 059fc32f00 | |||
| e2d964ea30 | |||
| 501da21f20 | |||
| 3336faf254 | |||
| 16f752125f | |||
| 0a5f7a677f | |||
| d3a0259944 | |||
| 5fda9610f9 | |||
| 3f2c3ecf85 | |||
| 907e2d8d3a | |||
| 33c70f418f | |||
| 2ebfda1ae9 | |||
| 2392478bd3 | |||
| a437206643 |
+1
-1
@@ -48,7 +48,7 @@ We consider publicly-registered domain names to be public information. This nece
|
||||
|
||||
It will speed things up if you suggest a working patch, such as a code diff, and explain why and how it works. Reports that are not actionable, do not contain enough information, are too pushy/demanding, or are not able to convince us that it is a viable and practical attack on the web server itself may be deferred to a later time or possibly ignored, depending on available resources. Priority will be given to credible, responsible reports that are constructive, specific, and actionable. (We get a lot of invalid reports.) Thank you for understanding.
|
||||
|
||||
When you are ready, please email Matt Holt (the author) directly: matt [at] lightcodelabs [dot com].
|
||||
When you are ready, please email Matt Holt (the author) directly: matt at dyanim dot com.
|
||||
|
||||
Please don't encrypt the email body. It only makes the process more complicated.
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
linters-settings:
|
||||
errcheck:
|
||||
ignore: fmt:.*,io/ioutil:^Read.*,go.uber.org/zap/zapcore:^Add.*
|
||||
ignore: fmt:.*,go.uber.org/zap/zapcore:^Add.*
|
||||
ignoretests: true
|
||||
|
||||
linters:
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ nfpms:
|
||||
- id: default
|
||||
package_name: caddy
|
||||
|
||||
vendor: Light Code Labs
|
||||
vendor: Dyanim
|
||||
homepage: https://caddyserver.com
|
||||
maintainer: Matthew Holt <mholt@users.noreply.github.com>
|
||||
description: |
|
||||
|
||||
@@ -176,6 +176,8 @@ Please use our [issue tracker](https://github.com/caddyserver/caddy/issues) only
|
||||
|
||||
## About
|
||||
|
||||
Matthew Holt began developing Caddy in 2014 while studying computer science at Brigham Young University. (The name "Caddy" was chosen because this software helps with the tedious, mundane tasks of serving the Web, and is also a single place for multiple things to be organized together.) It soon became the first web server to use HTTPS automatically and by default, and now has hundreds of contributors and has served trillions of HTTPS requests.
|
||||
|
||||
**The name "Caddy" is trademarked.** The name of the software is "Caddy", not "Caddy Server" or "CaddyServer". Please call it "Caddy" or, if you wish to clarify, "the Caddy web server". Caddy is a registered trademark of Stack Holdings GmbH.
|
||||
|
||||
- _Project on Twitter: [@caddyserver](https://twitter.com/caddyserver)_
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
"expvar"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
@@ -1202,7 +1201,7 @@ var (
|
||||
// will get deleted before the process gracefully exits.
|
||||
func PIDFile(filename string) error {
|
||||
pid := []byte(strconv.Itoa(os.Getpid()) + "\n")
|
||||
err := ioutil.WriteFile(filename, pid, 0600)
|
||||
err := os.WriteFile(filename, pid, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -300,7 +299,7 @@ func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error {
|
||||
zap.String("dir", dir),
|
||||
zap.Error(err))
|
||||
} else {
|
||||
err := ioutil.WriteFile(ConfigAutosavePath, cfgJSON, 0600)
|
||||
err := os.WriteFile(ConfigAutosavePath, cfgJSON, 0600)
|
||||
if err == nil {
|
||||
Log().Info("autosaved config (load with --resume flag)", zap.String("file", ConfigAutosavePath))
|
||||
} else {
|
||||
@@ -700,13 +699,13 @@ func ParseDuration(s string) (time.Duration, error) {
|
||||
// have its own unique ID.
|
||||
func InstanceID() (uuid.UUID, error) {
|
||||
uuidFilePath := filepath.Join(AppDataDir(), "instance.uuid")
|
||||
uuidFileBytes, err := ioutil.ReadFile(uuidFilePath)
|
||||
uuidFileBytes, err := os.ReadFile(uuidFilePath)
|
||||
if os.IsNotExist(err) {
|
||||
uuid, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return uuid, err
|
||||
}
|
||||
err = ioutil.WriteFile(uuidFilePath, []byte(uuid.String()), 0600)
|
||||
err = os.WriteFile(uuidFilePath, []byte(uuid.String()), 0600)
|
||||
return uuid, err
|
||||
} else if err != nil {
|
||||
return [16]byte{}, err
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,7 @@ package caddyfile
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -447,7 +447,7 @@ func (p *parser) doSingleImport(importFile string) ([]Token, error) {
|
||||
return nil, p.Errf("Could not import %s: is a directory", importFile)
|
||||
}
|
||||
|
||||
input, err := ioutil.ReadAll(file)
|
||||
input, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil, p.Errf("Could not read imported file %s: %v", importFile, err)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015 Light Code Labs, LLC
|
||||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,6 @@ package caddyfile
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -280,7 +279,7 @@ func TestRecursiveImport(t *testing.T) {
|
||||
}
|
||||
|
||||
// test relative recursive import
|
||||
err = ioutil.WriteFile(recursiveFile1, []byte(
|
||||
err = os.WriteFile(recursiveFile1, []byte(
|
||||
`localhost
|
||||
dir1
|
||||
import recursive_import_test2`), 0644)
|
||||
@@ -289,7 +288,7 @@ func TestRecursiveImport(t *testing.T) {
|
||||
}
|
||||
defer os.Remove(recursiveFile1)
|
||||
|
||||
err = ioutil.WriteFile(recursiveFile2, []byte("dir2 1"), 0644)
|
||||
err = os.WriteFile(recursiveFile2, []byte("dir2 1"), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -314,7 +313,7 @@ func TestRecursiveImport(t *testing.T) {
|
||||
}
|
||||
|
||||
// test absolute recursive import
|
||||
err = ioutil.WriteFile(recursiveFile1, []byte(
|
||||
err = os.WriteFile(recursiveFile1, []byte(
|
||||
`localhost
|
||||
dir1
|
||||
import `+recursiveFile2), 0644)
|
||||
@@ -370,7 +369,7 @@ func TestDirectiveImport(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(directiveFile, []byte(`prop1 1
|
||||
err = os.WriteFile(directiveFile, []byte(`prop1 1
|
||||
prop2 2`), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -633,7 +632,7 @@ func TestSnippets(t *testing.T) {
|
||||
}
|
||||
|
||||
func writeStringToTempFileOrDie(t *testing.T, str string) (pathToFile string) {
|
||||
file, err := ioutil.TempFile("", t.Name())
|
||||
file, err := os.CreateTemp("", t.Name())
|
||||
if err != nil {
|
||||
panic(err) // get a stack trace so we know where this was called from.
|
||||
}
|
||||
|
||||
@@ -337,7 +337,9 @@ func (a Address) Normalize() Address {
|
||||
// ensure host is normalized if it's an IP address
|
||||
host := strings.TrimSpace(a.Host)
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
host = ip.String()
|
||||
if ipv6 := ip.To16(); ipv6 != nil && ipv6.DefaultMask() == nil {
|
||||
host = ipv6.String()
|
||||
}
|
||||
}
|
||||
|
||||
return Address{
|
||||
@@ -349,28 +351,6 @@ func (a Address) Normalize() Address {
|
||||
}
|
||||
}
|
||||
|
||||
// Key returns a string form of a, much like String() does, but this
|
||||
// method doesn't add anything default that wasn't in the original.
|
||||
func (a Address) Key() string {
|
||||
res := ""
|
||||
if a.Scheme != "" {
|
||||
res += a.Scheme + "://"
|
||||
}
|
||||
if a.Host != "" {
|
||||
res += a.Host
|
||||
}
|
||||
// insert port only if the original has its own explicit port
|
||||
if a.Port != "" &&
|
||||
len(a.Original) >= len(res) &&
|
||||
strings.HasPrefix(a.Original[len(res):], ":"+a.Port) {
|
||||
res += ":" + a.Port
|
||||
}
|
||||
if a.Path != "" {
|
||||
res += a.Path
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// lowerExceptPlaceholders lowercases s except within
|
||||
// placeholders (substrings in non-escaped '{ }' spans).
|
||||
// See https://github.com/caddyserver/caddy/issues/3264
|
||||
|
||||
@@ -106,67 +106,128 @@ func TestAddressString(t *testing.T) {
|
||||
func TestKeyNormalization(t *testing.T) {
|
||||
testCases := []struct {
|
||||
input string
|
||||
expect string
|
||||
expect Address
|
||||
}{
|
||||
{
|
||||
input: "example.com",
|
||||
expect: "example.com",
|
||||
input: "example.com",
|
||||
expect: Address{
|
||||
Host: "example.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "http://host:1234/path",
|
||||
expect: "http://host:1234/path",
|
||||
input: "http://host:1234/path",
|
||||
expect: Address{
|
||||
Scheme: "http",
|
||||
Host: "host",
|
||||
Port: "1234",
|
||||
Path: "/path",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "HTTP://A/ABCDEF",
|
||||
expect: "http://a/ABCDEF",
|
||||
input: "HTTP://A/ABCDEF",
|
||||
expect: Address{
|
||||
Scheme: "http",
|
||||
Host: "a",
|
||||
Path: "/ABCDEF",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "A/ABCDEF",
|
||||
expect: "a/ABCDEF",
|
||||
input: "A/ABCDEF",
|
||||
expect: Address{
|
||||
Host: "a",
|
||||
Path: "/ABCDEF",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "A:2015/Path",
|
||||
expect: "a:2015/Path",
|
||||
input: "A:2015/Path",
|
||||
expect: Address{
|
||||
Host: "a",
|
||||
Port: "2015",
|
||||
Path: "/Path",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "sub.{env.MY_DOMAIN}",
|
||||
expect: "sub.{env.MY_DOMAIN}",
|
||||
input: "sub.{env.MY_DOMAIN}",
|
||||
expect: Address{
|
||||
Host: "sub.{env.MY_DOMAIN}",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "sub.ExAmPle",
|
||||
expect: "sub.example",
|
||||
input: "sub.ExAmPle",
|
||||
expect: Address{
|
||||
Host: "sub.example",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "sub.\\{env.MY_DOMAIN\\}",
|
||||
expect: "sub.\\{env.my_domain\\}",
|
||||
input: "sub.\\{env.MY_DOMAIN\\}",
|
||||
expect: Address{
|
||||
Host: "sub.\\{env.my_domain\\}",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "sub.{env.MY_DOMAIN}.com",
|
||||
expect: "sub.{env.MY_DOMAIN}.com",
|
||||
input: "sub.{env.MY_DOMAIN}.com",
|
||||
expect: Address{
|
||||
Host: "sub.{env.MY_DOMAIN}.com",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: ":80",
|
||||
expect: ":80",
|
||||
input: ":80",
|
||||
expect: Address{
|
||||
Port: "80",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: ":443",
|
||||
expect: ":443",
|
||||
input: ":443",
|
||||
expect: Address{
|
||||
Port: "443",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: ":1234",
|
||||
expect: ":1234",
|
||||
input: ":1234",
|
||||
expect: Address{
|
||||
Port: "1234",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "",
|
||||
expect: "",
|
||||
expect: Address{},
|
||||
},
|
||||
{
|
||||
input: ":",
|
||||
expect: "",
|
||||
expect: Address{},
|
||||
},
|
||||
{
|
||||
input: "[::]",
|
||||
expect: "::",
|
||||
input: "[::]",
|
||||
expect: Address{
|
||||
Host: "::",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "127.0.0.1",
|
||||
expect: Address{
|
||||
Host: "127.0.0.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:1234",
|
||||
expect: Address{
|
||||
Host: "2001:db8:85a3:8d3:1319:8a2e:370:7348",
|
||||
Port: "1234",
|
||||
},
|
||||
},
|
||||
{
|
||||
// IPv4 address in IPv6 form (#4381)
|
||||
input: "[::ffff:cff4:e77d]:1234",
|
||||
expect: Address{
|
||||
Host: "::ffff:cff4:e77d",
|
||||
Port: "1234",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "::ffff:cff4:e77d",
|
||||
expect: Address{
|
||||
Host: "::ffff:cff4:e77d",
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
@@ -175,9 +236,18 @@ func TestKeyNormalization(t *testing.T) {
|
||||
t.Errorf("Test %d: Parsing address '%s': %v", i, tc.input, err)
|
||||
continue
|
||||
}
|
||||
if actual := addr.Normalize().Key(); actual != tc.expect {
|
||||
t.Errorf("Test %d: Input '%s': Expected '%s' but got '%s'", i, tc.input, tc.expect, actual)
|
||||
actual := addr.Normalize()
|
||||
if actual.Scheme != tc.expect.Scheme {
|
||||
t.Errorf("Test %d: Input '%s': Expected Scheme='%s' but got Scheme='%s'", i, tc.input, tc.expect.Scheme, actual.Scheme)
|
||||
}
|
||||
if actual.Host != tc.expect.Host {
|
||||
t.Errorf("Test %d: Input '%s': Expected Host='%s' but got Host='%s'", i, tc.input, tc.expect.Host, actual.Host)
|
||||
}
|
||||
if actual.Port != tc.expect.Port {
|
||||
t.Errorf("Test %d: Input '%s': Expected Port='%s' but got Port='%s'", i, tc.input, tc.expect.Port, actual.Port)
|
||||
}
|
||||
if actual.Path != tc.expect.Path {
|
||||
t.Errorf("Test %d: Input '%s': Expected Path='%s' but got Path='%s'", i, tc.input, tc.expect.Path, actual.Path)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ import (
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"html"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -230,7 +230,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
|
||||
return nil, h.ArgErr()
|
||||
}
|
||||
filename := h.Val()
|
||||
certDataPEM, err := ioutil.ReadFile(filename)
|
||||
certDataPEM, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -485,7 +485,7 @@ func (sb serverBlock) hostsFromKeysNotHTTP(httpPort string) []string {
|
||||
if addr.Host == "" {
|
||||
continue
|
||||
}
|
||||
if addr.Scheme != "http" && addr.Port != httpPort {
|
||||
if addr.Scheme != "http" || addr.Port != httpPort {
|
||||
hostMap[addr.Host] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,7 @@ func (st ServerType) Setup(inputServerBlocks []caddyfile.ServerBlock,
|
||||
"{tls_client_serial}", "{http.request.tls.client.serial}",
|
||||
"{tls_client_subject}", "{http.request.tls.client.subject}",
|
||||
"{tls_client_certificate_pem}", "{http.request.tls.client.certificate_pem}",
|
||||
"{tls_client_certificate_der_base64}", "{http.request.tls.client.certificate_der_base64}",
|
||||
"{upstream_hostport}", "{http.reverse_proxy.upstream.hostport}",
|
||||
)
|
||||
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddyconfig
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
@@ -81,7 +96,7 @@ func (hl HTTPLoader) LoadConfig(ctx caddy.Context) ([]byte, error) {
|
||||
return nil, fmt.Errorf("server responded with HTTP %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -130,7 +145,7 @@ func (hl HTTPLoader) makeClient(ctx caddy.Context) (*http.Client, error) {
|
||||
if len(hl.TLS.RootCAPEMFiles) > 0 {
|
||||
rootPool := x509.NewCertPool()
|
||||
for _, pemFile := range hl.TLS.RootCAPEMFiles {
|
||||
pemData, err := ioutil.ReadFile(pemFile)
|
||||
pemData, err := os.ReadFile(pemFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed reading ca cert: %v", err)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -129,7 +129,7 @@ func (tc *Tester) initServer(rawConfig string, configType string) error {
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
body, _ := io.ReadAll(res.Body)
|
||||
|
||||
var out bytes.Buffer
|
||||
_ = json.Indent(&out, body, "", " ")
|
||||
@@ -162,7 +162,7 @@ func (tc *Tester) initServer(rawConfig string, configType string) error {
|
||||
timeElapsed(start, "caddytest: config load time")
|
||||
|
||||
defer res.Body.Close()
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
tc.t.Errorf("unable to read response. %s", err)
|
||||
return err
|
||||
@@ -202,7 +202,7 @@ func (tc *Tester) ensureConfigRunning(rawConfig string, configType string) error
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
actualBytes, err := ioutil.ReadAll(resp.Body)
|
||||
actualBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -471,7 +471,7 @@ func (tc *Tester) AssertResponse(req *http.Request, expectedStatusCode int, expe
|
||||
resp := tc.AssertResponseCode(req, expectedStatusCode)
|
||||
|
||||
defer resp.Body.Close()
|
||||
bytes, err := ioutil.ReadAll(resp.Body)
|
||||
bytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
tc.t.Fatalf("unable to read the response body %s", err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
:8884
|
||||
|
||||
php_fastcgi localhost:9000 {
|
||||
# some php_fastcgi-specific subdirectives
|
||||
split .php .php5
|
||||
env VAR1 value1
|
||||
env VAR2 value2
|
||||
root /var/www
|
||||
try_files {path} {path}/index.php =404
|
||||
dial_timeout 3s
|
||||
read_timeout 10s
|
||||
write_timeout 20s
|
||||
|
||||
# passed through to reverse_proxy (directive order doesn't matter!)
|
||||
lb_policy random
|
||||
}
|
||||
----------
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"srv0": {
|
||||
"listen": [
|
||||
":8884"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"file": {
|
||||
"try_files": [
|
||||
"{http.request.uri.path}/index.php"
|
||||
]
|
||||
},
|
||||
"not": [
|
||||
{
|
||||
"path": [
|
||||
"*/"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"handle": [
|
||||
{
|
||||
"handler": "static_response",
|
||||
"headers": {
|
||||
"Location": [
|
||||
"{http.request.uri.path}/"
|
||||
]
|
||||
},
|
||||
"status_code": 308
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"file": {
|
||||
"try_files": [
|
||||
"{http.request.uri.path}",
|
||||
"{http.request.uri.path}/index.php",
|
||||
"=404"
|
||||
],
|
||||
"split_path": [
|
||||
".php",
|
||||
".php5"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"handle": [
|
||||
{
|
||||
"handler": "rewrite",
|
||||
"uri": "{http.matchers.file.relative}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"path": [
|
||||
"*.php",
|
||||
"*.php5"
|
||||
]
|
||||
}
|
||||
],
|
||||
"handle": [
|
||||
{
|
||||
"handler": "reverse_proxy",
|
||||
"load_balancing": {
|
||||
"selection_policy": {
|
||||
"policy": "random"
|
||||
}
|
||||
},
|
||||
"transport": {
|
||||
"dial_timeout": 3000000000,
|
||||
"env": {
|
||||
"VAR1": "value1",
|
||||
"VAR2": "value2"
|
||||
},
|
||||
"protocol": "fastcgi",
|
||||
"read_timeout": 10000000000,
|
||||
"root": "/var/www",
|
||||
"split_path": [
|
||||
".php",
|
||||
".php5"
|
||||
],
|
||||
"write_timeout": 20000000000
|
||||
},
|
||||
"upstreams": [
|
||||
{
|
||||
"dial": "localhost:9000"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
# (this Caddyfile is contrived, but based on issues #4176 and #4198)
|
||||
|
||||
http://example.com {
|
||||
}
|
||||
|
||||
https://example.com {
|
||||
tls abc@example.com
|
||||
}
|
||||
|
||||
http://localhost:8081 {
|
||||
}
|
||||
|
||||
----------
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
"servers": {
|
||||
"srv0": {
|
||||
"listen": [
|
||||
":443"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"host": [
|
||||
"example.com"
|
||||
]
|
||||
}
|
||||
],
|
||||
"terminal": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"srv1": {
|
||||
"listen": [
|
||||
":80"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"host": [
|
||||
"example.com"
|
||||
]
|
||||
}
|
||||
],
|
||||
"terminal": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"srv2": {
|
||||
"listen": [
|
||||
":8081"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"match": [
|
||||
{
|
||||
"host": [
|
||||
"localhost"
|
||||
]
|
||||
}
|
||||
],
|
||||
"terminal": true
|
||||
}
|
||||
],
|
||||
"automatic_https": {
|
||||
"skip": [
|
||||
"localhost"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tls": {
|
||||
"automation": {
|
||||
"policies": [
|
||||
{
|
||||
"subjects": [
|
||||
"example.com"
|
||||
],
|
||||
"issuers": [
|
||||
{
|
||||
"email": "abc@example.com",
|
||||
"module": "acme"
|
||||
},
|
||||
{
|
||||
"email": "abc@example.com",
|
||||
"module": "zerossl"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package integration
|
||||
import (
|
||||
jsonMod "encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
func TestCaddyfileAdaptToJSON(t *testing.T) {
|
||||
// load the list of test files from the dir
|
||||
files, err := ioutil.ReadDir("./caddyfile_adapt")
|
||||
files, err := os.ReadDir("./caddyfile_adapt")
|
||||
if err != nil {
|
||||
t.Errorf("failed to read caddyfile_adapt dir: %s", err)
|
||||
}
|
||||
@@ -29,7 +29,7 @@ func TestCaddyfileAdaptToJSON(t *testing.T) {
|
||||
|
||||
// read the test file
|
||||
filename := f.Name()
|
||||
data, err := ioutil.ReadFile("./caddyfile_adapt/" + filename)
|
||||
data, err := os.ReadFile("./caddyfile_adapt/" + filename)
|
||||
if err != nil {
|
||||
t.Errorf("failed to read %s dir: %s", filename, err)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -85,7 +84,7 @@ func TestDialWithPlaceholderUnix(t *testing.T) {
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
f, err := ioutil.TempFile("", "*.sock")
|
||||
f, err := os.CreateTemp("", "*.sock")
|
||||
if err != nil {
|
||||
t.Errorf("failed to create TempFile: %s", err)
|
||||
return
|
||||
@@ -387,7 +386,7 @@ func TestReverseProxyHealthCheckUnixSocket(t *testing.T) {
|
||||
t.SkipNow()
|
||||
}
|
||||
tester := caddytest.NewTester(t)
|
||||
f, err := ioutil.TempFile("", "*.sock")
|
||||
f, err := os.CreateTemp("", "*.sock")
|
||||
if err != nil {
|
||||
t.Errorf("failed to create TempFile: %s", err)
|
||||
return
|
||||
@@ -442,7 +441,7 @@ func TestReverseProxyHealthCheckUnixSocketWithoutPort(t *testing.T) {
|
||||
t.SkipNow()
|
||||
}
|
||||
tester := caddytest.NewTester(t)
|
||||
f, err := ioutil.TempFile("", "*.sock")
|
||||
f, err := os.CreateTemp("", "*.sock")
|
||||
if err != nil {
|
||||
t.Errorf("failed to create TempFile: %s", err)
|
||||
return
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
@@ -110,7 +109,7 @@ func TestH2ToH2CStream(t *testing.T) {
|
||||
r, w := io.Pipe()
|
||||
req := &http.Request{
|
||||
Method: "PUT",
|
||||
Body: ioutil.NopCloser(r),
|
||||
Body: io.NopCloser(r),
|
||||
URL: &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "127.0.0.1:9443",
|
||||
@@ -134,7 +133,7 @@ func TestH2ToH2CStream(t *testing.T) {
|
||||
}()
|
||||
|
||||
defer resp.Body.Close()
|
||||
bytes, err := ioutil.ReadAll(resp.Body)
|
||||
bytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to read the response body %s", err)
|
||||
}
|
||||
@@ -319,7 +318,7 @@ func TestH2ToH1ChunkedResponse(t *testing.T) {
|
||||
r, w := io.Pipe()
|
||||
req := &http.Request{
|
||||
Method: "PUT",
|
||||
Body: ioutil.NopCloser(r),
|
||||
Body: io.NopCloser(r),
|
||||
URL: &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "127.0.0.1:9443",
|
||||
@@ -342,7 +341,7 @@ func TestH2ToH1ChunkedResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
bytes, err := ioutil.ReadAll(resp.Body)
|
||||
bytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to read the response body %s", err)
|
||||
}
|
||||
@@ -370,7 +369,7 @@ func testH2ToH1ChunkedResponseServeH1(t *testing.T) *http.Server {
|
||||
}
|
||||
|
||||
defer r.Body.Close()
|
||||
bytes, err := ioutil.ReadAll(r.Body)
|
||||
bytes, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to read the response body %s", err)
|
||||
}
|
||||
|
||||
+23
-16
@@ -22,7 +22,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -181,7 +180,7 @@ func cmdRun(fl Flags) (int, error) {
|
||||
var config []byte
|
||||
var err error
|
||||
if runCmdResumeFlag {
|
||||
config, err = ioutil.ReadFile(caddy.ConfigAutosavePath)
|
||||
config, err = os.ReadFile(caddy.ConfigAutosavePath)
|
||||
if os.IsNotExist(err) {
|
||||
// not a bad error; just can't resume if autosave file doesn't exist
|
||||
caddy.Log().Info("no autosave file exists", zap.String("autosave_file", caddy.ConfigAutosavePath))
|
||||
@@ -219,7 +218,7 @@ func cmdRun(fl Flags) (int, error) {
|
||||
// if we are to report to another process the successful start
|
||||
// of the server, do so now by echoing back contents of stdin
|
||||
if runCmdPingbackFlag != "" {
|
||||
confirmationBytes, err := ioutil.ReadAll(os.Stdin)
|
||||
confirmationBytes, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return caddy.ExitCodeFailedStartup,
|
||||
fmt.Errorf("reading confirmation bytes from stdin: %v", err)
|
||||
@@ -361,6 +360,7 @@ func cmdBuildInfo(fl Flags) (int, error) {
|
||||
func cmdListModules(fl Flags) (int, error) {
|
||||
packages := fl.Bool("packages")
|
||||
versions := fl.Bool("versions")
|
||||
skipStandard := fl.Bool("skip-standard")
|
||||
|
||||
printModuleInfo := func(mi moduleInfo) {
|
||||
fmt.Print(mi.caddyModuleID)
|
||||
@@ -389,14 +389,19 @@ func cmdListModules(fl Flags) (int, error) {
|
||||
return caddy.ExitCodeSuccess, nil
|
||||
}
|
||||
|
||||
if len(standard) > 0 {
|
||||
for _, mod := range standard {
|
||||
printModuleInfo(mod)
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n Standard modules: %d\n", len(standard))
|
||||
if len(nonstandard) > 0 {
|
||||
// Standard modules (always shipped with Caddy)
|
||||
if !skipStandard {
|
||||
if len(standard) > 0 {
|
||||
for _, mod := range standard {
|
||||
printModuleInfo(mod)
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n Standard modules: %d\n", len(standard))
|
||||
}
|
||||
|
||||
// Non-standard modules (third party plugins)
|
||||
if len(nonstandard) > 0 {
|
||||
if len(standard) > 0 && !skipStandard {
|
||||
fmt.Println()
|
||||
}
|
||||
for _, mod := range nonstandard {
|
||||
@@ -404,8 +409,10 @@ func cmdListModules(fl Flags) (int, error) {
|
||||
}
|
||||
}
|
||||
fmt.Printf("\n Non-standard modules: %d\n", len(nonstandard))
|
||||
|
||||
// Unknown modules (couldn't get Caddy module info)
|
||||
if len(unknown) > 0 {
|
||||
if len(standard) > 0 || len(nonstandard) > 0 {
|
||||
if (len(standard) > 0 && !skipStandard) || len(nonstandard) > 0 {
|
||||
fmt.Println()
|
||||
}
|
||||
for _, mod := range unknown {
|
||||
@@ -457,7 +464,7 @@ func cmdAdaptConfig(fl Flags) (int, error) {
|
||||
fmt.Errorf("unrecognized config adapter: %s", adaptCmdAdapterFlag)
|
||||
}
|
||||
|
||||
input, err := ioutil.ReadFile(adaptCmdInputFlag)
|
||||
input, err := os.ReadFile(adaptCmdInputFlag)
|
||||
if err != nil {
|
||||
return caddy.ExitCodeFailedStartup,
|
||||
fmt.Errorf("reading input file: %v", err)
|
||||
@@ -541,7 +548,7 @@ func cmdFmt(fl Flags) (int, error) {
|
||||
|
||||
// as a special case, read from stdin if the file name is "-"
|
||||
if formatCmdConfigFile == "-" {
|
||||
input, err := ioutil.ReadAll(os.Stdin)
|
||||
input, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return caddy.ExitCodeFailedStartup,
|
||||
fmt.Errorf("reading stdin: %v", err)
|
||||
@@ -550,7 +557,7 @@ func cmdFmt(fl Flags) (int, error) {
|
||||
return caddy.ExitCodeSuccess, nil
|
||||
}
|
||||
|
||||
input, err := ioutil.ReadFile(formatCmdConfigFile)
|
||||
input, err := os.ReadFile(formatCmdConfigFile)
|
||||
if err != nil {
|
||||
return caddy.ExitCodeFailedStartup,
|
||||
fmt.Errorf("reading input file: %v", err)
|
||||
@@ -559,7 +566,7 @@ func cmdFmt(fl Flags) (int, error) {
|
||||
output := caddyfile.Format(input)
|
||||
|
||||
if fl.Bool("overwrite") {
|
||||
if err := ioutil.WriteFile(formatCmdConfigFile, output, 0600); err != nil {
|
||||
if err := os.WriteFile(formatCmdConfigFile, output, 0600); err != nil {
|
||||
return caddy.ExitCodeFailedStartup, nil
|
||||
}
|
||||
} else {
|
||||
@@ -699,7 +706,7 @@ func apiRequest(adminAddr, method, uri string, headers http.Header, body io.Read
|
||||
|
||||
// if it didn't work, let the user know
|
||||
if resp.StatusCode >= 400 {
|
||||
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1024*10))
|
||||
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 1024*10))
|
||||
if err != nil {
|
||||
return fmt.Errorf("HTTP %d: reading error message: %v", resp.StatusCode, err)
|
||||
}
|
||||
|
||||
+18
-2
@@ -208,6 +208,7 @@ config file; otherwise the default is assumed.`,
|
||||
fs := flag.NewFlagSet("list-modules", flag.ExitOnError)
|
||||
fs.Bool("packages", false, "Print package paths")
|
||||
fs.Bool("versions", false, "Print version information")
|
||||
fs.Bool("skip-standard", false, "Skip printing standard modules")
|
||||
return fs
|
||||
}(),
|
||||
})
|
||||
@@ -259,7 +260,7 @@ Loads and provisions the provided config, but does not start running it.
|
||||
This reveals any errors with the configuration through the loading and
|
||||
provisioning stages.`,
|
||||
Flags: func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("load", flag.ExitOnError)
|
||||
fs := flag.NewFlagSet("validate", flag.ExitOnError)
|
||||
fs.String("config", "", "Input configuration file")
|
||||
fs.String("adapter", "", "Name of config adapter")
|
||||
return fs
|
||||
@@ -282,7 +283,7 @@ If you wish you use stdin instead of a regular file, use - as the path.
|
||||
When reading from stdin, the --overwrite flag has no effect: the result
|
||||
is always printed to stdout.`,
|
||||
Flags: func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("format", flag.ExitOnError)
|
||||
fs := flag.NewFlagSet("fmt", flag.ExitOnError)
|
||||
fs.Bool("overwrite", false, "Overwrite the input file with the results")
|
||||
return fs
|
||||
}(),
|
||||
@@ -295,6 +296,11 @@ is always printed to stdout.`,
|
||||
Long: `
|
||||
Downloads an updated Caddy binary with the same modules/plugins at the
|
||||
latest versions. EXPERIMENTAL: May be changed or removed.`,
|
||||
Flags: func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("upgrade", flag.ExitOnError)
|
||||
fs.Bool("keep-backup", false, "Keep the backed up binary, instead of deleting it")
|
||||
return fs
|
||||
}(),
|
||||
})
|
||||
|
||||
RegisterCommand(Command{
|
||||
@@ -307,6 +313,11 @@ Downloads an updated Caddy binary with the specified packages (module/plugin)
|
||||
added. Retains existing packages. Returns an error if the any of packages are
|
||||
already included. EXPERIMENTAL: May be changed or removed.
|
||||
`,
|
||||
Flags: func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("add-package", flag.ExitOnError)
|
||||
fs.Bool("keep-backup", false, "Keep the backed up binary, instead of deleting it")
|
||||
return fs
|
||||
}(),
|
||||
})
|
||||
|
||||
RegisterCommand(Command{
|
||||
@@ -319,6 +330,11 @@ Downloads an updated Caddy binaries without the specified packages (module/plugi
|
||||
Returns an error if any of the packages are not included.
|
||||
EXPERIMENTAL: May be changed or removed.
|
||||
`,
|
||||
Flags: func() *flag.FlagSet {
|
||||
fs := flag.NewFlagSet("remove-package", flag.ExitOnError)
|
||||
fs.Bool("keep-backup", false, "Keep the backed up binary, instead of deleting it")
|
||||
return fs
|
||||
}(),
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
+4
-5
@@ -20,7 +20,6 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
@@ -94,7 +93,7 @@ func Main() {
|
||||
// the bytes in expect, or returns an error if it doesn't.
|
||||
func handlePingbackConn(conn net.Conn, expect []byte) error {
|
||||
defer conn.Close()
|
||||
confirmationBytes, err := ioutil.ReadAll(io.LimitReader(conn, 32))
|
||||
confirmationBytes, err := io.ReadAll(io.LimitReader(conn, 32))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -124,9 +123,9 @@ func loadConfig(configFile, adapterName string) ([]byte, string, error) {
|
||||
var err error
|
||||
if configFile != "" {
|
||||
if configFile == "-" {
|
||||
config, err = ioutil.ReadAll(os.Stdin)
|
||||
config, err = io.ReadAll(os.Stdin)
|
||||
} else {
|
||||
config, err = ioutil.ReadFile(configFile)
|
||||
config, err = os.ReadFile(configFile)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("reading config file: %v", err)
|
||||
@@ -140,7 +139,7 @@ func loadConfig(configFile, adapterName string) ([]byte, string, error) {
|
||||
// plugged in, and if so, try using a default Caddyfile
|
||||
cfgAdapter = caddyconfig.GetAdapter("caddyfile")
|
||||
if cfgAdapter != nil {
|
||||
config, err = ioutil.ReadFile("Caddyfile")
|
||||
config, err = os.ReadFile("Caddyfile")
|
||||
if os.IsNotExist(err) {
|
||||
// okay, no default Caddyfile; pretend like this never happened
|
||||
cfgAdapter = nil
|
||||
|
||||
+17
-20
@@ -31,7 +31,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func cmdUpgrade(_ Flags) (int, error) {
|
||||
func cmdUpgrade(fl Flags) (int, error) {
|
||||
_, nonstandard, _, err := getModules()
|
||||
if err != nil {
|
||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("unable to enumerate installed plugins: %v", err)
|
||||
@@ -41,7 +41,7 @@ func cmdUpgrade(_ Flags) (int, error) {
|
||||
return caddy.ExitCodeFailedStartup, err
|
||||
}
|
||||
|
||||
return upgradeBuild(pluginPkgs)
|
||||
return upgradeBuild(pluginPkgs, fl)
|
||||
}
|
||||
|
||||
func cmdAddPackage(fl Flags) (int, error) {
|
||||
@@ -64,7 +64,7 @@ func cmdAddPackage(fl Flags) (int, error) {
|
||||
pluginPkgs[arg] = struct{}{}
|
||||
}
|
||||
|
||||
return upgradeBuild(pluginPkgs)
|
||||
return upgradeBuild(pluginPkgs, fl)
|
||||
}
|
||||
|
||||
func cmdRemovePackage(fl Flags) (int, error) {
|
||||
@@ -88,10 +88,10 @@ func cmdRemovePackage(fl Flags) (int, error) {
|
||||
delete(pluginPkgs, arg)
|
||||
}
|
||||
|
||||
return upgradeBuild(pluginPkgs)
|
||||
return upgradeBuild(pluginPkgs, fl)
|
||||
}
|
||||
|
||||
func upgradeBuild(pluginPkgs map[string]struct{}) (int, error) {
|
||||
func upgradeBuild(pluginPkgs map[string]struct{}, fl Flags) (int, error) {
|
||||
l := caddy.Log()
|
||||
|
||||
thisExecPath, err := os.Executable()
|
||||
@@ -152,18 +152,23 @@ func upgradeBuild(pluginPkgs map[string]struct{}) (int, error) {
|
||||
// use the new binary to print out version and module info
|
||||
fmt.Print("\nModule versions:\n\n")
|
||||
if err = listModules(thisExecPath); err != nil {
|
||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to execute: %v", err)
|
||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to execute 'caddy list-modules': %v", err)
|
||||
}
|
||||
fmt.Println("\nVersion:")
|
||||
if err = showVersion(thisExecPath); err != nil {
|
||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to execute: %v", err)
|
||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to execute 'caddy version': %v", err)
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
// clean up the backup file
|
||||
if err = os.Remove(backupExecPath); err != nil {
|
||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to clean up backup binary: %v", err)
|
||||
if !fl.Bool("keep-backup") {
|
||||
if err = removeCaddyBinary(backupExecPath); err != nil {
|
||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to clean up backup binary: %v", err)
|
||||
}
|
||||
} else {
|
||||
l.Info("skipped cleaning up the backup file", zap.String("backup_path", backupExecPath))
|
||||
}
|
||||
|
||||
l.Info("upgrade successful; please restart any running Caddy instances", zap.String("executable", thisExecPath))
|
||||
|
||||
return caddy.ExitCodeSuccess, nil
|
||||
@@ -220,25 +225,17 @@ func getModules() (standard, nonstandard, unknown []moduleInfo, err error) {
|
||||
}
|
||||
|
||||
func listModules(path string) error {
|
||||
cmd := exec.Command(path, "list-modules", "--versions")
|
||||
cmd := exec.Command(path, "list-modules", "--versions", "--skip-standard")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("download succeeded, but unable to execute: %v", err)
|
||||
}
|
||||
return nil
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func showVersion(path string) error {
|
||||
cmd := exec.Command(path, "version")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("download succeeded, but unable to execute: %v", err)
|
||||
}
|
||||
return nil
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func downloadBuild(qs url.Values) (*http.Response, error) {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package caddycmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// removeCaddyBinary removes the Caddy binary at the given path.
|
||||
//
|
||||
// On any non-Windows OS, this simply calls os.Remove, since they should
|
||||
// probably not exhibit any issue with processes deleting themselves.
|
||||
func removeCaddyBinary(path string) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package caddycmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// removeCaddyBinary removes the Caddy binary at the given path.
|
||||
//
|
||||
// On Windows, this uses a syscall to indirectly remove the file,
|
||||
// because otherwise we get an "Access is denied." error when trying
|
||||
// to delete the binary while Caddy is still running and performing
|
||||
// the upgrade. "cmd.exe /C" executes a command specified by the
|
||||
// following arguments, i.e. "del" which will run as a separate process,
|
||||
// which avoids the "Access is denied." error.
|
||||
func removeCaddyBinary(path string) error {
|
||||
var sI syscall.StartupInfo
|
||||
var pI syscall.ProcessInformation
|
||||
argv := syscall.StringToUTF16Ptr(filepath.Join(os.Getenv("windir"), "system32", "cmd.exe") + " /C del " + path)
|
||||
return syscall.CreateProcess(nil, argv, nil, nil, true, 0, nil, nil, &sI, &pI)
|
||||
}
|
||||
@@ -6,30 +6,34 @@ require (
|
||||
github.com/Masterminds/sprig/v3 v3.2.2
|
||||
github.com/alecthomas/chroma v0.9.2
|
||||
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b
|
||||
github.com/caddyserver/certmagic v0.14.5
|
||||
github.com/caddyserver/certmagic v0.15.2
|
||||
github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac
|
||||
github.com/go-chi/chi v4.1.2+incompatible
|
||||
github.com/google/cel-go v0.7.3
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/klauspost/compress v1.13.4
|
||||
github.com/klauspost/compress v1.13.6
|
||||
github.com/klauspost/cpuid/v2 v2.0.9
|
||||
github.com/lucas-clemente/quic-go v0.23.0
|
||||
github.com/mholt/acmez v1.0.0
|
||||
github.com/mholt/acmez v1.0.1
|
||||
github.com/naoina/go-stringutil v0.1.0 // indirect
|
||||
github.com/naoina/toml v0.1.1
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/smallstep/certificates v0.16.4
|
||||
github.com/smallstep/cli v0.16.1
|
||||
github.com/smallstep/certificates v0.17.5-0.20211008195551-04fe3126bebf
|
||||
github.com/smallstep/cli v0.17.6
|
||||
github.com/smallstep/nosql v0.3.8
|
||||
github.com/smallstep/truststore v0.9.6
|
||||
github.com/yuin/goldmark v1.4.0
|
||||
github.com/yuin/goldmark v1.4.1
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01
|
||||
go.uber.org/zap v1.19.0
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
|
||||
golang.org/x/crypto v0.0.0-20210915214749-c084706c2272
|
||||
golang.org/x/net v0.0.0-20210913180222-943fd674d43e
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08
|
||||
google.golang.org/genproto v0.0.0-20210719143636-1d5a45f8e492
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
// avoid license conflict from juju/ansiterm until https://github.com/manifoldco/promptui/pull/181
|
||||
// is merged or other dependency in path currently in violation fixes compliance
|
||||
replace github.com/manifoldco/promptui => github.com/nguyer/promptui v0.8.1-0.20210517132806-70ccd4709797
|
||||
|
||||
@@ -74,8 +74,6 @@ github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSW
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic=
|
||||
@@ -173,8 +171,8 @@ github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw=
|
||||
github.com/caddyserver/certmagic v0.14.5 h1:y4HcFzLLBMsTv8sSlAPj5K55mvntX8e8ExcmB/lhO6w=
|
||||
github.com/caddyserver/certmagic v0.14.5/go.mod h1:/0VQ5og2Jxa5yBQ8eT80wWS7fi/DgNy1uXeXRUJ1Wj0=
|
||||
github.com/caddyserver/certmagic v0.15.2 h1:OMTakTsLM1ZfzMDjwvYprfUgFzpVPh3u87oxMPwmeBc=
|
||||
github.com/caddyserver/certmagic v0.15.2/go.mod h1:qhkAOthf72ufAcp3Y5jF2RaGE96oip3UbEQRIzwe3/8=
|
||||
github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A=
|
||||
@@ -201,6 +199,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
||||
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
||||
@@ -238,7 +237,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
|
||||
github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8=
|
||||
github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
|
||||
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20201003150343-5d1bab4fc658/go.mod h1:2uGEvGm+JSDLd5UAaKIFSbXDcYyeH0fWJP4N2HMMYMI=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
|
||||
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
@@ -271,6 +269,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE=
|
||||
@@ -370,8 +369,6 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
@@ -497,8 +494,9 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
||||
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
|
||||
github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs=
|
||||
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
@@ -506,8 +504,9 @@ github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGzny
|
||||
github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||
@@ -536,8 +535,6 @@ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
|
||||
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
|
||||
github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
@@ -548,9 +545,8 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s=
|
||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -578,14 +574,11 @@ github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0U
|
||||
github.com/lucas-clemente/quic-go v0.23.0 h1:5vFnKtZ6nHDFsc/F3uuiF4T3y/AXaQdxjUqiVw26GZE=
|
||||
github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
|
||||
github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/lunixbochs/vtclean v1.0.0 h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo=
|
||||
github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ=
|
||||
github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
@@ -617,20 +610,23 @@ github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb44
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mholt/acmez v1.0.0 h1:ZAdWrilnq41HTlUO0vMJ6C+z8ZvzQ9I2LR1/Bo+137U=
|
||||
github.com/mholt/acmez v1.0.0/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mholt/acmez v1.0.1 h1:J7uquHOKEmo71UDnVApy1sSLA0oF/r+NtVrNzMKKA9I=
|
||||
github.com/mholt/acmez v1.0.1/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/micromdm/scep/v2 v2.0.0 h1:cRzcY0S5QX+0+J+7YC4P2uZSnfMup8S8zJu/bLFgOkA=
|
||||
github.com/micromdm/scep/v2 v2.0.0/go.mod h1:ouaDs5tcjOjdHD/h8BGaQsWE87MUnQ/wMTMgfMMIpPc=
|
||||
github.com/micromdm/scep/v2 v2.1.0 h1:2fS9Rla7qRR266hvUoEauBJ7J6FhgssEiq2OkSKXmaU=
|
||||
github.com/micromdm/scep/v2 v2.1.0/go.mod h1:BkF7TkPPhmgJAMtHfP+sFTKXmgzNJgLQlvvGoOExBcc=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY=
|
||||
github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
@@ -639,8 +635,9 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE=
|
||||
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
@@ -666,6 +663,8 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/newrelic/go-agent v2.15.0+incompatible/go.mod h1:a8Fv1b/fYhFSReoTU6HDkTYIMZeSVNffmoS726Y0LzQ=
|
||||
github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM=
|
||||
github.com/nguyer/promptui v0.8.1-0.20210517132806-70ccd4709797 h1:unCiBzwNjcuVbP3bgM76z0ORyIuI4sspop1qhkQJ044=
|
||||
github.com/nguyer/promptui v0.8.1-0.20210517132806-70ccd4709797/go.mod h1:CBMXL3a2sC3Q8TjpLcQt8w/3aQ23VSy6r7UFeCG6phA=
|
||||
github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
@@ -823,18 +822,17 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||
github.com/smallstep/assert v0.0.0-20180720014142-de77670473b5/go.mod h1:TC9A4+RjIOS+HyTH7wG17/gSqVv95uDw2J64dQZx7RE=
|
||||
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY=
|
||||
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc=
|
||||
github.com/smallstep/certificates v0.16.0/go.mod h1:oht6bnzBapjumPGXTZK/rBJYLO+O8/TTWt5/VlE9Wd4=
|
||||
github.com/smallstep/certificates v0.16.4 h1:/dhaR+6reeTHd2etVIjgpZI0CTn6USrhVqakoV0HZ0w=
|
||||
github.com/smallstep/certificates v0.16.4/go.mod h1:U3Dkt4ttxRxC4yPedzzAQokC121/7d3Sfnj6mNgpw7Q=
|
||||
github.com/smallstep/certinfo v1.5.1/go.mod h1:gA7HBbue0Wwr3kD60P2UtgTIFfMAOC66D3rzYhI0GZ4=
|
||||
github.com/smallstep/cli v0.16.1 h1:zFN/B5XF+WbvwfRya11SPfiT7g7LIMRSCaoeQNce3Hw=
|
||||
github.com/smallstep/cli v0.16.1/go.mod h1:C8IES4TcHN3/Va6x9B+ugJM1t0pwzICHAg+RB2FASg4=
|
||||
github.com/smallstep/nosql v0.3.6/go.mod h1:h1zC/Z54uNHc8euquLED4qJNCrMHd3nytA141ZZh4qQ=
|
||||
github.com/smallstep/certificates v0.17.4/go.mod h1:NRV/XqAmL65jDaAiLDEYeW0PySKPim+RX+rWi00LKDM=
|
||||
github.com/smallstep/certificates v0.17.5-0.20211008195551-04fe3126bebf h1:T27FAcJuIadMwnt5uaYCxeNQceUoCkLHqWc0Y+PneHE=
|
||||
github.com/smallstep/certificates v0.17.5-0.20211008195551-04fe3126bebf/go.mod h1:dAdOimWAt87o2PZvf3KCjbKkxWKBsq85/eFemB4JVTE=
|
||||
github.com/smallstep/certinfo v1.5.2/go.mod h1:gA7HBbue0Wwr3kD60P2UtgTIFfMAOC66D3rzYhI0GZ4=
|
||||
github.com/smallstep/cli v0.17.6 h1:0npb8eQGDgEBPziYXb9tW4f4S5jt8aRRmEJvs97oh+Y=
|
||||
github.com/smallstep/cli v0.17.6/go.mod h1:IZoK7eNA/r6cTN9GCd6+M1omgb5Ic8mJjHHH9Bh078U=
|
||||
github.com/smallstep/nosql v0.3.8 h1:1/EWUbbEdz9ai0g9Fd09VekVjtxp+5+gIHpV2PdwW3o=
|
||||
github.com/smallstep/nosql v0.3.8/go.mod h1:X2qkYpNcW3yjLUvhEHfgGfClpKbFPapewvx7zo4TOFs=
|
||||
github.com/smallstep/truststore v0.9.6 h1:vNzEJmaJL0XOZD8uouXLmYu4/aP1UQ/wHUopH3qKeYA=
|
||||
github.com/smallstep/truststore v0.9.6/go.mod h1:HwHKRcBi0RUxxw1LYDpTRhYC4jZUuxPpkHdVonlkoDM=
|
||||
github.com/smallstep/zcrypto v0.0.0-20200203191936-fbc32cf76bce/go.mod h1:+F24VU3UCxfVFvvqgm5jNUFQOm/L6ed13ImwWGFgg/g=
|
||||
github.com/smallstep/zcrypto v0.0.0-20210924233136-66c2600f6e71/go.mod h1:+F24VU3UCxfVFvvqgm5jNUFQOm/L6ed13ImwWGFgg/g=
|
||||
github.com/smallstep/zlint v0.0.0-20180727184541-d84eaafe274f/go.mod h1:GeHHT7sJDI9ti3oEaFnvx1F4N8n3ZSw2YM1+sbEoxc4=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||
@@ -852,8 +850,9 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
@@ -919,8 +918,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.3.6/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0 h1:OtISOGfH6sOWa1/qXqqAiOIAO6Z5J3AEAE18WAq6BiQ=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1 h1:/vn0k+RBvwlxEmP5E7SZMqNxPhfMVFEJiykr15/0XKM=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01 h1:0SJnXjE4jDClMW6grE0xpNhwpqbPwkBTn8zpVw5C0SI=
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01/go.mod h1:TwKQPa5XkCCRC2GRZ5wtfNUTQ2+9/i19mGRijFeJ4BE=
|
||||
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
|
||||
@@ -955,8 +954,9 @@ go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0/go.mod h1:HnrHxjyCuZ8YDt8PYVyQQ5d1ZQfzJV
|
||||
go.etcd.io/etcd/tests/v3 v3.5.0/go.mod h1:f+mtZ1bE1YPvgKdOJV2BKy4JQW0nAFnQehgOE7+WyJE=
|
||||
go.etcd.io/etcd/v3 v3.5.0-alpha.0/go.mod h1:JZ79d3LV6NUfPjUxXrpiFAYcjhT+06qqw+i28snx8To=
|
||||
go.etcd.io/etcd/v3 v3.5.0/go.mod h1:FldM0/VzcxYWLvWx1sdA7ghKw7C3L2DvUTzGrcEtsC4=
|
||||
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 h1:A/5uWzF44DlIgdm/PQFwfMkW0JX+cIcQi/SwLAmZP5M=
|
||||
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
|
||||
go.mozilla.org/pkcs7 v0.0.0-20210730143726-725912489c62/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
|
||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak=
|
||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
|
||||
go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
@@ -981,12 +981,14 @@ go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi
|
||||
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
|
||||
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.step.sm/cli-utils v0.4.1 h1:QztRUhGYjOPM1I2Nmi7V6XejQyVtcESmo+sbegxvX7Q=
|
||||
go.step.sm/cli-utils v0.4.1/go.mod h1:hWYVOSlw8W9Pd+BwIbs/aftVVMRms3EG7Q2qLRwc0WA=
|
||||
go.step.sm/crypto v0.9.0 h1:q2AllTSnVj4NRtyEPkGW2ohArLmbGbe6ZAL/VIOKDzA=
|
||||
go.step.sm/cli-utils v0.6.0 h1:sH4FxBcjmbxyilKXheSyJuKF/QjpojpiW90ERwUWOgQ=
|
||||
go.step.sm/cli-utils v0.6.0/go.mod h1:jklBMavFl2PbmGlyxgax08ZnB0uWpadjuOlSKKXz+0U=
|
||||
go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
|
||||
go.step.sm/linkedca v0.0.0-20210611183751-27424aae8d25 h1:ncJqviWswJT19IdnfOYQGKG1zL7IDy4lAJz1PuM3fgw=
|
||||
go.step.sm/linkedca v0.0.0-20210611183751-27424aae8d25/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo=
|
||||
go.step.sm/crypto v0.11.0 h1:VDpeVgEmqme/FK2w5QINxkOQ1FWOm/Wi2TwQXiacKr8=
|
||||
go.step.sm/crypto v0.11.0/go.mod h1:5YzQ85BujYBu6NH18jw7nFjwuRnDch35nLzH0ES5sKg=
|
||||
go.step.sm/linkedca v0.5.0 h1:oZVRSpElM7lAL1XN2YkjdHwI/oIZ+1ULOnuqYPM6xjY=
|
||||
go.step.sm/linkedca v0.5.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
@@ -1031,10 +1033,9 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 h1:3erb+vDS8lU1sxfDHF4/hhWyaXnhIaO+7RgL4fDZORA=
|
||||
golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -1134,8 +1135,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210913180222-943fd674d43e h1:+b/22bPvDYt4NPDcy4xAGCmON713ONAWFeY3Z7I3tR8=
|
||||
golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -1253,8 +1254,8 @@ golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164 h1:7ZDGnxgHAMw7thfC5bEos0RDAccZKxioiWBhfIe+tvw=
|
||||
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
||||
@@ -1265,8 +1266,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1343,8 +1345,9 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3 h1:L69ShwSZEyCsLKoAxDKeMvLDZkumEe8gXUZAjab0tX8=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1454,8 +1457,9 @@ google.golang.org/genproto v0.0.0-20210427215850-f767ed18ee4d/go.mod h1:P3QM42oQ
|
||||
google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08 h1:pc16UedxnxXXtGxHCSUhafAoVHQZ0yXl8ZelMH4EETc=
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210719143636-1d5a45f8e492 h1:7yQQsvnwjfEahbNNEKcBHv3mR+HnB1ctGY/z1JXzx8M=
|
||||
google.golang.org/genproto v0.0.0-20210719143636-1d5a45f8e492/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
@@ -1486,8 +1490,9 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
@@ -1519,8 +1524,9 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
|
||||
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
|
||||
|
||||
+2
-3
@@ -18,7 +18,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -630,9 +629,9 @@ func (StderrWriter) OpenWriter() (io.WriteCloser, error) {
|
||||
return notClosable{os.Stderr}, nil
|
||||
}
|
||||
|
||||
// OpenWriter returns ioutil.Discard that can't be closed.
|
||||
// OpenWriter returns io.Discard that can't be closed.
|
||||
func (DiscardWriter) OpenWriter() (io.WriteCloser, error) {
|
||||
return notClosable{ioutil.Discard}, nil
|
||||
return notClosable{io.Discard}, nil
|
||||
}
|
||||
|
||||
// notClosable is an io.WriteCloser that can't be closed.
|
||||
|
||||
@@ -77,6 +77,7 @@ func init() {
|
||||
// `{http.request.tls.client.public_key}` | The public key of the client certificate.
|
||||
// `{http.request.tls.client.public_key_sha256}` | The SHA256 checksum of the client's public key.
|
||||
// `{http.request.tls.client.certificate_pem}` | The PEM-encoded value of the certificate.
|
||||
// `{http.request.tls.client.certificate_der_base64}` | The base64-encoded value of the certificate.
|
||||
// `{http.request.tls.client.issuer}` | The issuer DN of the client certificate
|
||||
// `{http.request.tls.client.serial}` | The serial number of the client certificate
|
||||
// `{http.request.tls.client.subject}` | The subject DN of the client certificate
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -227,6 +228,7 @@ func StatusCodeMatches(actual, configured int) bool {
|
||||
// never be outside of root. The resulting path can be used
|
||||
// with the local file system.
|
||||
func SanitizedPathJoin(root, reqPath string) string {
|
||||
reqPath, _ = url.PathUnescape(reqPath)
|
||||
if root == "" {
|
||||
root = "."
|
||||
}
|
||||
|
||||
@@ -137,7 +137,12 @@ func (fsrv *FileServer) loadDirectoryContents(dir *os.File, root, urlPath string
|
||||
// user can presumably browse "up" to parent folder if path is longer than "/"
|
||||
canGoUp := len(urlPath) > 1
|
||||
|
||||
return fsrv.directoryListing(files, canGoUp, root, urlPath, repl), nil
|
||||
l, err := fsrv.directoryListing(files, canGoUp, root, urlPath, repl)
|
||||
if err != nil {
|
||||
return browseTemplateContext{}, err
|
||||
}
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// browseApplyQueryParams applies query parameters to the listing.
|
||||
|
||||
@@ -39,6 +39,10 @@ h1 a:hover {
|
||||
color: #319cff;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #800080;
|
||||
}
|
||||
|
||||
header,
|
||||
#summary {
|
||||
padding-left: 5%;
|
||||
@@ -426,7 +430,7 @@ footer {
|
||||
</footer>
|
||||
<script>
|
||||
var filterEl = document.getElementById('filter');
|
||||
filterEl.focus();
|
||||
filterEl.focus({ preventScroll: true });
|
||||
|
||||
function initFilter() {
|
||||
if (!filterEl.value) {
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
"github.com/dustin/go-humanize"
|
||||
)
|
||||
|
||||
func (fsrv *FileServer) directoryListing(files []os.FileInfo, canGoUp bool, root, urlPath string, repl *caddy.Replacer) browseTemplateContext {
|
||||
func (fsrv *FileServer) directoryListing(files []os.FileInfo, canGoUp bool, root, urlPath string, repl *caddy.Replacer) (browseTemplateContext, error) {
|
||||
filesToHide := fsrv.transformHidePaths(repl)
|
||||
|
||||
var dirCount, fileCount int
|
||||
@@ -42,20 +42,31 @@ func (fsrv *FileServer) directoryListing(files []os.FileInfo, canGoUp bool, root
|
||||
|
||||
isDir := f.IsDir() || isSymlinkTargetDir(f, root, urlPath)
|
||||
|
||||
u := url.URL{Path: url.PathEscape(name)}
|
||||
|
||||
// add the slash after the escape of path to avoid escaping the slash as well
|
||||
if isDir {
|
||||
name += "/"
|
||||
u.Path += "/"
|
||||
dirCount++
|
||||
} else {
|
||||
fileCount++
|
||||
}
|
||||
|
||||
u := url.URL{Path: "./" + name} // prepend with "./" to fix paths with ':' in the name
|
||||
fileIsSymlink := isSymlink(f)
|
||||
size := f.Size()
|
||||
if fileIsSymlink {
|
||||
info, err := os.Stat(name)
|
||||
if err != nil {
|
||||
return browseTemplateContext{}, err
|
||||
}
|
||||
size = info.Size()
|
||||
}
|
||||
|
||||
fileInfos = append(fileInfos, fileInfo{
|
||||
IsDir: isDir,
|
||||
IsSymlink: isSymlink(f),
|
||||
Name: f.Name(),
|
||||
Size: f.Size(),
|
||||
IsSymlink: fileIsSymlink,
|
||||
Name: name,
|
||||
Size: size,
|
||||
URL: u.String(),
|
||||
ModTime: f.ModTime().UTC(),
|
||||
Mode: f.Mode(),
|
||||
@@ -69,7 +80,7 @@ func (fsrv *FileServer) directoryListing(files []os.FileInfo, canGoUp bool, root
|
||||
Items: fileInfos,
|
||||
NumDirs: dirCount,
|
||||
NumFiles: fileCount,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// browseTemplateContext provides the template context for directory listings.
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -60,7 +61,11 @@ type MatchFile struct {
|
||||
// directories are treated distinctly, so to match
|
||||
// a directory, the filepath MUST end in a forward
|
||||
// slash `/`. To match a regular file, there must
|
||||
// be no trailing slash. Accepts placeholders.
|
||||
// be no trailing slash. Accepts placeholders. If
|
||||
// the policy is "first_exist", then an error may
|
||||
// be triggered as a fallback by configuring "="
|
||||
// followed by a status code number,
|
||||
// for example "=404".
|
||||
TryFiles []string `json:"try_files,omitempty"`
|
||||
|
||||
// How to choose a file in TryFiles. Can be:
|
||||
@@ -205,6 +210,10 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) {
|
||||
switch m.TryPolicy {
|
||||
case "", tryPolicyFirstExist:
|
||||
for _, f := range m.TryFiles {
|
||||
if err := parseErrorCode(f); err != nil {
|
||||
caddyhttp.SetVar(r.Context(), caddyhttp.MatcherErrorVarKey, err)
|
||||
return
|
||||
}
|
||||
suffix, fullpath, remainder := prepareFilePath(f)
|
||||
if info, exists := strictFileExists(fullpath); exists {
|
||||
setPlaceholders(info, suffix, fullpath, remainder)
|
||||
@@ -274,6 +283,20 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// parseErrorCode checks if the input is a status
|
||||
// code number, prefixed by "=", and returns an
|
||||
// error if so.
|
||||
func parseErrorCode(input string) error {
|
||||
if len(input) > 1 && input[0] == '=' {
|
||||
code, err := strconv.Atoi(input[1:])
|
||||
if err != nil || code < 100 || code > 999 {
|
||||
return nil
|
||||
}
|
||||
return caddyhttp.Error(code, fmt.Errorf("%s", input[1:]))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// strictFileExists returns true if file exists
|
||||
// and matches the convention of the given file
|
||||
// path. If the path ends in a forward slash,
|
||||
|
||||
@@ -17,12 +17,31 @@ package fileserver
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
)
|
||||
|
||||
func TestFileMatcher(t *testing.T) {
|
||||
|
||||
// Windows doesn't like colons in files names
|
||||
isWindows := runtime.GOOS == "windows"
|
||||
if !isWindows {
|
||||
filename := "with:in-name.txt"
|
||||
f, err := os.Create("./testdata/" + filename)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
os.Remove("./testdata/" + filename)
|
||||
})
|
||||
f.WriteString(filename)
|
||||
f.Close()
|
||||
}
|
||||
|
||||
for i, tc := range []struct {
|
||||
path string
|
||||
expectedPath string
|
||||
@@ -63,6 +82,30 @@ func TestFileMatcher(t *testing.T) {
|
||||
path: "/missingfile.php",
|
||||
matched: false,
|
||||
},
|
||||
{
|
||||
path: "ملف.txt", // the path file name is not escaped
|
||||
expectedPath: "ملف.txt",
|
||||
expectedType: "file",
|
||||
matched: true,
|
||||
},
|
||||
{
|
||||
path: url.PathEscape("ملف.txt"), // singly-escaped path
|
||||
expectedPath: "ملف.txt",
|
||||
expectedType: "file",
|
||||
matched: true,
|
||||
},
|
||||
{
|
||||
path: url.PathEscape(url.PathEscape("ملف.txt")), // doubly-escaped path
|
||||
expectedPath: "%D9%85%D9%84%D9%81.txt",
|
||||
expectedType: "file",
|
||||
matched: true,
|
||||
},
|
||||
{
|
||||
path: "./with:in-name.txt", // browsers send the request with the path as such
|
||||
expectedPath: "with:in-name.txt",
|
||||
expectedType: "file",
|
||||
matched: !isWindows,
|
||||
},
|
||||
} {
|
||||
m := &MatchFile{
|
||||
Root: "./testdata",
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
weakrand "math/rand"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -165,6 +166,16 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
|
||||
filesToHide := fsrv.transformHidePaths(repl)
|
||||
|
||||
root := repl.ReplaceAll(fsrv.Root, ".")
|
||||
// PathUnescape returns an error if the escapes aren't well-formed,
|
||||
// meaning the count % matches the RFC. Return early if the escape is
|
||||
// improper.
|
||||
if _, err := url.PathUnescape(r.URL.Path); err != nil {
|
||||
fsrv.logger.Debug("improper path escape",
|
||||
zap.String("site_root", root),
|
||||
zap.String("request_path", r.URL.Path),
|
||||
zap.Error(err))
|
||||
return err
|
||||
}
|
||||
filename := caddyhttp.SanitizedPathJoin(root, r.URL.Path)
|
||||
|
||||
fsrv.logger.Debug("sanitized path join",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
%D9%85%D9%84%D9%81.txt
|
||||
@@ -0,0 +1 @@
|
||||
ملف.txt
|
||||
@@ -213,7 +213,7 @@ func (ops HeaderOps) ApplyTo(hdr http.Header, repl *caddy.Replacer) {
|
||||
|
||||
// replace
|
||||
for fieldName, replacements := range ops.Replace {
|
||||
fieldName = repl.ReplaceAll(fieldName, "")
|
||||
fieldName = http.CanonicalHeaderKey(repl.ReplaceAll(fieldName, ""))
|
||||
|
||||
// all fields...
|
||||
if fieldName == "*" {
|
||||
@@ -237,11 +237,17 @@ func (ops HeaderOps) ApplyTo(hdr http.Header, repl *caddy.Replacer) {
|
||||
for _, r := range replacements {
|
||||
search := repl.ReplaceAll(r.Search, "")
|
||||
replace := repl.ReplaceAll(r.Replace, "")
|
||||
for i := range hdr[fieldName] {
|
||||
if r.re != nil {
|
||||
hdr[fieldName][i] = r.re.ReplaceAllString(hdr[fieldName][i], replace)
|
||||
} else {
|
||||
hdr[fieldName][i] = strings.ReplaceAll(hdr[fieldName][i], search, replace)
|
||||
for hdrFieldName, vals := range hdr {
|
||||
// see issue #4330 for why we don't simply use hdr[fieldName]
|
||||
if http.CanonicalHeaderKey(hdrFieldName) != fieldName {
|
||||
continue
|
||||
}
|
||||
for i := range vals {
|
||||
if r.re != nil {
|
||||
hdr[hdrFieldName][i] = r.re.ReplaceAllString(hdr[hdrFieldName][i], replace)
|
||||
} else {
|
||||
hdr[hdrFieldName][i] = strings.ReplaceAll(hdr[hdrFieldName][i], search, replace)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,6 +160,28 @@ func TestHandler(t *testing.T) {
|
||||
"Fail-5xx": []string{"true"},
|
||||
},
|
||||
},
|
||||
{
|
||||
handler: Handler{
|
||||
Request: &HeaderOps{
|
||||
Replace: map[string][]Replacement{
|
||||
"Case-Insensitive": {
|
||||
Replacement{
|
||||
Search: "issue4330",
|
||||
Replace: "issue #4330",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
reqHeader: http.Header{
|
||||
"case-insensitive": []string{"issue4330"},
|
||||
"Other-Header": []string{"issue4330"},
|
||||
},
|
||||
expectedReqHeader: http.Header{
|
||||
"case-insensitive": []string{"issue #4330"},
|
||||
"Other-Header": []string{"issue4330"},
|
||||
},
|
||||
},
|
||||
} {
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
@@ -191,7 +213,7 @@ func TestHandler(t *testing.T) {
|
||||
})
|
||||
|
||||
if err := tc.handler.ServeHTTP(rr, req, next); err != nil {
|
||||
t.Errorf("Test %d: %w", i, err)
|
||||
t.Errorf("Test %d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -131,23 +131,21 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhtt
|
||||
// find the first mapping matching the input and return
|
||||
// the requested destination/output value
|
||||
for _, m := range h.Mappings {
|
||||
if m.re != nil {
|
||||
if m.re.MatchString(input) {
|
||||
if output := m.Outputs[destIdx]; output == nil {
|
||||
continue
|
||||
} else {
|
||||
output = m.re.ReplaceAllString(input, m.Outputs[destIdx].(string))
|
||||
return output, true
|
||||
}
|
||||
}
|
||||
output := m.Outputs[destIdx]
|
||||
if output == nil {
|
||||
continue
|
||||
}
|
||||
if input == m.Input {
|
||||
if output := m.Outputs[destIdx]; output == nil {
|
||||
if m.re != nil {
|
||||
var result []byte
|
||||
matches := m.re.FindStringSubmatchIndex(input)
|
||||
if matches == nil {
|
||||
continue
|
||||
} else {
|
||||
return output, true
|
||||
}
|
||||
result = m.re.ExpandString(result, output.(string), input, matches)
|
||||
return string(result), true
|
||||
}
|
||||
if input == m.Input {
|
||||
return output, true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package maphandler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
)
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
for i, tc := range []struct {
|
||||
handler Handler
|
||||
reqURI string
|
||||
expect map[string]interface{}
|
||||
}{
|
||||
{
|
||||
reqURI: "/foo",
|
||||
handler: Handler{
|
||||
Source: "{http.request.uri.path}",
|
||||
Destinations: []string{"{output}"},
|
||||
Mappings: []Mapping{
|
||||
{
|
||||
Input: "/foo",
|
||||
Outputs: []interface{}{"FOO"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: map[string]interface{}{
|
||||
"output": "FOO",
|
||||
},
|
||||
},
|
||||
{
|
||||
reqURI: "/abcdef",
|
||||
handler: Handler{
|
||||
Source: "{http.request.uri.path}",
|
||||
Destinations: []string{"{output}"},
|
||||
Mappings: []Mapping{
|
||||
{
|
||||
InputRegexp: "(/abc)",
|
||||
Outputs: []interface{}{"ABC"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: map[string]interface{}{
|
||||
"output": "ABC",
|
||||
},
|
||||
},
|
||||
{
|
||||
reqURI: "/ABCxyzDEF",
|
||||
handler: Handler{
|
||||
Source: "{http.request.uri.path}",
|
||||
Destinations: []string{"{output}"},
|
||||
Mappings: []Mapping{
|
||||
{
|
||||
InputRegexp: "(xyz)",
|
||||
Outputs: []interface{}{"...${1}..."},
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: map[string]interface{}{
|
||||
"output": "...xyz...",
|
||||
},
|
||||
},
|
||||
{
|
||||
// Test case from https://caddy.community/t/map-directive-and-regular-expressions/13866/14?u=matt
|
||||
reqURI: "/?s=0%27+AND+%28SELECT+0+FROM+%28SELECT+count%28%2A%29%2C+CONCAT%28%28SELECT+%40%40version%29%2C+0x23%2C+FLOOR%28RAND%280%29%2A2%29%29+AS+x+FROM+information_schema.columns+GROUP+BY+x%29+y%29+-+-+%27",
|
||||
handler: Handler{
|
||||
Source: "{http.request.uri}",
|
||||
Destinations: []string{"{output}"},
|
||||
Mappings: []Mapping{
|
||||
{
|
||||
InputRegexp: "(?i)(\\^|`|<|>|%|\\\\|\\{|\\}|\\|)",
|
||||
Outputs: []interface{}{"3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expect: map[string]interface{}{
|
||||
"output": "3",
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := tc.handler.Provision(caddy.Context{}); err != nil {
|
||||
t.Fatalf("Test %d: Provisioning handler: %v", i, err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, tc.reqURI, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Test %d: Creating request: %v", i, err)
|
||||
}
|
||||
repl := caddyhttp.NewTestReplacer(req)
|
||||
ctx := context.WithValue(req.Context(), caddy.ReplacerCtxKey, repl)
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
noop := caddyhttp.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) error { return nil })
|
||||
|
||||
if err := tc.handler.ServeHTTP(rr, req, noop); err != nil {
|
||||
t.Errorf("Test %d: Handler returned error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for key, expected := range tc.expect {
|
||||
actual, _ := repl.Get(key)
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("Test %d: Expected %#v but got %#v for {%s}", i, expected, actual, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
@@ -97,7 +98,8 @@ type (
|
||||
// ```
|
||||
MatchQuery url.Values
|
||||
|
||||
// MatchHeader matches requests by header fields. It performs fast,
|
||||
// MatchHeader matches requests by header fields. The key is the field
|
||||
// name and the array is the list of field values. It performs fast,
|
||||
// exact string comparisons of the field values. Fast prefix, suffix,
|
||||
// and substring matches can also be done by suffixing, prefixing, or
|
||||
// surrounding the value with the wildcard `*` character, respectively.
|
||||
@@ -114,7 +116,8 @@ type (
|
||||
// (potentially leading to collisions).
|
||||
MatchHeaderRE map[string]*MatchRegexp
|
||||
|
||||
// MatchProtocol matches requests by protocol.
|
||||
// MatchProtocol matches requests by protocol. Recognized values are
|
||||
// "http", "https", and "grpc".
|
||||
MatchProtocol string
|
||||
|
||||
// MatchRemoteIP matches requests by client IP (or CIDR range).
|
||||
@@ -139,9 +142,9 @@ type (
|
||||
// matchers within a set work the same (i.e. different matchers in
|
||||
// the same set are AND'ed).
|
||||
//
|
||||
// Note that the generated docs which describe the structure of
|
||||
// this module are wrong because of how this type unmarshals JSON
|
||||
// in a custom way. The correct structure is:
|
||||
// NOTE: The generated docs which describe the structure of this
|
||||
// module are wrong because of how this type unmarshals JSON in a
|
||||
// custom way. The correct structure is:
|
||||
//
|
||||
// ```json
|
||||
// [
|
||||
@@ -312,7 +315,15 @@ func (m MatchPath) Provision(_ caddy.Context) error {
|
||||
|
||||
// Match returns true if r matches m.
|
||||
func (m MatchPath) Match(r *http.Request) bool {
|
||||
lowerPath := strings.ToLower(r.URL.Path)
|
||||
// PathUnescape returns an error if the escapes aren't
|
||||
// well-formed, meaning the count % matches the RFC.
|
||||
// Return early if the escape is improper.
|
||||
unescapedPath, err := url.PathUnescape(r.URL.Path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
lowerPath := strings.ToLower(unescapedPath)
|
||||
|
||||
// see #2917; Windows ignores trailing dots and spaces
|
||||
// when accessing files (sigh), potentially causing a
|
||||
@@ -321,6 +332,16 @@ func (m MatchPath) Match(r *http.Request) bool {
|
||||
// being matched by *.php to be treated as PHP scripts
|
||||
lowerPath = strings.TrimRight(lowerPath, ". ")
|
||||
|
||||
// Clean the path, merges doubled slashes, etc.
|
||||
// This ensures maliciously crafted requests can't bypass
|
||||
// the path matcher. See #4407
|
||||
lowerPath = path.Clean(lowerPath)
|
||||
|
||||
// Cleaning may remove the trailing slash, but we want to keep it
|
||||
if lowerPath != "/" && strings.HasSuffix(r.URL.Path, "/") {
|
||||
lowerPath = lowerPath + "/"
|
||||
}
|
||||
|
||||
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
|
||||
|
||||
for _, matchPath := range m {
|
||||
@@ -394,7 +415,26 @@ func (MatchPathRE) CaddyModule() caddy.ModuleInfo {
|
||||
// Match returns true if r matches m.
|
||||
func (m MatchPathRE) Match(r *http.Request) bool {
|
||||
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
|
||||
return m.MatchRegexp.Match(r.URL.Path, repl)
|
||||
|
||||
// PathUnescape returns an error if the escapes aren't
|
||||
// well-formed, meaning the count % matches the RFC.
|
||||
// Return early if the escape is improper.
|
||||
unescapedPath, err := url.PathUnescape(r.URL.Path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Clean the path, merges doubled slashes, etc.
|
||||
// This ensures maliciously crafted requests can't bypass
|
||||
// the path matcher. See #4407
|
||||
cleanedPath := path.Clean(unescapedPath)
|
||||
|
||||
// Cleaning may remove the trailing slash, but we want to keep it
|
||||
if cleanedPath != "/" && strings.HasSuffix(r.URL.Path, "/") {
|
||||
cleanedPath = cleanedPath + "/"
|
||||
}
|
||||
|
||||
return m.MatchRegexp.Match(cleanedPath, repl)
|
||||
}
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
@@ -987,6 +1027,12 @@ var wordRE = regexp.MustCompile(`\w+`)
|
||||
|
||||
const regexpPlaceholderPrefix = "http.regexp"
|
||||
|
||||
// MatcherErrorVarKey is the key used for the variable that
|
||||
// holds an optional error emitted from a request matcher,
|
||||
// to short-circuit the handler chain, since matchers cannot
|
||||
// return errors via the RequestMatcher interface.
|
||||
const MatcherErrorVarKey = "matchers.error"
|
||||
|
||||
// Interface guards
|
||||
var (
|
||||
_ RequestMatcher = (*MatchHost)(nil)
|
||||
|
||||
@@ -257,6 +257,21 @@ func TestPathMatcher(t *testing.T) {
|
||||
input: "/foo/BAR.txt",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
match: MatchPath{"/foo*"},
|
||||
input: "//foo/bar",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
match: MatchPath{"/foo*"},
|
||||
input: "//foo",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
match: MatchPath{"/foo*"},
|
||||
input: "/%2F/foo",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
match: MatchPath{"*"},
|
||||
input: "/",
|
||||
@@ -326,15 +341,30 @@ func TestPathREMatcher(t *testing.T) {
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
match: MatchPathRE{MatchRegexp{Pattern: "/foo"}},
|
||||
match: MatchPathRE{MatchRegexp{Pattern: "^/foo"}},
|
||||
input: "/foo",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
match: MatchPathRE{MatchRegexp{Pattern: "/foo"}},
|
||||
match: MatchPathRE{MatchRegexp{Pattern: "^/foo"}},
|
||||
input: "/foo/",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
match: MatchPathRE{MatchRegexp{Pattern: "^/foo"}},
|
||||
input: "//foo",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
match: MatchPathRE{MatchRegexp{Pattern: "^/foo"}},
|
||||
input: "//foo/",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
match: MatchPathRE{MatchRegexp{Pattern: "^/foo"}},
|
||||
input: "/%2F/foo/",
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
match: MatchPathRE{MatchRegexp{Pattern: "/bar"}},
|
||||
input: "/foo/",
|
||||
|
||||
@@ -55,7 +55,7 @@ func TestMetricsInstrumentedHandler(t *testing.T) {
|
||||
|
||||
handlerErr = nil
|
||||
if err := ih.ServeHTTP(w, r, h); err != nil {
|
||||
t.Errorf("Received unexpected error: %w", err)
|
||||
t.Errorf("Received unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// an empty handler - no errors, no header written
|
||||
@@ -67,7 +67,7 @@ func TestMetricsInstrumentedHandler(t *testing.T) {
|
||||
w = httptest.NewRecorder()
|
||||
|
||||
if err := ih.ServeHTTP(w, r, h); err != nil {
|
||||
t.Errorf("Received unexpected error: %w", err)
|
||||
t.Errorf("Received unexpected error: %v", err)
|
||||
}
|
||||
if actual := w.Result().StatusCode; actual != 200 {
|
||||
t.Errorf("Not same: expected status code %#v, but got %#v", 200, actual)
|
||||
|
||||
@@ -25,10 +25,10 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
@@ -162,7 +162,7 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
|
||||
return "", true
|
||||
}
|
||||
// replace real body with buffered data
|
||||
req.Body = ioutil.NopCloser(buf)
|
||||
req.Body = io.NopCloser(buf)
|
||||
return buf.String(), true
|
||||
|
||||
// original request, before any internal changes
|
||||
@@ -353,6 +353,8 @@ func getReqTLSReplacement(req *http.Request, key string) (interface{}, bool) {
|
||||
case "client.certificate_pem":
|
||||
block := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}
|
||||
return pem.EncodeToMemory(&block), true
|
||||
case "client.certificate_der_base64":
|
||||
return base64.StdEncoding.EncodeToString(cert.Raw), true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ type ResponseMatcher struct {
|
||||
|
||||
// If set, each header specified must be one of the
|
||||
// specified values, with the same logic used by the
|
||||
// request header matcher.
|
||||
// [request header matcher](/docs/json/apps/http/servers/routes/match/header/).
|
||||
Headers http.Header `json:"headers,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ default, all incoming headers are passed through unmodified.)
|
||||
fs.String("from", "localhost", "Address on which to receive traffic")
|
||||
fs.String("to", "", "Upstream address to which to to proxy traffic")
|
||||
fs.Bool("change-host-header", false, "Set upstream Host header to address of upstream")
|
||||
fs.Bool("insecure", false, "Disable TLS verification (WARNING: DISABLES SECURITY, WHY ARE YOU EVEN USING TLS?)")
|
||||
fs.Bool("insecure", false, "Disable TLS verification (WARNING: DISABLES SECURITY BY NOT VERIFYING SSL CERTIFICATES!)")
|
||||
return fs
|
||||
}(),
|
||||
})
|
||||
|
||||
@@ -124,21 +124,22 @@ func (t *Transport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
//
|
||||
// is equivalent to a route consisting of:
|
||||
//
|
||||
// # Add trailing slash for directory requests
|
||||
// @canonicalPath {
|
||||
// file {
|
||||
// try_files {path}/index.php
|
||||
// }
|
||||
// not {
|
||||
// path */
|
||||
// }
|
||||
// file {path}/index.php
|
||||
// not path */
|
||||
// }
|
||||
// redir @canonicalPath {path}/ 308
|
||||
//
|
||||
// try_files {path} {path}/index.php index.php
|
||||
//
|
||||
// @phpFiles {
|
||||
// path *.php
|
||||
// # If the requested file does not exist, try index files
|
||||
// @indexFiles file {
|
||||
// try_files {path} {path}/index.php index.php
|
||||
// split_path .php
|
||||
// }
|
||||
// rewrite @indexFiles {http.matchers.file.relative}
|
||||
//
|
||||
// # Proxy PHP files to the FastCGI responder
|
||||
// @phpFiles path *.php
|
||||
// reverse_proxy @phpFiles localhost:7777 {
|
||||
// transport fastcgi {
|
||||
// split .php
|
||||
@@ -172,6 +173,9 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
||||
// set the default index file for the try_files rewrites
|
||||
indexFile := "index.php"
|
||||
|
||||
// set up for explicitly overriding try_files
|
||||
tryFiles := []string{}
|
||||
|
||||
// if the user specified a matcher token, use that
|
||||
// matcher in a route that wraps both of our routes;
|
||||
// either way, strip the matcher token and pass
|
||||
@@ -237,6 +241,17 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
||||
}
|
||||
indexFile = args[0]
|
||||
|
||||
case "try_files":
|
||||
args := dispenser.RemainingArgs()
|
||||
dispenser.Delete()
|
||||
for range args {
|
||||
dispenser.Delete()
|
||||
}
|
||||
if len(args) < 1 {
|
||||
return nil, dispenser.ArgErr()
|
||||
}
|
||||
tryFiles = args
|
||||
|
||||
case "resolve_root_symlink":
|
||||
args := dispenser.RemainingArgs()
|
||||
dispenser.Delete()
|
||||
@@ -318,10 +333,15 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
||||
HandlersRaw: []json.RawMessage{caddyconfig.JSONModuleObject(redirHandler, "handler", "static_response", nil)},
|
||||
}
|
||||
|
||||
// if tryFiles wasn't overridden, use a reasonable default
|
||||
if len(tryFiles) == 0 {
|
||||
tryFiles = []string{"{http.request.uri.path}", "{http.request.uri.path}/" + indexFile, indexFile}
|
||||
}
|
||||
|
||||
// route to rewrite to PHP index file
|
||||
rewriteMatcherSet := caddy.ModuleMap{
|
||||
"file": h.JSON(fileserver.MatchFile{
|
||||
TryFiles: []string{"{http.request.uri.path}", "{http.request.uri.path}/" + indexFile, indexFile},
|
||||
TryFiles: tryFiles,
|
||||
SplitPath: extensions,
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -445,7 +444,7 @@ func (c *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http.Res
|
||||
if chunked(resp.TransferEncoding) {
|
||||
resp.Body = clientCloser{c, httputil.NewChunkedReader(rb)}
|
||||
} else {
|
||||
resp.Body = clientCloser{c, ioutil.NopCloser(rb)}
|
||||
resp.Body = clientCloser{c, io.NopCloser(rb)}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
@@ -166,7 +165,7 @@ func sendFcgi(reqType int, fcgiParams map[string]string, data []byte, posts map[
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
content, _ = ioutil.ReadAll(resp.Body)
|
||||
content, _ = io.ReadAll(resp.Body)
|
||||
|
||||
log.Println("c: send data length ≈", length, string(content))
|
||||
fcgi.Close()
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -282,7 +281,7 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, host H
|
||||
}
|
||||
defer func() {
|
||||
// drain any remaining body so connection could be re-used
|
||||
_, _ = io.Copy(ioutil.Discard, body)
|
||||
_, _ = io.Copy(io.Discard, body)
|
||||
resp.Body.Close()
|
||||
}()
|
||||
|
||||
@@ -313,7 +312,7 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, host H
|
||||
|
||||
// if body does not match regex, mark down
|
||||
if h.HealthChecks.Active.bodyRegexp != nil {
|
||||
bodyBytes, err := ioutil.ReadAll(body)
|
||||
bodyBytes, err := io.ReadAll(body)
|
||||
if err != nil {
|
||||
h.HealthChecks.Active.logger.Info("failed to read response body",
|
||||
zap.String("host", hostAddr),
|
||||
|
||||
@@ -20,10 +20,10 @@ import (
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
weakrand "math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
@@ -364,7 +364,7 @@ func (t TLSConfig) MakeTLSClientConfig(ctx caddy.Context) (*tls.Config, error) {
|
||||
rootPool.AddCert(caCert)
|
||||
}
|
||||
for _, pemFile := range t.RootCAPEMFiles {
|
||||
pemData, err := ioutil.ReadFile(pemFile)
|
||||
pemData, err := os.ReadFile(pemFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed reading ca cert: %v", err)
|
||||
}
|
||||
|
||||
@@ -395,9 +395,23 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht
|
||||
// should not permanently change r.Host; issue #3509)
|
||||
reqHost := r.Host
|
||||
reqHeader := r.Header
|
||||
|
||||
// sanitize the request URL; we expect it to not contain the scheme and host
|
||||
// since those should be determined by r.TLS and r.Host respectively, but
|
||||
// some clients may include it in the request-line, which is technically
|
||||
// valid in HTTP, but breaks reverseproxy behaviour, overriding how the
|
||||
// dialer will behave. See #4237 for context.
|
||||
origURLScheme := r.URL.Scheme
|
||||
origURLHost := r.URL.Host
|
||||
r.URL.Scheme = ""
|
||||
r.URL.Host = ""
|
||||
|
||||
// restore modifications to the request after we're done proxying
|
||||
defer func() {
|
||||
r.Host = reqHost // TODO: data race, see #4038
|
||||
r.Header = reqHeader // TODO: data race, see #4038
|
||||
r.URL.Scheme = origURLScheme
|
||||
r.URL.Host = origURLHost
|
||||
}()
|
||||
|
||||
start := time.Now()
|
||||
@@ -574,12 +588,11 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, repl *
|
||||
duration := time.Since(start)
|
||||
logger := h.logger.With(
|
||||
zap.String("upstream", di.Upstream.String()),
|
||||
zap.Duration("duration", duration),
|
||||
zap.Object("request", caddyhttp.LoggableHTTPRequest{Request: req}),
|
||||
)
|
||||
if err != nil {
|
||||
logger.Debug("upstream roundtrip",
|
||||
zap.Duration("duration", duration),
|
||||
zap.Error(err))
|
||||
logger.Debug("upstream roundtrip", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
logger.Debug("upstream roundtrip",
|
||||
@@ -615,6 +628,11 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, repl *
|
||||
res.Body = h.bufferedBody(res.Body)
|
||||
}
|
||||
|
||||
// the response body may get closed by a response handler,
|
||||
// and we need to keep track to make sure we don't try to copy
|
||||
// the response if it was already closed
|
||||
bodyClosed := false
|
||||
|
||||
// see if any response handler is configured for this response from the backend
|
||||
for i, rh := range h.HandleResponse {
|
||||
if rh.Match != nil && !rh.Match.Match(res.StatusCode, res.Header) {
|
||||
@@ -639,8 +657,6 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, repl *
|
||||
continue
|
||||
}
|
||||
|
||||
res.Body.Close()
|
||||
|
||||
// set up the replacer so that parts of the original response can be
|
||||
// used for routing decisions
|
||||
for field, value := range res.Header {
|
||||
@@ -650,7 +666,17 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, repl *
|
||||
repl.Set("http.reverse_proxy.status_text", res.Status)
|
||||
|
||||
h.logger.Debug("handling response", zap.Int("handler", i))
|
||||
if routeErr := rh.Routes.Compile(next).ServeHTTP(rw, req); routeErr != nil {
|
||||
|
||||
// pass the request through the response handler routes
|
||||
routeErr := rh.Routes.Compile(next).ServeHTTP(rw, req)
|
||||
|
||||
// always close the response body afterwards since it's expected
|
||||
// that the response handler routes will have written to the
|
||||
// response writer with a new body
|
||||
res.Body.Close()
|
||||
bodyClosed = true
|
||||
|
||||
if routeErr != nil {
|
||||
// wrap error in roundtripSucceeded so caller knows that
|
||||
// the roundtrip was successful and to not retry
|
||||
return roundtripSucceeded{routeErr}
|
||||
@@ -691,15 +717,17 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, repl *
|
||||
}
|
||||
|
||||
rw.WriteHeader(res.StatusCode)
|
||||
err = h.copyResponse(rw, res.Body, h.flushInterval(req, res))
|
||||
res.Body.Close() // close now, instead of defer, to populate res.Trailer
|
||||
if err != nil {
|
||||
// we're streaming the response and we've already written headers, so
|
||||
// there's nothing an error handler can do to recover at this point;
|
||||
// the standard lib's proxy panics at this point, but we'll just log
|
||||
// the error and abort the stream here
|
||||
h.logger.Error("aborting with incomplete response", zap.Error(err))
|
||||
return nil
|
||||
if !bodyClosed {
|
||||
err = h.copyResponse(rw, res.Body, h.flushInterval(req, res))
|
||||
res.Body.Close() // close now, instead of defer, to populate res.Trailer
|
||||
if err != nil {
|
||||
// we're streaming the response and we've already written headers, so
|
||||
// there's nothing an error handler can do to recover at this point;
|
||||
// the standard lib's proxy panics at this point, but we'll just log
|
||||
// the error and abort the stream here
|
||||
h.logger.Error("aborting with incomplete response", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(res.Trailer) > 0 {
|
||||
|
||||
@@ -200,6 +200,15 @@ func wrapRoute(route Route) Middleware {
|
||||
|
||||
// route must match at least one of the matcher sets
|
||||
if !route.MatcherSets.AnyMatch(req) {
|
||||
// allow matchers the opportunity to short circuit
|
||||
// the request and trigger the error handling chain
|
||||
err, ok := GetVar(req.Context(), MatcherErrorVarKey).(error)
|
||||
if ok {
|
||||
return err
|
||||
}
|
||||
|
||||
// call the next handler, and skip this one,
|
||||
// since the matcher didn't match
|
||||
return nextCopy.ServeHTTP(rw, req)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ package caddyhttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
@@ -44,7 +44,7 @@ func TestStaticResponseHandler(t *testing.T) {
|
||||
}
|
||||
|
||||
resp := w.Result()
|
||||
respBody, _ := ioutil.ReadAll(resp.Body)
|
||||
respBody, _ := io.ReadAll(resp.Body)
|
||||
|
||||
if resp.StatusCode != http.StatusNotFound {
|
||||
t.Errorf("expected status %d but got %d", http.StatusNotFound, resp.StatusCode)
|
||||
|
||||
@@ -16,6 +16,7 @@ package templates
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -90,9 +91,25 @@ func init() {
|
||||
// {{httpInclude "/foo/bar?q=val"}}
|
||||
// ```
|
||||
//
|
||||
// ##### `import`
|
||||
//
|
||||
// Imports the contents of another file and adds any template definitions to the template stack. If there are no defitions, the filepath will be the defition name. Any {{ define }} blocks will be accessible by {{ template }} or {{ block }}. Imports must happen before the template or block action is called
|
||||
//
|
||||
// **filename.html**
|
||||
// ```
|
||||
// {{ define "main" }}
|
||||
// content
|
||||
// {{ end }}
|
||||
//
|
||||
// **index.html**
|
||||
// ```
|
||||
// {{ import "/path/to/file.html" }}
|
||||
// {{ template "main" }}
|
||||
// ```
|
||||
//
|
||||
// ##### `include`
|
||||
//
|
||||
// Includes the contents of another file. Optionally can pass key-value pairs as arguments to be accessed by the included file.
|
||||
// Includes the contents of another file and renders in-place. Optionally can pass key-value pairs as arguments to be accessed by the included file.
|
||||
//
|
||||
// ```
|
||||
// {{include "path/to/file.html"}} // no arguments
|
||||
@@ -220,7 +237,8 @@ type Templates struct {
|
||||
// Default is text/plain, text/markdown, and text/html.
|
||||
MIMETypes []string `json:"mime_types,omitempty"`
|
||||
|
||||
// The template action delimiters.
|
||||
// The template action delimiters. If set, must be precisely two elements:
|
||||
// the opening and closing delimiters. Default: `["{{", "}}"]`
|
||||
Delimiters []string `json:"delimiters,omitempty"`
|
||||
}
|
||||
|
||||
@@ -312,6 +330,12 @@ func (t *Templates) executeTemplate(rr caddyhttp.ResponseRecorder, r *http.Reque
|
||||
|
||||
err := ctx.executeTemplateInBuffer(r.URL.Path, rr.Buffer())
|
||||
if err != nil {
|
||||
// templates may return a custom HTTP error to be propagated to the client,
|
||||
// otherwise for any other error we assume the template is broken
|
||||
var handlerErr caddyhttp.HandlerError
|
||||
if errors.As(err, &handlerErr) {
|
||||
return handlerErr
|
||||
}
|
||||
return caddyhttp.Error(http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -46,24 +46,26 @@ type TemplateContext struct {
|
||||
RespHeader WrappedHeader
|
||||
|
||||
config *Templates
|
||||
tpl *template.Template
|
||||
}
|
||||
|
||||
// NewTemplate returns a new template intended to be evaluated with this
|
||||
// context, as it is initialized with configuration from this context.
|
||||
func (c TemplateContext) NewTemplate(tplName string) *template.Template {
|
||||
tpl := template.New(tplName)
|
||||
func (c *TemplateContext) NewTemplate(tplName string) *template.Template {
|
||||
c.tpl = template.New(tplName)
|
||||
|
||||
// customize delimiters, if applicable
|
||||
if c.config != nil && len(c.config.Delimiters) == 2 {
|
||||
tpl.Delims(c.config.Delimiters[0], c.config.Delimiters[1])
|
||||
c.tpl.Delims(c.config.Delimiters[0], c.config.Delimiters[1])
|
||||
}
|
||||
|
||||
// add sprig library
|
||||
tpl.Funcs(sprigFuncMap)
|
||||
c.tpl.Funcs(sprigFuncMap)
|
||||
|
||||
// add our own library
|
||||
tpl.Funcs(template.FuncMap{
|
||||
c.tpl.Funcs(template.FuncMap{
|
||||
"include": c.funcInclude,
|
||||
"import": c.funcImport,
|
||||
"httpInclude": c.funcHTTPInclude,
|
||||
"stripHTML": c.funcStripHTML,
|
||||
"markdown": c.funcMarkdown,
|
||||
@@ -74,8 +76,7 @@ func (c TemplateContext) NewTemplate(tplName string) *template.Template {
|
||||
"fileExists": c.funcFileExists,
|
||||
"httpError": c.funcHTTPError,
|
||||
})
|
||||
|
||||
return tpl
|
||||
return c.tpl
|
||||
}
|
||||
|
||||
// OriginalReq returns the original, unmodified, un-rewritten request as
|
||||
@@ -85,26 +86,13 @@ func (c TemplateContext) OriginalReq() http.Request {
|
||||
return or
|
||||
}
|
||||
|
||||
// funcInclude returns the contents of filename relative to the site root.
|
||||
// funcInclude returns the contents of filename relative to the site root and renders it in place.
|
||||
// Note that included files are NOT escaped, so you should only include
|
||||
// trusted files. If it is not trusted, be sure to use escaping functions
|
||||
// in your template.
|
||||
func (c TemplateContext) funcInclude(filename string, args ...interface{}) (string, error) {
|
||||
if c.Root == nil {
|
||||
return "", fmt.Errorf("root file system not specified")
|
||||
}
|
||||
bodyBuf, err := c.readFileToBuffer(filename)
|
||||
|
||||
file, err := c.Root.Open(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
bodyBuf := bufPool.Get().(*bytes.Buffer)
|
||||
bodyBuf.Reset()
|
||||
defer bufPool.Put(bodyBuf)
|
||||
|
||||
_, err = io.Copy(bodyBuf, file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -119,6 +107,30 @@ func (c TemplateContext) funcInclude(filename string, args ...interface{}) (stri
|
||||
return bodyBuf.String(), nil
|
||||
}
|
||||
|
||||
// readFileToBuffer returns the contents of filename relative to root as a buffer
|
||||
func (c TemplateContext) readFileToBuffer(filename string) (*bytes.Buffer, error) {
|
||||
if c.Root == nil {
|
||||
return nil, fmt.Errorf("root file system not specified")
|
||||
}
|
||||
|
||||
file, err := c.Root.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
bodyBuf := bufPool.Get().(*bytes.Buffer)
|
||||
bodyBuf.Reset()
|
||||
defer bufPool.Put(bodyBuf)
|
||||
|
||||
_, err = io.Copy(bodyBuf, file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bodyBuf, nil
|
||||
}
|
||||
|
||||
// funcHTTPInclude returns the body of a virtual (lightweight) request
|
||||
// to the given URI on the same server. Note that included bodies
|
||||
// are NOT escaped, so you should only include trusted resources.
|
||||
@@ -148,6 +160,7 @@ func (c TemplateContext) funcHTTPInclude(uri string) (string, error) {
|
||||
}
|
||||
virtReq.Host = c.Req.Host
|
||||
virtReq.Header = c.Req.Header.Clone()
|
||||
virtReq.Header.Set("Accept-Encoding", "identity") // https://github.com/caddyserver/caddy/issues/4352
|
||||
virtReq.Trailer = c.Req.Trailer.Clone()
|
||||
virtReq.Header.Set(recursionPreventionHeader, strconv.Itoa(recursionCount))
|
||||
|
||||
@@ -167,17 +180,34 @@ func (c TemplateContext) funcHTTPInclude(uri string) (string, error) {
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func (c TemplateContext) executeTemplateInBuffer(tplName string, buf *bytes.Buffer) error {
|
||||
tpl := c.NewTemplate(tplName)
|
||||
// funcImport parses the filename into the current template stack. The imported
|
||||
// file will be rendered within the current template by calling {{ block }} or
|
||||
// {{ template }} from the standard template library. If the imported file has
|
||||
// no {{ define }} blocks, the name of the import will be the path
|
||||
func (c *TemplateContext) funcImport(filename string) (string, error) {
|
||||
bodyBuf, err := c.readFileToBuffer(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
parsedTpl, err := tpl.Parse(buf.String())
|
||||
_, err = c.tpl.Parse(bodyBuf.String())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (c *TemplateContext) executeTemplateInBuffer(tplName string, buf *bytes.Buffer) error {
|
||||
c.NewTemplate(tplName)
|
||||
|
||||
_, err := c.tpl.Parse(buf.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf.Reset() // reuse buffer for output
|
||||
|
||||
return parsedTpl.Execute(buf, c)
|
||||
return c.tpl.Execute(buf, c)
|
||||
}
|
||||
|
||||
func (c TemplateContext) funcPlaceholder(name string) string {
|
||||
@@ -350,9 +380,8 @@ func (c TemplateContext) funcFileExists(filename string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// funcHTTPError returns a structured HTTP handler error. EXPERIMENTAL.
|
||||
// TODO: Requires https://github.com/golang/go/issues/34201 to be fixed (Go 1.17).
|
||||
// Example usage might be: `{{if not (fileExists $includeFile)}}{{httpError 404}}{{end}}`
|
||||
// funcHTTPError returns a structured HTTP handler error. EXPERIMENTAL; SUBJECT TO CHANGE.
|
||||
// Example usage: `{{if not (fileExists $includeFile)}}{{httpError 404}}{{end}}`
|
||||
func (c TemplateContext) funcHTTPError(statusCode int) (bool, error) {
|
||||
return false, caddyhttp.Error(statusCode, nil)
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ package templates
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -26,10 +26,49 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
)
|
||||
|
||||
type handle struct {
|
||||
}
|
||||
|
||||
func (h *handle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get("Accept-Encoding") == "identity" {
|
||||
w.Write([]byte("good contents"))
|
||||
} else {
|
||||
w.Write([]byte("bad cause Accept-Encoding: " + r.Header.Get("Accept-Encoding")))
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPInclude(t *testing.T) {
|
||||
tplContext := getContextOrFail(t)
|
||||
for i, test := range []struct {
|
||||
uri string
|
||||
handler *handle
|
||||
expect string
|
||||
}{
|
||||
{
|
||||
uri: "https://example.com/foo/bar",
|
||||
handler: &handle{},
|
||||
expect: "good contents",
|
||||
},
|
||||
} {
|
||||
ctx := context.WithValue(tplContext.Req.Context(), caddyhttp.ServerCtxKey, test.handler)
|
||||
tplContext.Req = tplContext.Req.WithContext(ctx)
|
||||
tplContext.Req.Header.Add("Accept-Encoding", "gzip")
|
||||
result, err := tplContext.funcHTTPInclude(test.uri)
|
||||
if result != test.expect {
|
||||
t.Errorf("Test %d: expected '%s' but got '%s'", i, test.expect, result)
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("Test %d: got error: %v", i, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarkdown(t *testing.T) {
|
||||
context := getContextOrFail(t)
|
||||
tplContext := getContextOrFail(t)
|
||||
|
||||
for i, test := range []struct {
|
||||
body string
|
||||
@@ -40,7 +79,7 @@ func TestMarkdown(t *testing.T) {
|
||||
expect: "<ul>\n<li>str1</li>\n<li>str2</li>\n</ul>\n",
|
||||
},
|
||||
} {
|
||||
result, err := context.funcMarkdown(test.body)
|
||||
result, err := tplContext.funcMarkdown(test.body)
|
||||
if result != test.expect {
|
||||
t.Errorf("Test %d: expected '%s' but got '%s'", i, test.expect, result)
|
||||
}
|
||||
@@ -81,9 +120,9 @@ func TestCookie(t *testing.T) {
|
||||
expect: "cookieValue",
|
||||
},
|
||||
} {
|
||||
context := getContextOrFail(t)
|
||||
context.Req.AddCookie(test.cookie)
|
||||
actual := context.Cookie(test.cookieName)
|
||||
tplContext := getContextOrFail(t)
|
||||
tplContext.Req.AddCookie(test.cookie)
|
||||
actual := tplContext.Cookie(test.cookieName)
|
||||
if actual != test.expect {
|
||||
t.Errorf("Test %d: Expected cookie value '%s' but got '%s' for cookie with name '%s'",
|
||||
i, test.expect, actual, test.cookieName)
|
||||
@@ -91,13 +130,147 @@ func TestCookie(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestImport(t *testing.T) {
|
||||
for i, test := range []struct {
|
||||
fileContent string
|
||||
fileName string
|
||||
shouldErr bool
|
||||
expect string
|
||||
}{
|
||||
{
|
||||
// file exists, template is defined
|
||||
fileContent: `{{ define "imported" }}text{{end}}`,
|
||||
fileName: "file1",
|
||||
shouldErr: false,
|
||||
expect: `"imported"`,
|
||||
},
|
||||
{
|
||||
// file does not exit
|
||||
fileContent: "",
|
||||
fileName: "",
|
||||
shouldErr: true,
|
||||
},
|
||||
} {
|
||||
tplContext := getContextOrFail(t)
|
||||
var absFilePath string
|
||||
|
||||
// create files for test case
|
||||
if test.fileName != "" {
|
||||
absFilePath := filepath.Join(fmt.Sprintf("%s", tplContext.Root), test.fileName)
|
||||
if err := os.WriteFile(absFilePath, []byte(test.fileContent), os.ModePerm); err != nil {
|
||||
os.Remove(absFilePath)
|
||||
t.Fatalf("Test %d: Expected no error creating file, got: '%s'", i, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// perform test
|
||||
tplContext.NewTemplate("parent")
|
||||
actual, err := tplContext.funcImport(test.fileName)
|
||||
templateWasDefined := strings.Contains(tplContext.tpl.DefinedTemplates(), test.expect)
|
||||
if err != nil {
|
||||
if !test.shouldErr {
|
||||
t.Errorf("Test %d: Expected no error, got: '%s'", i, err)
|
||||
}
|
||||
} else if test.shouldErr {
|
||||
t.Errorf("Test %d: Expected error but had none", i)
|
||||
} else if !templateWasDefined && actual != "" {
|
||||
// template should be defined, return value should be an empty string
|
||||
t.Errorf("Test %d: Expected template %s to be define but got %s", i, test.expect, tplContext.tpl.DefinedTemplates())
|
||||
|
||||
}
|
||||
|
||||
if absFilePath != "" {
|
||||
if err := os.Remove(absFilePath); err != nil && !os.IsNotExist(err) {
|
||||
t.Fatalf("Test %d: Expected no error removing temporary test file, got: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclude(t *testing.T) {
|
||||
for i, test := range []struct {
|
||||
fileContent string
|
||||
fileName string
|
||||
shouldErr bool
|
||||
expect string
|
||||
args string
|
||||
}{
|
||||
{
|
||||
// file exists, content is text only
|
||||
fileContent: "text",
|
||||
fileName: "file1",
|
||||
shouldErr: false,
|
||||
expect: "text",
|
||||
},
|
||||
{
|
||||
// file exists, content is template
|
||||
fileContent: "{{ if . }}text{{ end }}",
|
||||
fileName: "file1",
|
||||
shouldErr: false,
|
||||
expect: "text",
|
||||
},
|
||||
{
|
||||
// file does not exit
|
||||
fileContent: "",
|
||||
fileName: "",
|
||||
shouldErr: true,
|
||||
},
|
||||
{
|
||||
// args
|
||||
fileContent: "{{ index .Args 0 }}",
|
||||
fileName: "file1",
|
||||
shouldErr: false,
|
||||
args: "text",
|
||||
expect: "text",
|
||||
},
|
||||
{
|
||||
// args, reference arg out of range
|
||||
fileContent: "{{ index .Args 1 }}",
|
||||
fileName: "file1",
|
||||
shouldErr: true,
|
||||
args: "text",
|
||||
},
|
||||
} {
|
||||
tplContext := getContextOrFail(t)
|
||||
var absFilePath string
|
||||
|
||||
// create files for test case
|
||||
if test.fileName != "" {
|
||||
absFilePath := filepath.Join(fmt.Sprintf("%s", tplContext.Root), test.fileName)
|
||||
if err := os.WriteFile(absFilePath, []byte(test.fileContent), os.ModePerm); err != nil {
|
||||
os.Remove(absFilePath)
|
||||
t.Fatalf("Test %d: Expected no error creating file, got: '%s'", i, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// perform test
|
||||
actual, err := tplContext.funcInclude(test.fileName, test.args)
|
||||
if err != nil {
|
||||
if !test.shouldErr {
|
||||
t.Errorf("Test %d: Expected no error, got: '%s'", i, err)
|
||||
}
|
||||
} else if test.shouldErr {
|
||||
t.Errorf("Test %d: Expected error but had none", i)
|
||||
} else if actual != test.expect {
|
||||
t.Errorf("Test %d: Expected %s but got %s", i, test.expect, actual)
|
||||
|
||||
}
|
||||
|
||||
if absFilePath != "" {
|
||||
if err := os.Remove(absFilePath); err != nil && !os.IsNotExist(err) {
|
||||
t.Fatalf("Test %d: Expected no error removing temporary test file, got: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCookieMultipleCookies(t *testing.T) {
|
||||
context := getContextOrFail(t)
|
||||
tplContext := getContextOrFail(t)
|
||||
|
||||
cookieNameBase, cookieValueBase := "cookieName", "cookieValue"
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
context.Req.AddCookie(&http.Cookie{
|
||||
tplContext.Req.AddCookie(&http.Cookie{
|
||||
Name: fmt.Sprintf("%s%d", cookieNameBase, i),
|
||||
Value: fmt.Sprintf("%s%d", cookieValueBase, i),
|
||||
})
|
||||
@@ -105,7 +278,7 @@ func TestCookieMultipleCookies(t *testing.T) {
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
expectedCookieVal := fmt.Sprintf("%s%d", cookieValueBase, i)
|
||||
actualCookieVal := context.Cookie(fmt.Sprintf("%s%d", cookieNameBase, i))
|
||||
actualCookieVal := tplContext.Cookie(fmt.Sprintf("%s%d", cookieNameBase, i))
|
||||
if actualCookieVal != expectedCookieVal {
|
||||
t.Errorf("Expected cookie value %s, found %s", expectedCookieVal, actualCookieVal)
|
||||
}
|
||||
@@ -113,7 +286,7 @@ func TestCookieMultipleCookies(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIP(t *testing.T) {
|
||||
context := getContextOrFail(t)
|
||||
tplContext := getContextOrFail(t)
|
||||
for i, test := range []struct {
|
||||
inputRemoteAddr string
|
||||
expect string
|
||||
@@ -124,15 +297,15 @@ func TestIP(t *testing.T) {
|
||||
{"[2001:db8:a0b:12f0::1]", "[2001:db8:a0b:12f0::1]"},
|
||||
{`[fe80:1::3%eth0]:44`, `fe80:1::3%eth0`},
|
||||
} {
|
||||
context.Req.RemoteAddr = test.inputRemoteAddr
|
||||
if actual := context.RemoteIP(); actual != test.expect {
|
||||
tplContext.Req.RemoteAddr = test.inputRemoteAddr
|
||||
if actual := tplContext.RemoteIP(); actual != test.expect {
|
||||
t.Errorf("Test %d: Expected %s but got %s", i, test.expect, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStripHTML(t *testing.T) {
|
||||
context := getContextOrFail(t)
|
||||
tplContext := getContextOrFail(t)
|
||||
|
||||
for i, test := range []struct {
|
||||
input string
|
||||
@@ -169,7 +342,7 @@ func TestStripHTML(t *testing.T) {
|
||||
expect: `<h1hi`,
|
||||
},
|
||||
} {
|
||||
actual := context.funcStripHTML(test.input)
|
||||
actual := tplContext.funcStripHTML(test.input)
|
||||
if actual != test.expect {
|
||||
t.Errorf("Test %d: Expected %s, found %s. Input was StripHTML(%s)", i, test.expect, actual, test.input)
|
||||
}
|
||||
@@ -217,19 +390,19 @@ func TestFileListing(t *testing.T) {
|
||||
verifyErr: os.IsNotExist,
|
||||
},
|
||||
} {
|
||||
context := getContextOrFail(t)
|
||||
tplContext := getContextOrFail(t)
|
||||
var dirPath string
|
||||
var err error
|
||||
|
||||
// create files for test case
|
||||
if test.fileNames != nil {
|
||||
dirPath, err = ioutil.TempDir(fmt.Sprintf("%s", context.Root), "caddy_ctxtest")
|
||||
dirPath, err = os.MkdirTemp(fmt.Sprintf("%s", tplContext.Root), "caddy_ctxtest")
|
||||
if err != nil {
|
||||
t.Fatalf("Test %d: Expected no error creating directory, got: '%s'", i, err.Error())
|
||||
}
|
||||
for _, name := range test.fileNames {
|
||||
absFilePath := filepath.Join(dirPath, name)
|
||||
if err = ioutil.WriteFile(absFilePath, []byte(""), os.ModePerm); err != nil {
|
||||
if err = os.WriteFile(absFilePath, []byte(""), os.ModePerm); err != nil {
|
||||
os.RemoveAll(dirPath)
|
||||
t.Fatalf("Test %d: Expected no error creating file, got: '%s'", i, err.Error())
|
||||
}
|
||||
@@ -238,7 +411,7 @@ func TestFileListing(t *testing.T) {
|
||||
|
||||
// perform test
|
||||
input := filepath.ToSlash(filepath.Join(filepath.Base(dirPath), test.inputBase))
|
||||
actual, err := context.funcListFiles(input)
|
||||
actual, err := tplContext.funcListFiles(input)
|
||||
if err != nil {
|
||||
if !test.shouldErr {
|
||||
t.Errorf("Test %d: Expected no error, got: '%s'", i, err)
|
||||
@@ -271,7 +444,7 @@ func TestFileListing(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSplitFrontMatter(t *testing.T) {
|
||||
context := getContextOrFail(t)
|
||||
tplContext := getContextOrFail(t)
|
||||
|
||||
for i, test := range []struct {
|
||||
input string
|
||||
@@ -332,7 +505,7 @@ title = "Welcome"
|
||||
body: "\n### Test",
|
||||
},
|
||||
} {
|
||||
result, _ := context.funcSplitFrontMatter(test.input)
|
||||
result, _ := tplContext.funcSplitFrontMatter(test.input)
|
||||
if result.Meta["title"] != test.expect {
|
||||
t.Errorf("Test %d: Expected %s, found %s. Input was SplitFrontMatter(%s)", i, test.expect, result.Meta["title"], test.input)
|
||||
}
|
||||
@@ -344,11 +517,11 @@ title = "Welcome"
|
||||
}
|
||||
|
||||
func getContextOrFail(t *testing.T) TemplateContext {
|
||||
context, err := initTestContext()
|
||||
tplContext, err := initTestContext()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to prepare test context: %v", err)
|
||||
}
|
||||
return context
|
||||
return tplContext
|
||||
}
|
||||
|
||||
func initTestContext() (TemplateContext, error) {
|
||||
|
||||
@@ -29,9 +29,14 @@ func init() {
|
||||
caddy.RegisterModule(MatchVarsRE{})
|
||||
}
|
||||
|
||||
// VarsMiddleware is an HTTP middleware which sets variables
|
||||
// in the context, mainly for use by placeholders. The
|
||||
// placeholders have the form: `{http.vars.variable_name}`
|
||||
// VarsMiddleware is an HTTP middleware which sets variables to
|
||||
// have values that can be used in the HTTP request handler
|
||||
// chain. The primary way to access variables is with placeholders,
|
||||
// which have the form: `{http.vars.variable_name}`, or with
|
||||
// the `vars` and `vars_regexp` request matchers.
|
||||
//
|
||||
// The key is the variable name, and the value is the value of the
|
||||
// variable. Both the name and value may use or contain placeholders.
|
||||
type VarsMiddleware map[string]string
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -137,11 +137,11 @@ type KeyPair struct {
|
||||
func (kp KeyPair) Load() (*x509.Certificate, interface{}, error) {
|
||||
switch kp.Format {
|
||||
case "", "pem_file":
|
||||
certData, err := ioutil.ReadFile(kp.Certificate)
|
||||
certData, err := os.ReadFile(kp.Certificate)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
keyData, err := ioutil.ReadFile(kp.PrivateKey)
|
||||
keyData, err := os.ReadFile(kp.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
@@ -26,10 +26,15 @@ func init() {
|
||||
}
|
||||
|
||||
// PKI provides Public Key Infrastructure facilities for Caddy.
|
||||
//
|
||||
// This app can define certificate authorities (CAs) which are capable
|
||||
// of signing certificates. Other modules can be configured to use
|
||||
// the CAs defined by this app for issuing certificates or getting
|
||||
// key information needed for establishing trust.
|
||||
type PKI struct {
|
||||
// The CAs to manage. Each CA is keyed by an ID that is used
|
||||
// to uniquely identify it from other CAs. The default CA ID
|
||||
// is "local".
|
||||
// The certificate authorities to manage. Each CA is keyed by an
|
||||
// ID that is used to uniquely identify it from other CAs.
|
||||
// The default CA ID is "local".
|
||||
CAs map[string]*CA `json:"certificate_authorities,omitempty"`
|
||||
|
||||
ctx caddy.Context
|
||||
|
||||
@@ -18,8 +18,8 @@ import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -36,20 +36,16 @@ func init() {
|
||||
caddy.RegisterModule(ACMEIssuer{})
|
||||
}
|
||||
|
||||
// ACMEIssuer makes an ACME manager
|
||||
// for managing certificates using ACME.
|
||||
//
|
||||
// TODO: support multiple ACME endpoints (probably
|
||||
// requires an array of these structs) - caddy would
|
||||
// also have to load certs from the backup CAs if the
|
||||
// first one is expired...
|
||||
// ACMEIssuer manages certificates using the ACME protocol (RFC 8555).
|
||||
type ACMEIssuer struct {
|
||||
// The URL to the CA's ACME directory endpoint.
|
||||
// The URL to the CA's ACME directory endpoint. Default:
|
||||
// https://acme-v02.api.letsencrypt.org/directory
|
||||
CA string `json:"ca,omitempty"`
|
||||
|
||||
// The URL to the test CA's ACME directory endpoint.
|
||||
// This endpoint is only used during retries if there
|
||||
// is a failure using the primary CA.
|
||||
// is a failure using the primary CA. Default:
|
||||
// https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
TestCA string `json:"test_ca,omitempty"`
|
||||
|
||||
// Your email address, so the CA can contact you if necessary.
|
||||
@@ -71,6 +67,7 @@ type ACMEIssuer struct {
|
||||
ExternalAccount *acme.EAB `json:"external_account,omitempty"`
|
||||
|
||||
// Time to wait before timing out an ACME operation.
|
||||
// Default: 0 (no timeout)
|
||||
ACMETimeout caddy.Duration `json:"acme_timeout,omitempty"`
|
||||
|
||||
// Configures the various ACME challenge types.
|
||||
@@ -155,7 +152,7 @@ func (iss *ACMEIssuer) Provision(ctx caddy.Context) error {
|
||||
if len(iss.TrustedRootsPEMFiles) > 0 {
|
||||
iss.rootPool = x509.NewCertPool()
|
||||
for _, pemFile := range iss.TrustedRootsPEMFiles {
|
||||
pemData, err := ioutil.ReadFile(pemFile)
|
||||
pemData, err := os.ReadFile(pemFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading trusted root CA's PEM file: %s: %v", pemFile, err)
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ import (
|
||||
|
||||
// AutomationConfig governs the automated management of TLS certificates.
|
||||
type AutomationConfig struct {
|
||||
// The list of automation policies. The first matching
|
||||
// policy will be applied for a given certificate/name.
|
||||
// The list of automation policies. The first policy matching
|
||||
// a certificate or subject name will be applied.
|
||||
Policies []*AutomationPolicy `json:"policies,omitempty"`
|
||||
|
||||
// On-Demand TLS defers certificate operations to the
|
||||
@@ -39,7 +39,7 @@ type AutomationConfig struct {
|
||||
// In 2015, Caddy became the first web server to
|
||||
// implement this experimental technology.
|
||||
//
|
||||
// Note that this field does not enable on-demand TLS,
|
||||
// Note that this field does not enable on-demand TLS;
|
||||
// it only configures it for when it is used. To enable
|
||||
// it, create an automation policy with `on_demand`.
|
||||
OnDemand *OnDemandConfig `json:"on_demand,omitempty"`
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
@@ -369,7 +369,7 @@ func (clientauth *ClientAuthentication) ConfigureTLSConfig(cfg *tls.Config) erro
|
||||
caPool.AddCert(clientCA)
|
||||
}
|
||||
for _, pemFile := range clientauth.TrustedCACertPEMFiles {
|
||||
pemContents, err := ioutil.ReadFile(pemFile)
|
||||
pemContents, err := os.ReadFile(pemFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading %s: %v", pemFile, err)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ package caddytls
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/caddyserver/caddy/v2"
|
||||
)
|
||||
@@ -59,11 +59,11 @@ type CertKeyFilePair struct {
|
||||
func (fl FileLoader) LoadCertificates() ([]Certificate, error) {
|
||||
certs := make([]Certificate, 0, len(fl))
|
||||
for _, pair := range fl {
|
||||
certData, err := ioutil.ReadFile(pair.Certificate)
|
||||
certData, err := os.ReadFile(pair.Certificate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyData, err := ioutil.ReadFile(pair.Key)
|
||||
keyData, err := os.ReadFile(pair.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"crypto/tls"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -79,7 +78,7 @@ func (fl FolderLoader) LoadCertificates() ([]Certificate, error) {
|
||||
}
|
||||
|
||||
func x509CertFromCertAndKeyPEMFile(fpath string) (tls.Certificate, error) {
|
||||
bundle, err := ioutil.ReadFile(fpath)
|
||||
bundle, err := os.ReadFile(fpath)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
|
||||
+17
-18
@@ -47,7 +47,7 @@ type TLS struct {
|
||||
// have to be refreshed manually before they expire.
|
||||
CertificatesRaw caddy.ModuleMap `json:"certificates,omitempty" caddy:"namespace=tls.certificates"`
|
||||
|
||||
// Configures the automation of certificate management.
|
||||
// Configures certificate automation.
|
||||
Automation *AutomationConfig `json:"automation,omitempty"`
|
||||
|
||||
// Configures session ticket ephemeral keys (STEKs).
|
||||
@@ -458,20 +458,17 @@ func (t *TLS) cleanStorageUnits() {
|
||||
defer storageCleanMu.Unlock()
|
||||
|
||||
// If storage was cleaned recently, don't do it again for now. Although the ticker
|
||||
// drops missed ticks for us, config reloads discard the old ticker and replace it
|
||||
// with a new one, possibly invoking a cleaning to happen again too soon.
|
||||
// (We divide the interval by 2 because the actual cleaning takes non-zero time,
|
||||
// and we don't want to skip cleanings if we don't have to; whereas if a cleaning
|
||||
// took the entire interval, we'd probably want to skip the next one so we aren't
|
||||
// calling this function drops missed ticks for us, config reloads discard the old
|
||||
// ticker and replace it with a new one, possibly invoking a cleaning to happen again
|
||||
// too soon. (We divide the interval by 2 because the actual cleaning takes non-zero
|
||||
// time, and we don't want to skip cleanings if we don't have to; whereas if a cleaning
|
||||
// took most of the interval, we'd probably want to skip the next one so we aren't
|
||||
// constantly cleaning. This allows cleanings to take up to half the interval's
|
||||
// duration before we decide to skip the next one.)
|
||||
if !storageClean.IsZero() && time.Since(storageClean) < t.storageCleanInterval()/2 {
|
||||
return
|
||||
}
|
||||
|
||||
// mark when storage cleaning was last initiated
|
||||
storageClean = time.Now()
|
||||
|
||||
options := certmagic.CleanStorageOptions{
|
||||
OCSPStaples: true,
|
||||
ExpiredCerts: true,
|
||||
@@ -504,6 +501,9 @@ func (t *TLS) cleanStorageUnits() {
|
||||
}
|
||||
}
|
||||
|
||||
// remember last time storage was finished cleaning
|
||||
storageClean = time.Now()
|
||||
|
||||
t.logger.Info("finished cleaning storage units")
|
||||
}
|
||||
|
||||
@@ -527,14 +527,14 @@ type Certificate struct {
|
||||
Tags []string
|
||||
}
|
||||
|
||||
// AutomateLoader will automatically manage certificates for the names
|
||||
// in the list, including obtaining and renewing certificates. Automated
|
||||
// certificates are managed according to their matching automation policy,
|
||||
// configured elsewhere in this app.
|
||||
// AutomateLoader will automatically manage certificates for the names in the
|
||||
// list, including obtaining and renewing certificates. Automated certificates
|
||||
// are managed according to their matching automation policy, configured
|
||||
// elsewhere in this app.
|
||||
//
|
||||
// This is a no-op certificate loader module that is treated as a special
|
||||
// case: it uses this app's automation features to load certificates for the
|
||||
// list of hostnames, rather than loading certificates manually.
|
||||
// Technically, this is a no-op certificate loader module that is treated as
|
||||
// a special case: it uses this app's automation features to load certificates
|
||||
// for the list of hostnames, rather than loading certificates manually.
|
||||
type AutomateLoader []string
|
||||
|
||||
// CaddyModule returns the Caddy module information.
|
||||
@@ -549,8 +549,7 @@ func (AutomateLoader) CaddyModule() caddy.ModuleInfo {
|
||||
type CertCacheOptions struct {
|
||||
// Maximum number of certificates to allow in the
|
||||
// cache. If reached, certificates will be randomly
|
||||
// evicted to make room for new ones. Default: 0
|
||||
// (no limit).
|
||||
// evicted to make room for new ones. Default: 10,000
|
||||
Capacity int `json:"capacity,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user