mirror of
https://github.com/caddyserver/caddy.git
synced 2026-05-26 08:42:31 -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.
|
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.
|
Please don't encrypt the email body. It only makes the process more complicated.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
linters-settings:
|
linters-settings:
|
||||||
errcheck:
|
errcheck:
|
||||||
ignore: fmt:.*,io/ioutil:^Read.*,go.uber.org/zap/zapcore:^Add.*
|
ignore: fmt:.*,go.uber.org/zap/zapcore:^Add.*
|
||||||
ignoretests: true
|
ignoretests: true
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
|
|||||||
+1
-1
@@ -75,7 +75,7 @@ nfpms:
|
|||||||
- id: default
|
- id: default
|
||||||
package_name: caddy
|
package_name: caddy
|
||||||
|
|
||||||
vendor: Light Code Labs
|
vendor: Dyanim
|
||||||
homepage: https://caddyserver.com
|
homepage: https://caddyserver.com
|
||||||
maintainer: Matthew Holt <mholt@users.noreply.github.com>
|
maintainer: Matthew Holt <mholt@users.noreply.github.com>
|
||||||
description: |
|
description: |
|
||||||
|
|||||||
@@ -176,6 +176,8 @@ Please use our [issue tracker](https://github.com/caddyserver/caddy/issues) only
|
|||||||
|
|
||||||
## About
|
## 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.
|
**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)_
|
- _Project on Twitter: [@caddyserver](https://twitter.com/caddyserver)_
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import (
|
|||||||
"expvar"
|
"expvar"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/pprof"
|
"net/http/pprof"
|
||||||
@@ -1202,7 +1201,7 @@ var (
|
|||||||
// will get deleted before the process gracefully exits.
|
// will get deleted before the process gracefully exits.
|
||||||
func PIDFile(filename string) error {
|
func PIDFile(filename string) error {
|
||||||
pid := []byte(strconv.Itoa(os.Getpid()) + "\n")
|
pid := []byte(strconv.Itoa(os.Getpid()) + "\n")
|
||||||
err := ioutil.WriteFile(filename, pid, 0600)
|
err := os.WriteFile(filename, pid, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -300,7 +299,7 @@ func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error {
|
|||||||
zap.String("dir", dir),
|
zap.String("dir", dir),
|
||||||
zap.Error(err))
|
zap.Error(err))
|
||||||
} else {
|
} else {
|
||||||
err := ioutil.WriteFile(ConfigAutosavePath, cfgJSON, 0600)
|
err := os.WriteFile(ConfigAutosavePath, cfgJSON, 0600)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
Log().Info("autosaved config (load with --resume flag)", zap.String("file", ConfigAutosavePath))
|
Log().Info("autosaved config (load with --resume flag)", zap.String("file", ConfigAutosavePath))
|
||||||
} else {
|
} else {
|
||||||
@@ -700,13 +699,13 @@ func ParseDuration(s string) (time.Duration, error) {
|
|||||||
// have its own unique ID.
|
// have its own unique ID.
|
||||||
func InstanceID() (uuid.UUID, error) {
|
func InstanceID() (uuid.UUID, error) {
|
||||||
uuidFilePath := filepath.Join(AppDataDir(), "instance.uuid")
|
uuidFilePath := filepath.Join(AppDataDir(), "instance.uuid")
|
||||||
uuidFileBytes, err := ioutil.ReadFile(uuidFilePath)
|
uuidFileBytes, err := os.ReadFile(uuidFilePath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
uuid, err := uuid.NewRandom()
|
uuid, err := uuid.NewRandom()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return uuid, err
|
return uuid, err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(uuidFilePath, []byte(uuid.String()), 0600)
|
err = os.WriteFile(uuidFilePath, []byte(uuid.String()), 0600)
|
||||||
return uuid, err
|
return uuid, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return [16]byte{}, err
|
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");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with 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");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with 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");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@@ -17,7 +17,7 @@ package caddyfile
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"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)
|
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 {
|
if err != nil {
|
||||||
return nil, p.Errf("Could not read imported file %s: %v", importFile, err)
|
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");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@@ -16,7 +16,6 @@ package caddyfile
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -280,7 +279,7 @@ func TestRecursiveImport(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test relative recursive import
|
// test relative recursive import
|
||||||
err = ioutil.WriteFile(recursiveFile1, []byte(
|
err = os.WriteFile(recursiveFile1, []byte(
|
||||||
`localhost
|
`localhost
|
||||||
dir1
|
dir1
|
||||||
import recursive_import_test2`), 0644)
|
import recursive_import_test2`), 0644)
|
||||||
@@ -289,7 +288,7 @@ func TestRecursiveImport(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer os.Remove(recursiveFile1)
|
defer os.Remove(recursiveFile1)
|
||||||
|
|
||||||
err = ioutil.WriteFile(recursiveFile2, []byte("dir2 1"), 0644)
|
err = os.WriteFile(recursiveFile2, []byte("dir2 1"), 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -314,7 +313,7 @@ func TestRecursiveImport(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test absolute recursive import
|
// test absolute recursive import
|
||||||
err = ioutil.WriteFile(recursiveFile1, []byte(
|
err = os.WriteFile(recursiveFile1, []byte(
|
||||||
`localhost
|
`localhost
|
||||||
dir1
|
dir1
|
||||||
import `+recursiveFile2), 0644)
|
import `+recursiveFile2), 0644)
|
||||||
@@ -370,7 +369,7 @@ func TestDirectiveImport(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ioutil.WriteFile(directiveFile, []byte(`prop1 1
|
err = os.WriteFile(directiveFile, []byte(`prop1 1
|
||||||
prop2 2`), 0644)
|
prop2 2`), 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -633,7 +632,7 @@ func TestSnippets(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func writeStringToTempFileOrDie(t *testing.T, str string) (pathToFile string) {
|
func writeStringToTempFileOrDie(t *testing.T, str string) (pathToFile string) {
|
||||||
file, err := ioutil.TempFile("", t.Name())
|
file, err := os.CreateTemp("", t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err) // get a stack trace so we know where this was called from.
|
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
|
// ensure host is normalized if it's an IP address
|
||||||
host := strings.TrimSpace(a.Host)
|
host := strings.TrimSpace(a.Host)
|
||||||
if ip := net.ParseIP(host); ip != nil {
|
if ip := net.ParseIP(host); ip != nil {
|
||||||
host = ip.String()
|
if ipv6 := ip.To16(); ipv6 != nil && ipv6.DefaultMask() == nil {
|
||||||
|
host = ipv6.String()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Address{
|
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
|
// lowerExceptPlaceholders lowercases s except within
|
||||||
// placeholders (substrings in non-escaped '{ }' spans).
|
// placeholders (substrings in non-escaped '{ }' spans).
|
||||||
// See https://github.com/caddyserver/caddy/issues/3264
|
// See https://github.com/caddyserver/caddy/issues/3264
|
||||||
|
|||||||
@@ -106,67 +106,128 @@ func TestAddressString(t *testing.T) {
|
|||||||
func TestKeyNormalization(t *testing.T) {
|
func TestKeyNormalization(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
input string
|
input string
|
||||||
expect string
|
expect Address
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
input: "example.com",
|
input: "example.com",
|
||||||
expect: "example.com",
|
expect: Address{
|
||||||
|
Host: "example.com",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "http://host:1234/path",
|
input: "http://host:1234/path",
|
||||||
expect: "http://host:1234/path",
|
expect: Address{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: "host",
|
||||||
|
Port: "1234",
|
||||||
|
Path: "/path",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "HTTP://A/ABCDEF",
|
input: "HTTP://A/ABCDEF",
|
||||||
expect: "http://a/ABCDEF",
|
expect: Address{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: "a",
|
||||||
|
Path: "/ABCDEF",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "A/ABCDEF",
|
input: "A/ABCDEF",
|
||||||
expect: "a/ABCDEF",
|
expect: Address{
|
||||||
|
Host: "a",
|
||||||
|
Path: "/ABCDEF",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "A:2015/Path",
|
input: "A:2015/Path",
|
||||||
expect: "a:2015/Path",
|
expect: Address{
|
||||||
|
Host: "a",
|
||||||
|
Port: "2015",
|
||||||
|
Path: "/Path",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "sub.{env.MY_DOMAIN}",
|
input: "sub.{env.MY_DOMAIN}",
|
||||||
expect: "sub.{env.MY_DOMAIN}",
|
expect: Address{
|
||||||
|
Host: "sub.{env.MY_DOMAIN}",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "sub.ExAmPle",
|
input: "sub.ExAmPle",
|
||||||
expect: "sub.example",
|
expect: Address{
|
||||||
|
Host: "sub.example",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "sub.\\{env.MY_DOMAIN\\}",
|
input: "sub.\\{env.MY_DOMAIN\\}",
|
||||||
expect: "sub.\\{env.my_domain\\}",
|
expect: Address{
|
||||||
|
Host: "sub.\\{env.my_domain\\}",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "sub.{env.MY_DOMAIN}.com",
|
input: "sub.{env.MY_DOMAIN}.com",
|
||||||
expect: "sub.{env.MY_DOMAIN}.com",
|
expect: Address{
|
||||||
|
Host: "sub.{env.MY_DOMAIN}.com",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: ":80",
|
input: ":80",
|
||||||
expect: ":80",
|
expect: Address{
|
||||||
|
Port: "80",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: ":443",
|
input: ":443",
|
||||||
expect: ":443",
|
expect: Address{
|
||||||
|
Port: "443",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: ":1234",
|
input: ":1234",
|
||||||
expect: ":1234",
|
expect: Address{
|
||||||
|
Port: "1234",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "",
|
input: "",
|
||||||
expect: "",
|
expect: Address{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: ":",
|
input: ":",
|
||||||
expect: "",
|
expect: Address{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "[::]",
|
input: "[::]",
|
||||||
expect: "::",
|
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 {
|
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)
|
t.Errorf("Test %d: Parsing address '%s': %v", i, tc.input, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if actual := addr.Normalize().Key(); actual != tc.expect {
|
actual := addr.Normalize()
|
||||||
t.Errorf("Test %d: Input '%s': Expected '%s' but got '%s'", i, tc.input, tc.expect, actual)
|
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"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -230,7 +230,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
|
|||||||
return nil, h.ArgErr()
|
return nil, h.ArgErr()
|
||||||
}
|
}
|
||||||
filename := h.Val()
|
filename := h.Val()
|
||||||
certDataPEM, err := ioutil.ReadFile(filename)
|
certDataPEM, err := os.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -485,7 +485,7 @@ func (sb serverBlock) hostsFromKeysNotHTTP(httpPort string) []string {
|
|||||||
if addr.Host == "" {
|
if addr.Host == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if addr.Scheme != "http" && addr.Port != httpPort {
|
if addr.Scheme != "http" || addr.Port != httpPort {
|
||||||
hostMap[addr.Host] = struct{}{}
|
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_serial}", "{http.request.tls.client.serial}",
|
||||||
"{tls_client_subject}", "{http.request.tls.client.subject}",
|
"{tls_client_subject}", "{http.request.tls.client.subject}",
|
||||||
"{tls_client_certificate_pem}", "{http.request.tls.client.certificate_pem}",
|
"{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}",
|
"{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
|
package caddyconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/caddyserver/caddy/v2"
|
"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)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -130,7 +145,7 @@ func (hl HTTPLoader) makeClient(ctx caddy.Context) (*http.Client, error) {
|
|||||||
if len(hl.TLS.RootCAPEMFiles) > 0 {
|
if len(hl.TLS.RootCAPEMFiles) > 0 {
|
||||||
rootPool := x509.NewCertPool()
|
rootPool := x509.NewCertPool()
|
||||||
for _, pemFile := range hl.TLS.RootCAPEMFiles {
|
for _, pemFile := range hl.TLS.RootCAPEMFiles {
|
||||||
pemData, err := ioutil.ReadFile(pemFile)
|
pemData, err := os.ReadFile(pemFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed reading ca cert: %v", err)
|
return nil, fmt.Errorf("failed reading ca cert: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -129,7 +129,7 @@ func (tc *Tester) initServer(rawConfig string, configType string) error {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
body, _ := ioutil.ReadAll(res.Body)
|
body, _ := io.ReadAll(res.Body)
|
||||||
|
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
_ = json.Indent(&out, body, "", " ")
|
_ = json.Indent(&out, body, "", " ")
|
||||||
@@ -162,7 +162,7 @@ func (tc *Tester) initServer(rawConfig string, configType string) error {
|
|||||||
timeElapsed(start, "caddytest: config load time")
|
timeElapsed(start, "caddytest: config load time")
|
||||||
|
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
body, err := ioutil.ReadAll(res.Body)
|
body, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tc.t.Errorf("unable to read response. %s", err)
|
tc.t.Errorf("unable to read response. %s", err)
|
||||||
return err
|
return err
|
||||||
@@ -202,7 +202,7 @@ func (tc *Tester) ensureConfigRunning(rawConfig string, configType string) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
actualBytes, err := ioutil.ReadAll(resp.Body)
|
actualBytes, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -471,7 +471,7 @@ func (tc *Tester) AssertResponse(req *http.Request, expectedStatusCode int, expe
|
|||||||
resp := tc.AssertResponseCode(req, expectedStatusCode)
|
resp := tc.AssertResponseCode(req, expectedStatusCode)
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
bytes, err := ioutil.ReadAll(resp.Body)
|
bytes, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tc.t.Fatalf("unable to read the response body %s", err)
|
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 (
|
import (
|
||||||
jsonMod "encoding/json"
|
jsonMod "encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
func TestCaddyfileAdaptToJSON(t *testing.T) {
|
func TestCaddyfileAdaptToJSON(t *testing.T) {
|
||||||
// load the list of test files from the dir
|
// load the list of test files from the dir
|
||||||
files, err := ioutil.ReadDir("./caddyfile_adapt")
|
files, err := os.ReadDir("./caddyfile_adapt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to read caddyfile_adapt dir: %s", err)
|
t.Errorf("failed to read caddyfile_adapt dir: %s", err)
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ func TestCaddyfileAdaptToJSON(t *testing.T) {
|
|||||||
|
|
||||||
// read the test file
|
// read the test file
|
||||||
filename := f.Name()
|
filename := f.Name()
|
||||||
data, err := ioutil.ReadFile("./caddyfile_adapt/" + filename)
|
data, err := os.ReadFile("./caddyfile_adapt/" + filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to read %s dir: %s", filename, err)
|
t.Errorf("failed to read %s dir: %s", filename, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package integration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -85,7 +84,7 @@ func TestDialWithPlaceholderUnix(t *testing.T) {
|
|||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := ioutil.TempFile("", "*.sock")
|
f, err := os.CreateTemp("", "*.sock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to create TempFile: %s", err)
|
t.Errorf("failed to create TempFile: %s", err)
|
||||||
return
|
return
|
||||||
@@ -387,7 +386,7 @@ func TestReverseProxyHealthCheckUnixSocket(t *testing.T) {
|
|||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
tester := caddytest.NewTester(t)
|
tester := caddytest.NewTester(t)
|
||||||
f, err := ioutil.TempFile("", "*.sock")
|
f, err := os.CreateTemp("", "*.sock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to create TempFile: %s", err)
|
t.Errorf("failed to create TempFile: %s", err)
|
||||||
return
|
return
|
||||||
@@ -442,7 +441,7 @@ func TestReverseProxyHealthCheckUnixSocketWithoutPort(t *testing.T) {
|
|||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
tester := caddytest.NewTester(t)
|
tester := caddytest.NewTester(t)
|
||||||
f, err := ioutil.TempFile("", "*.sock")
|
f, err := os.CreateTemp("", "*.sock")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to create TempFile: %s", err)
|
t.Errorf("failed to create TempFile: %s", err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -110,7 +109,7 @@ func TestH2ToH2CStream(t *testing.T) {
|
|||||||
r, w := io.Pipe()
|
r, w := io.Pipe()
|
||||||
req := &http.Request{
|
req := &http.Request{
|
||||||
Method: "PUT",
|
Method: "PUT",
|
||||||
Body: ioutil.NopCloser(r),
|
Body: io.NopCloser(r),
|
||||||
URL: &url.URL{
|
URL: &url.URL{
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Host: "127.0.0.1:9443",
|
Host: "127.0.0.1:9443",
|
||||||
@@ -134,7 +133,7 @@ func TestH2ToH2CStream(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
bytes, err := ioutil.ReadAll(resp.Body)
|
bytes, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to read the response body %s", err)
|
t.Fatalf("unable to read the response body %s", err)
|
||||||
}
|
}
|
||||||
@@ -319,7 +318,7 @@ func TestH2ToH1ChunkedResponse(t *testing.T) {
|
|||||||
r, w := io.Pipe()
|
r, w := io.Pipe()
|
||||||
req := &http.Request{
|
req := &http.Request{
|
||||||
Method: "PUT",
|
Method: "PUT",
|
||||||
Body: ioutil.NopCloser(r),
|
Body: io.NopCloser(r),
|
||||||
URL: &url.URL{
|
URL: &url.URL{
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Host: "127.0.0.1:9443",
|
Host: "127.0.0.1:9443",
|
||||||
@@ -342,7 +341,7 @@ func TestH2ToH1ChunkedResponse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
bytes, err := ioutil.ReadAll(resp.Body)
|
bytes, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to read the response body %s", err)
|
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()
|
defer r.Body.Close()
|
||||||
bytes, err := ioutil.ReadAll(r.Body)
|
bytes, err := io.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to read the response body %s", err)
|
t.Fatalf("unable to read the response body %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-16
@@ -22,7 +22,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -181,7 +180,7 @@ func cmdRun(fl Flags) (int, error) {
|
|||||||
var config []byte
|
var config []byte
|
||||||
var err error
|
var err error
|
||||||
if runCmdResumeFlag {
|
if runCmdResumeFlag {
|
||||||
config, err = ioutil.ReadFile(caddy.ConfigAutosavePath)
|
config, err = os.ReadFile(caddy.ConfigAutosavePath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// not a bad error; just can't resume if autosave file doesn't exist
|
// 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))
|
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
|
// if we are to report to another process the successful start
|
||||||
// of the server, do so now by echoing back contents of stdin
|
// of the server, do so now by echoing back contents of stdin
|
||||||
if runCmdPingbackFlag != "" {
|
if runCmdPingbackFlag != "" {
|
||||||
confirmationBytes, err := ioutil.ReadAll(os.Stdin)
|
confirmationBytes, err := io.ReadAll(os.Stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return caddy.ExitCodeFailedStartup,
|
return caddy.ExitCodeFailedStartup,
|
||||||
fmt.Errorf("reading confirmation bytes from stdin: %v", err)
|
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) {
|
func cmdListModules(fl Flags) (int, error) {
|
||||||
packages := fl.Bool("packages")
|
packages := fl.Bool("packages")
|
||||||
versions := fl.Bool("versions")
|
versions := fl.Bool("versions")
|
||||||
|
skipStandard := fl.Bool("skip-standard")
|
||||||
|
|
||||||
printModuleInfo := func(mi moduleInfo) {
|
printModuleInfo := func(mi moduleInfo) {
|
||||||
fmt.Print(mi.caddyModuleID)
|
fmt.Print(mi.caddyModuleID)
|
||||||
@@ -389,14 +389,19 @@ func cmdListModules(fl Flags) (int, error) {
|
|||||||
return caddy.ExitCodeSuccess, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(standard) > 0 {
|
// Standard modules (always shipped with Caddy)
|
||||||
for _, mod := range standard {
|
if !skipStandard {
|
||||||
printModuleInfo(mod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Printf("\n Standard modules: %d\n", len(standard))
|
|
||||||
if len(nonstandard) > 0 {
|
|
||||||
if len(standard) > 0 {
|
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()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
for _, mod := range nonstandard {
|
for _, mod := range nonstandard {
|
||||||
@@ -404,8 +409,10 @@ func cmdListModules(fl Flags) (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Printf("\n Non-standard modules: %d\n", len(nonstandard))
|
fmt.Printf("\n Non-standard modules: %d\n", len(nonstandard))
|
||||||
|
|
||||||
|
// Unknown modules (couldn't get Caddy module info)
|
||||||
if len(unknown) > 0 {
|
if len(unknown) > 0 {
|
||||||
if len(standard) > 0 || len(nonstandard) > 0 {
|
if (len(standard) > 0 && !skipStandard) || len(nonstandard) > 0 {
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
for _, mod := range unknown {
|
for _, mod := range unknown {
|
||||||
@@ -457,7 +464,7 @@ func cmdAdaptConfig(fl Flags) (int, error) {
|
|||||||
fmt.Errorf("unrecognized config adapter: %s", adaptCmdAdapterFlag)
|
fmt.Errorf("unrecognized config adapter: %s", adaptCmdAdapterFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
input, err := ioutil.ReadFile(adaptCmdInputFlag)
|
input, err := os.ReadFile(adaptCmdInputFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return caddy.ExitCodeFailedStartup,
|
return caddy.ExitCodeFailedStartup,
|
||||||
fmt.Errorf("reading input file: %v", err)
|
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 "-"
|
// as a special case, read from stdin if the file name is "-"
|
||||||
if formatCmdConfigFile == "-" {
|
if formatCmdConfigFile == "-" {
|
||||||
input, err := ioutil.ReadAll(os.Stdin)
|
input, err := io.ReadAll(os.Stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return caddy.ExitCodeFailedStartup,
|
return caddy.ExitCodeFailedStartup,
|
||||||
fmt.Errorf("reading stdin: %v", err)
|
fmt.Errorf("reading stdin: %v", err)
|
||||||
@@ -550,7 +557,7 @@ func cmdFmt(fl Flags) (int, error) {
|
|||||||
return caddy.ExitCodeSuccess, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
input, err := ioutil.ReadFile(formatCmdConfigFile)
|
input, err := os.ReadFile(formatCmdConfigFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return caddy.ExitCodeFailedStartup,
|
return caddy.ExitCodeFailedStartup,
|
||||||
fmt.Errorf("reading input file: %v", err)
|
fmt.Errorf("reading input file: %v", err)
|
||||||
@@ -559,7 +566,7 @@ func cmdFmt(fl Flags) (int, error) {
|
|||||||
output := caddyfile.Format(input)
|
output := caddyfile.Format(input)
|
||||||
|
|
||||||
if fl.Bool("overwrite") {
|
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
|
return caddy.ExitCodeFailedStartup, nil
|
||||||
}
|
}
|
||||||
} else {
|
} 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 it didn't work, let the user know
|
||||||
if resp.StatusCode >= 400 {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("HTTP %d: reading error message: %v", resp.StatusCode, err)
|
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 := flag.NewFlagSet("list-modules", flag.ExitOnError)
|
||||||
fs.Bool("packages", false, "Print package paths")
|
fs.Bool("packages", false, "Print package paths")
|
||||||
fs.Bool("versions", false, "Print version information")
|
fs.Bool("versions", false, "Print version information")
|
||||||
|
fs.Bool("skip-standard", false, "Skip printing standard modules")
|
||||||
return fs
|
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
|
This reveals any errors with the configuration through the loading and
|
||||||
provisioning stages.`,
|
provisioning stages.`,
|
||||||
Flags: func() *flag.FlagSet {
|
Flags: func() *flag.FlagSet {
|
||||||
fs := flag.NewFlagSet("load", flag.ExitOnError)
|
fs := flag.NewFlagSet("validate", flag.ExitOnError)
|
||||||
fs.String("config", "", "Input configuration file")
|
fs.String("config", "", "Input configuration file")
|
||||||
fs.String("adapter", "", "Name of config adapter")
|
fs.String("adapter", "", "Name of config adapter")
|
||||||
return fs
|
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
|
When reading from stdin, the --overwrite flag has no effect: the result
|
||||||
is always printed to stdout.`,
|
is always printed to stdout.`,
|
||||||
Flags: func() *flag.FlagSet {
|
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")
|
fs.Bool("overwrite", false, "Overwrite the input file with the results")
|
||||||
return fs
|
return fs
|
||||||
}(),
|
}(),
|
||||||
@@ -295,6 +296,11 @@ is always printed to stdout.`,
|
|||||||
Long: `
|
Long: `
|
||||||
Downloads an updated Caddy binary with the same modules/plugins at the
|
Downloads an updated Caddy binary with the same modules/plugins at the
|
||||||
latest versions. EXPERIMENTAL: May be changed or removed.`,
|
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{
|
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
|
added. Retains existing packages. Returns an error if the any of packages are
|
||||||
already included. EXPERIMENTAL: May be changed or removed.
|
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{
|
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.
|
Returns an error if any of the packages are not included.
|
||||||
EXPERIMENTAL: May be changed or removed.
|
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"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@@ -94,7 +93,7 @@ func Main() {
|
|||||||
// the bytes in expect, or returns an error if it doesn't.
|
// the bytes in expect, or returns an error if it doesn't.
|
||||||
func handlePingbackConn(conn net.Conn, expect []byte) error {
|
func handlePingbackConn(conn net.Conn, expect []byte) error {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
confirmationBytes, err := ioutil.ReadAll(io.LimitReader(conn, 32))
|
confirmationBytes, err := io.ReadAll(io.LimitReader(conn, 32))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -124,9 +123,9 @@ func loadConfig(configFile, adapterName string) ([]byte, string, error) {
|
|||||||
var err error
|
var err error
|
||||||
if configFile != "" {
|
if configFile != "" {
|
||||||
if configFile == "-" {
|
if configFile == "-" {
|
||||||
config, err = ioutil.ReadAll(os.Stdin)
|
config, err = io.ReadAll(os.Stdin)
|
||||||
} else {
|
} else {
|
||||||
config, err = ioutil.ReadFile(configFile)
|
config, err = os.ReadFile(configFile)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", fmt.Errorf("reading config file: %v", err)
|
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
|
// plugged in, and if so, try using a default Caddyfile
|
||||||
cfgAdapter = caddyconfig.GetAdapter("caddyfile")
|
cfgAdapter = caddyconfig.GetAdapter("caddyfile")
|
||||||
if cfgAdapter != nil {
|
if cfgAdapter != nil {
|
||||||
config, err = ioutil.ReadFile("Caddyfile")
|
config, err = os.ReadFile("Caddyfile")
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// okay, no default Caddyfile; pretend like this never happened
|
// okay, no default Caddyfile; pretend like this never happened
|
||||||
cfgAdapter = nil
|
cfgAdapter = nil
|
||||||
|
|||||||
+17
-20
@@ -31,7 +31,7 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func cmdUpgrade(_ Flags) (int, error) {
|
func cmdUpgrade(fl Flags) (int, error) {
|
||||||
_, nonstandard, _, err := getModules()
|
_, nonstandard, _, err := getModules()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("unable to enumerate installed plugins: %v", err)
|
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 caddy.ExitCodeFailedStartup, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return upgradeBuild(pluginPkgs)
|
return upgradeBuild(pluginPkgs, fl)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdAddPackage(fl Flags) (int, error) {
|
func cmdAddPackage(fl Flags) (int, error) {
|
||||||
@@ -64,7 +64,7 @@ func cmdAddPackage(fl Flags) (int, error) {
|
|||||||
pluginPkgs[arg] = struct{}{}
|
pluginPkgs[arg] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return upgradeBuild(pluginPkgs)
|
return upgradeBuild(pluginPkgs, fl)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdRemovePackage(fl Flags) (int, error) {
|
func cmdRemovePackage(fl Flags) (int, error) {
|
||||||
@@ -88,10 +88,10 @@ func cmdRemovePackage(fl Flags) (int, error) {
|
|||||||
delete(pluginPkgs, arg)
|
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()
|
l := caddy.Log()
|
||||||
|
|
||||||
thisExecPath, err := os.Executable()
|
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
|
// use the new binary to print out version and module info
|
||||||
fmt.Print("\nModule versions:\n\n")
|
fmt.Print("\nModule versions:\n\n")
|
||||||
if err = listModules(thisExecPath); err != nil {
|
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:")
|
fmt.Println("\nVersion:")
|
||||||
if err = showVersion(thisExecPath); err != nil {
|
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()
|
fmt.Println()
|
||||||
|
|
||||||
// clean up the backup file
|
// clean up the backup file
|
||||||
if err = os.Remove(backupExecPath); err != nil {
|
if !fl.Bool("keep-backup") {
|
||||||
return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to clean up backup binary: %v", err)
|
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))
|
l.Info("upgrade successful; please restart any running Caddy instances", zap.String("executable", thisExecPath))
|
||||||
|
|
||||||
return caddy.ExitCodeSuccess, nil
|
return caddy.ExitCodeSuccess, nil
|
||||||
@@ -220,25 +225,17 @@ func getModules() (standard, nonstandard, unknown []moduleInfo, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listModules(path string) 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.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
err := cmd.Run()
|
return cmd.Run()
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("download succeeded, but unable to execute: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func showVersion(path string) error {
|
func showVersion(path string) error {
|
||||||
cmd := exec.Command(path, "version")
|
cmd := exec.Command(path, "version")
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
err := cmd.Run()
|
return cmd.Run()
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("download succeeded, but unable to execute: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadBuild(qs url.Values) (*http.Response, error) {
|
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/Masterminds/sprig/v3 v3.2.2
|
||||||
github.com/alecthomas/chroma v0.9.2
|
github.com/alecthomas/chroma v0.9.2
|
||||||
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b
|
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/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac
|
||||||
github.com/go-chi/chi v4.1.2+incompatible
|
github.com/go-chi/chi v4.1.2+incompatible
|
||||||
github.com/google/cel-go v0.7.3
|
github.com/google/cel-go v0.7.3
|
||||||
github.com/google/uuid v1.3.0
|
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/klauspost/cpuid/v2 v2.0.9
|
||||||
github.com/lucas-clemente/quic-go v0.23.0
|
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/go-stringutil v0.1.0 // indirect
|
||||||
github.com/naoina/toml v0.1.1
|
github.com/naoina/toml v0.1.1
|
||||||
github.com/prometheus/client_golang v1.11.0
|
github.com/prometheus/client_golang v1.11.0
|
||||||
github.com/smallstep/certificates v0.16.4
|
github.com/smallstep/certificates v0.17.5-0.20211008195551-04fe3126bebf
|
||||||
github.com/smallstep/cli v0.16.1
|
github.com/smallstep/cli v0.17.6
|
||||||
github.com/smallstep/nosql v0.3.8
|
github.com/smallstep/nosql v0.3.8
|
||||||
github.com/smallstep/truststore v0.9.6
|
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
|
github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01
|
||||||
go.uber.org/zap v1.19.0
|
go.uber.org/zap v1.19.0
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
|
golang.org/x/crypto v0.0.0-20210915214749-c084706c2272
|
||||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
|
golang.org/x/net v0.0.0-20210913180222-943fd674d43e
|
||||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
|
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
|
google.golang.org/protobuf v1.27.1
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||||
gopkg.in/yaml.v2 v2.4.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 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
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/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/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/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=
|
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/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/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/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.15.2 h1:OMTakTsLM1ZfzMDjwvYprfUgFzpVPh3u87oxMPwmeBc=
|
||||||
github.com/caddyserver/certmagic v0.14.5/go.mod h1:/0VQ5og2Jxa5yBQ8eT80wWS7fi/DgNy1uXeXRUJ1Wj0=
|
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/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/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=
|
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-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-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/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-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
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=
|
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/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 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8=
|
||||||
github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
|
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 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=
|
||||||
github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
|
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=
|
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.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.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.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.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/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=
|
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 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
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.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 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
||||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
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=
|
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/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.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.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.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/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-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/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.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/imdario/mergo v0.3.8/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.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.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/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/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=
|
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.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/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/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/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.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||||
github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s=
|
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
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/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=
|
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 h1:5vFnKtZ6nHDFsc/F3uuiF4T3y/AXaQdxjUqiVw26GZE=
|
||||||
github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
|
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 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/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/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.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.1/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/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 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs=
|
||||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
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=
|
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 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
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/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/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||||
github.com/mholt/acmez v1.0.0/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM=
|
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/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.1.0 h1:2fS9Rla7qRR266hvUoEauBJ7J6FhgssEiq2OkSKXmaU=
|
||||||
github.com/micromdm/scep/v2 v2.0.0/go.mod h1:ouaDs5tcjOjdHD/h8BGaQsWE87MUnQ/wMTMgfMMIpPc=
|
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.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY=
|
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
|
||||||
github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
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.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-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||||
github.com/miekg/pkcs11 v1.0.3/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/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.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.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-homedir v1.1.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=
|
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 v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/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.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.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-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/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=
|
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/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/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/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/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.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
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-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 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/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.17.4/go.mod h1:NRV/XqAmL65jDaAiLDEYeW0PySKPim+RX+rWi00LKDM=
|
||||||
github.com/smallstep/certificates v0.16.4 h1:/dhaR+6reeTHd2etVIjgpZI0CTn6USrhVqakoV0HZ0w=
|
github.com/smallstep/certificates v0.17.5-0.20211008195551-04fe3126bebf h1:T27FAcJuIadMwnt5uaYCxeNQceUoCkLHqWc0Y+PneHE=
|
||||||
github.com/smallstep/certificates v0.16.4/go.mod h1:U3Dkt4ttxRxC4yPedzzAQokC121/7d3Sfnj6mNgpw7Q=
|
github.com/smallstep/certificates v0.17.5-0.20211008195551-04fe3126bebf/go.mod h1:dAdOimWAt87o2PZvf3KCjbKkxWKBsq85/eFemB4JVTE=
|
||||||
github.com/smallstep/certinfo v1.5.1/go.mod h1:gA7HBbue0Wwr3kD60P2UtgTIFfMAOC66D3rzYhI0GZ4=
|
github.com/smallstep/certinfo v1.5.2/go.mod h1:gA7HBbue0Wwr3kD60P2UtgTIFfMAOC66D3rzYhI0GZ4=
|
||||||
github.com/smallstep/cli v0.16.1 h1:zFN/B5XF+WbvwfRya11SPfiT7g7LIMRSCaoeQNce3Hw=
|
github.com/smallstep/cli v0.17.6 h1:0npb8eQGDgEBPziYXb9tW4f4S5jt8aRRmEJvs97oh+Y=
|
||||||
github.com/smallstep/cli v0.16.1/go.mod h1:C8IES4TcHN3/Va6x9B+ugJM1t0pwzICHAg+RB2FASg4=
|
github.com/smallstep/cli v0.17.6/go.mod h1:IZoK7eNA/r6cTN9GCd6+M1omgb5Ic8mJjHHH9Bh078U=
|
||||||
github.com/smallstep/nosql v0.3.6/go.mod h1:h1zC/Z54uNHc8euquLED4qJNCrMHd3nytA141ZZh4qQ=
|
|
||||||
github.com/smallstep/nosql v0.3.8 h1:1/EWUbbEdz9ai0g9Fd09VekVjtxp+5+gIHpV2PdwW3o=
|
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/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 h1:vNzEJmaJL0XOZD8uouXLmYu4/aP1UQ/wHUopH3qKeYA=
|
||||||
github.com/smallstep/truststore v0.9.6/go.mod h1:HwHKRcBi0RUxxw1LYDpTRhYC4jZUuxPpkHdVonlkoDM=
|
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/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 v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
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/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
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.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.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.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
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.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.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.3.6/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.0 h1:OtISOGfH6sOWa1/qXqqAiOIAO6Z5J3AEAE18WAq6BiQ=
|
github.com/yuin/goldmark v1.4.1 h1:/vn0k+RBvwlxEmP5E7SZMqNxPhfMVFEJiykr15/0XKM=
|
||||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
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 h1:0SJnXjE4jDClMW6grE0xpNhwpqbPwkBTn8zpVw5C0SI=
|
||||||
github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01/go.mod h1:TwKQPa5XkCCRC2GRZ5wtfNUTQ2+9/i19mGRijFeJ4BE=
|
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=
|
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/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-alpha.0/go.mod h1:JZ79d3LV6NUfPjUxXrpiFAYcjhT+06qqw+i28snx8To=
|
||||||
go.etcd.io/etcd/v3 v3.5.0/go.mod h1:FldM0/VzcxYWLvWx1sdA7ghKw7C3L2DvUTzGrcEtsC4=
|
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-20210730143726-725912489c62/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
|
||||||
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/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.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
|
||||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
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/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/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
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/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/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
|
||||||
go.step.sm/linkedca v0.0.0-20210611183751-27424aae8d25 h1:ncJqviWswJT19IdnfOYQGKG1zL7IDy4lAJz1PuM3fgw=
|
go.step.sm/crypto v0.11.0 h1:VDpeVgEmqme/FK2w5QINxkOQ1FWOm/Wi2TwQXiacKr8=
|
||||||
go.step.sm/linkedca v0.0.0-20210611183751-27424aae8d25/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo=
|
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.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.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
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-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-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-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-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-20210915214749-c084706c2272 h1:3erb+vDS8lU1sxfDHF4/hhWyaXnhIaO+7RgL4fDZORA=
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
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-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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
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-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-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-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-20210913180222-943fd674d43e h1:+b/22bPvDYt4NPDcy4xAGCmON713ONAWFeY3Z7I3tR8=
|
||||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
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-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-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/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-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-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-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-20210915083310-ed5796bab164 h1:7ZDGnxgHAMw7thfC5bEos0RDAccZKxioiWBhfIe+tvw=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
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-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 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=
|
||||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/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.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.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-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-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/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.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
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.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.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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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-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-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-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-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.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.14.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=
|
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.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
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.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.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/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-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
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 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
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/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.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-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-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||||
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
|
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
|
||||||
|
|||||||
+2
-3
@@ -18,7 +18,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -630,9 +629,9 @@ func (StderrWriter) OpenWriter() (io.WriteCloser, error) {
|
|||||||
return notClosable{os.Stderr}, nil
|
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) {
|
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.
|
// 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}` | 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.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_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.issuer}` | The issuer DN of the client certificate
|
||||||
// `{http.request.tls.client.serial}` | The serial number 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
|
// `{http.request.tls.client.subject}` | The subject DN of the client certificate
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -227,6 +228,7 @@ func StatusCodeMatches(actual, configured int) bool {
|
|||||||
// never be outside of root. The resulting path can be used
|
// never be outside of root. The resulting path can be used
|
||||||
// with the local file system.
|
// with the local file system.
|
||||||
func SanitizedPathJoin(root, reqPath string) string {
|
func SanitizedPathJoin(root, reqPath string) string {
|
||||||
|
reqPath, _ = url.PathUnescape(reqPath)
|
||||||
if root == "" {
|
if root == "" {
|
||||||
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 "/"
|
// user can presumably browse "up" to parent folder if path is longer than "/"
|
||||||
canGoUp := len(urlPath) > 1
|
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.
|
// browseApplyQueryParams applies query parameters to the listing.
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ h1 a:hover {
|
|||||||
color: #319cff;
|
color: #319cff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: #800080;
|
||||||
|
}
|
||||||
|
|
||||||
header,
|
header,
|
||||||
#summary {
|
#summary {
|
||||||
padding-left: 5%;
|
padding-left: 5%;
|
||||||
@@ -426,7 +430,7 @@ footer {
|
|||||||
</footer>
|
</footer>
|
||||||
<script>
|
<script>
|
||||||
var filterEl = document.getElementById('filter');
|
var filterEl = document.getElementById('filter');
|
||||||
filterEl.focus();
|
filterEl.focus({ preventScroll: true });
|
||||||
|
|
||||||
function initFilter() {
|
function initFilter() {
|
||||||
if (!filterEl.value) {
|
if (!filterEl.value) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import (
|
|||||||
"github.com/dustin/go-humanize"
|
"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)
|
filesToHide := fsrv.transformHidePaths(repl)
|
||||||
|
|
||||||
var dirCount, fileCount int
|
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)
|
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 {
|
if isDir {
|
||||||
name += "/"
|
u.Path += "/"
|
||||||
dirCount++
|
dirCount++
|
||||||
} else {
|
} else {
|
||||||
fileCount++
|
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{
|
fileInfos = append(fileInfos, fileInfo{
|
||||||
IsDir: isDir,
|
IsDir: isDir,
|
||||||
IsSymlink: isSymlink(f),
|
IsSymlink: fileIsSymlink,
|
||||||
Name: f.Name(),
|
Name: name,
|
||||||
Size: f.Size(),
|
Size: size,
|
||||||
URL: u.String(),
|
URL: u.String(),
|
||||||
ModTime: f.ModTime().UTC(),
|
ModTime: f.ModTime().UTC(),
|
||||||
Mode: f.Mode(),
|
Mode: f.Mode(),
|
||||||
@@ -69,7 +80,7 @@ func (fsrv *FileServer) directoryListing(files []os.FileInfo, canGoUp bool, root
|
|||||||
Items: fileInfos,
|
Items: fileInfos,
|
||||||
NumDirs: dirCount,
|
NumDirs: dirCount,
|
||||||
NumFiles: fileCount,
|
NumFiles: fileCount,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// browseTemplateContext provides the template context for directory listings.
|
// browseTemplateContext provides the template context for directory listings.
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -60,7 +61,11 @@ type MatchFile struct {
|
|||||||
// directories are treated distinctly, so to match
|
// directories are treated distinctly, so to match
|
||||||
// a directory, the filepath MUST end in a forward
|
// a directory, the filepath MUST end in a forward
|
||||||
// slash `/`. To match a regular file, there must
|
// 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"`
|
TryFiles []string `json:"try_files,omitempty"`
|
||||||
|
|
||||||
// How to choose a file in TryFiles. Can be:
|
// 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 {
|
switch m.TryPolicy {
|
||||||
case "", tryPolicyFirstExist:
|
case "", tryPolicyFirstExist:
|
||||||
for _, f := range m.TryFiles {
|
for _, f := range m.TryFiles {
|
||||||
|
if err := parseErrorCode(f); err != nil {
|
||||||
|
caddyhttp.SetVar(r.Context(), caddyhttp.MatcherErrorVarKey, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
suffix, fullpath, remainder := prepareFilePath(f)
|
suffix, fullpath, remainder := prepareFilePath(f)
|
||||||
if info, exists := strictFileExists(fullpath); exists {
|
if info, exists := strictFileExists(fullpath); exists {
|
||||||
setPlaceholders(info, suffix, fullpath, remainder)
|
setPlaceholders(info, suffix, fullpath, remainder)
|
||||||
@@ -274,6 +283,20 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) {
|
|||||||
return
|
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
|
// strictFileExists returns true if file exists
|
||||||
// and matches the convention of the given file
|
// and matches the convention of the given file
|
||||||
// path. If the path ends in a forward slash,
|
// path. If the path ends in a forward slash,
|
||||||
|
|||||||
@@ -17,12 +17,31 @@ package fileserver
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFileMatcher(t *testing.T) {
|
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 {
|
for i, tc := range []struct {
|
||||||
path string
|
path string
|
||||||
expectedPath string
|
expectedPath string
|
||||||
@@ -63,6 +82,30 @@ func TestFileMatcher(t *testing.T) {
|
|||||||
path: "/missingfile.php",
|
path: "/missingfile.php",
|
||||||
matched: false,
|
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{
|
m := &MatchFile{
|
||||||
Root: "./testdata",
|
Root: "./testdata",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
weakrand "math/rand"
|
weakrand "math/rand"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -165,6 +166,16 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next c
|
|||||||
filesToHide := fsrv.transformHidePaths(repl)
|
filesToHide := fsrv.transformHidePaths(repl)
|
||||||
|
|
||||||
root := repl.ReplaceAll(fsrv.Root, ".")
|
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)
|
filename := caddyhttp.SanitizedPathJoin(root, r.URL.Path)
|
||||||
|
|
||||||
fsrv.logger.Debug("sanitized path join",
|
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
|
// replace
|
||||||
for fieldName, replacements := range ops.Replace {
|
for fieldName, replacements := range ops.Replace {
|
||||||
fieldName = repl.ReplaceAll(fieldName, "")
|
fieldName = http.CanonicalHeaderKey(repl.ReplaceAll(fieldName, ""))
|
||||||
|
|
||||||
// all fields...
|
// all fields...
|
||||||
if fieldName == "*" {
|
if fieldName == "*" {
|
||||||
@@ -237,11 +237,17 @@ func (ops HeaderOps) ApplyTo(hdr http.Header, repl *caddy.Replacer) {
|
|||||||
for _, r := range replacements {
|
for _, r := range replacements {
|
||||||
search := repl.ReplaceAll(r.Search, "")
|
search := repl.ReplaceAll(r.Search, "")
|
||||||
replace := repl.ReplaceAll(r.Replace, "")
|
replace := repl.ReplaceAll(r.Replace, "")
|
||||||
for i := range hdr[fieldName] {
|
for hdrFieldName, vals := range hdr {
|
||||||
if r.re != nil {
|
// see issue #4330 for why we don't simply use hdr[fieldName]
|
||||||
hdr[fieldName][i] = r.re.ReplaceAllString(hdr[fieldName][i], replace)
|
if http.CanonicalHeaderKey(hdrFieldName) != fieldName {
|
||||||
} else {
|
continue
|
||||||
hdr[fieldName][i] = strings.ReplaceAll(hdr[fieldName][i], search, replace)
|
}
|
||||||
|
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"},
|
"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()
|
rr := httptest.NewRecorder()
|
||||||
|
|
||||||
@@ -191,7 +213,7 @@ func TestHandler(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err := tc.handler.ServeHTTP(rr, req, next); err != nil {
|
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
|
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
|
// find the first mapping matching the input and return
|
||||||
// the requested destination/output value
|
// the requested destination/output value
|
||||||
for _, m := range h.Mappings {
|
for _, m := range h.Mappings {
|
||||||
if m.re != nil {
|
output := m.Outputs[destIdx]
|
||||||
if m.re.MatchString(input) {
|
if output == nil {
|
||||||
if output := m.Outputs[destIdx]; output == nil {
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
output = m.re.ReplaceAllString(input, m.Outputs[destIdx].(string))
|
|
||||||
return output, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if input == m.Input {
|
if m.re != nil {
|
||||||
if output := m.Outputs[destIdx]; output == nil {
|
var result []byte
|
||||||
|
matches := m.re.FindStringSubmatchIndex(input)
|
||||||
|
if matches == nil {
|
||||||
continue
|
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/http"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -97,7 +98,8 @@ type (
|
|||||||
// ```
|
// ```
|
||||||
MatchQuery url.Values
|
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,
|
// exact string comparisons of the field values. Fast prefix, suffix,
|
||||||
// and substring matches can also be done by suffixing, prefixing, or
|
// and substring matches can also be done by suffixing, prefixing, or
|
||||||
// surrounding the value with the wildcard `*` character, respectively.
|
// surrounding the value with the wildcard `*` character, respectively.
|
||||||
@@ -114,7 +116,8 @@ type (
|
|||||||
// (potentially leading to collisions).
|
// (potentially leading to collisions).
|
||||||
MatchHeaderRE map[string]*MatchRegexp
|
MatchHeaderRE map[string]*MatchRegexp
|
||||||
|
|
||||||
// MatchProtocol matches requests by protocol.
|
// MatchProtocol matches requests by protocol. Recognized values are
|
||||||
|
// "http", "https", and "grpc".
|
||||||
MatchProtocol string
|
MatchProtocol string
|
||||||
|
|
||||||
// MatchRemoteIP matches requests by client IP (or CIDR range).
|
// 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
|
// matchers within a set work the same (i.e. different matchers in
|
||||||
// the same set are AND'ed).
|
// the same set are AND'ed).
|
||||||
//
|
//
|
||||||
// Note that the generated docs which describe the structure of
|
// NOTE: The generated docs which describe the structure of this
|
||||||
// this module are wrong because of how this type unmarshals JSON
|
// module are wrong because of how this type unmarshals JSON in a
|
||||||
// in a custom way. The correct structure is:
|
// custom way. The correct structure is:
|
||||||
//
|
//
|
||||||
// ```json
|
// ```json
|
||||||
// [
|
// [
|
||||||
@@ -312,7 +315,15 @@ func (m MatchPath) Provision(_ caddy.Context) error {
|
|||||||
|
|
||||||
// Match returns true if r matches m.
|
// Match returns true if r matches m.
|
||||||
func (m MatchPath) Match(r *http.Request) bool {
|
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
|
// see #2917; Windows ignores trailing dots and spaces
|
||||||
// when accessing files (sigh), potentially causing a
|
// 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
|
// being matched by *.php to be treated as PHP scripts
|
||||||
lowerPath = strings.TrimRight(lowerPath, ". ")
|
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)
|
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
|
||||||
|
|
||||||
for _, matchPath := range m {
|
for _, matchPath := range m {
|
||||||
@@ -394,7 +415,26 @@ func (MatchPathRE) CaddyModule() caddy.ModuleInfo {
|
|||||||
// Match returns true if r matches m.
|
// Match returns true if r matches m.
|
||||||
func (m MatchPathRE) Match(r *http.Request) bool {
|
func (m MatchPathRE) Match(r *http.Request) bool {
|
||||||
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
|
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.
|
// CaddyModule returns the Caddy module information.
|
||||||
@@ -987,6 +1027,12 @@ var wordRE = regexp.MustCompile(`\w+`)
|
|||||||
|
|
||||||
const regexpPlaceholderPrefix = "http.regexp"
|
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
|
// Interface guards
|
||||||
var (
|
var (
|
||||||
_ RequestMatcher = (*MatchHost)(nil)
|
_ RequestMatcher = (*MatchHost)(nil)
|
||||||
|
|||||||
@@ -257,6 +257,21 @@ func TestPathMatcher(t *testing.T) {
|
|||||||
input: "/foo/BAR.txt",
|
input: "/foo/BAR.txt",
|
||||||
expect: true,
|
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{"*"},
|
match: MatchPath{"*"},
|
||||||
input: "/",
|
input: "/",
|
||||||
@@ -326,15 +341,30 @@ func TestPathREMatcher(t *testing.T) {
|
|||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: MatchPathRE{MatchRegexp{Pattern: "/foo"}},
|
match: MatchPathRE{MatchRegexp{Pattern: "^/foo"}},
|
||||||
input: "/foo",
|
input: "/foo",
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: MatchPathRE{MatchRegexp{Pattern: "/foo"}},
|
match: MatchPathRE{MatchRegexp{Pattern: "^/foo"}},
|
||||||
input: "/foo/",
|
input: "/foo/",
|
||||||
expect: true,
|
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"}},
|
match: MatchPathRE{MatchRegexp{Pattern: "/bar"}},
|
||||||
input: "/foo/",
|
input: "/foo/",
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func TestMetricsInstrumentedHandler(t *testing.T) {
|
|||||||
|
|
||||||
handlerErr = nil
|
handlerErr = nil
|
||||||
if err := ih.ServeHTTP(w, r, h); err != 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
|
// an empty handler - no errors, no header written
|
||||||
@@ -67,7 +67,7 @@ func TestMetricsInstrumentedHandler(t *testing.T) {
|
|||||||
w = httptest.NewRecorder()
|
w = httptest.NewRecorder()
|
||||||
|
|
||||||
if err := ih.ServeHTTP(w, r, h); err != nil {
|
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 {
|
if actual := w.Result().StatusCode; actual != 200 {
|
||||||
t.Errorf("Not same: expected status code %#v, but got %#v", 200, actual)
|
t.Errorf("Not same: expected status code %#v, but got %#v", 200, actual)
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
@@ -162,7 +162,7 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
|
|||||||
return "", true
|
return "", true
|
||||||
}
|
}
|
||||||
// replace real body with buffered data
|
// replace real body with buffered data
|
||||||
req.Body = ioutil.NopCloser(buf)
|
req.Body = io.NopCloser(buf)
|
||||||
return buf.String(), true
|
return buf.String(), true
|
||||||
|
|
||||||
// original request, before any internal changes
|
// original request, before any internal changes
|
||||||
@@ -353,6 +353,8 @@ func getReqTLSReplacement(req *http.Request, key string) (interface{}, bool) {
|
|||||||
case "client.certificate_pem":
|
case "client.certificate_pem":
|
||||||
block := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}
|
block := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}
|
||||||
return pem.EncodeToMemory(&block), true
|
return pem.EncodeToMemory(&block), true
|
||||||
|
case "client.certificate_der_base64":
|
||||||
|
return base64.StdEncoding.EncodeToString(cert.Raw), true
|
||||||
default:
|
default:
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ type ResponseMatcher struct {
|
|||||||
|
|
||||||
// If set, each header specified must be one of the
|
// If set, each header specified must be one of the
|
||||||
// specified values, with the same logic used by 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"`
|
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("from", "localhost", "Address on which to receive traffic")
|
||||||
fs.String("to", "", "Upstream address to which to to proxy 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("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
|
return fs
|
||||||
}(),
|
}(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -124,21 +124,22 @@ func (t *Transport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
|||||||
//
|
//
|
||||||
// is equivalent to a route consisting of:
|
// is equivalent to a route consisting of:
|
||||||
//
|
//
|
||||||
|
// # Add trailing slash for directory requests
|
||||||
// @canonicalPath {
|
// @canonicalPath {
|
||||||
// file {
|
// file {path}/index.php
|
||||||
// try_files {path}/index.php
|
// not path */
|
||||||
// }
|
|
||||||
// not {
|
|
||||||
// path */
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
// redir @canonicalPath {path}/ 308
|
// redir @canonicalPath {path}/ 308
|
||||||
//
|
//
|
||||||
// try_files {path} {path}/index.php index.php
|
// # If the requested file does not exist, try index files
|
||||||
//
|
// @indexFiles file {
|
||||||
// @phpFiles {
|
// try_files {path} {path}/index.php index.php
|
||||||
// path *.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 {
|
// reverse_proxy @phpFiles localhost:7777 {
|
||||||
// transport fastcgi {
|
// transport fastcgi {
|
||||||
// split .php
|
// split .php
|
||||||
@@ -172,6 +173,9 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
|||||||
// set the default index file for the try_files rewrites
|
// set the default index file for the try_files rewrites
|
||||||
indexFile := "index.php"
|
indexFile := "index.php"
|
||||||
|
|
||||||
|
// set up for explicitly overriding try_files
|
||||||
|
tryFiles := []string{}
|
||||||
|
|
||||||
// if the user specified a matcher token, use that
|
// if the user specified a matcher token, use that
|
||||||
// matcher in a route that wraps both of our routes;
|
// matcher in a route that wraps both of our routes;
|
||||||
// either way, strip the matcher token and pass
|
// either way, strip the matcher token and pass
|
||||||
@@ -237,6 +241,17 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
|||||||
}
|
}
|
||||||
indexFile = args[0]
|
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":
|
case "resolve_root_symlink":
|
||||||
args := dispenser.RemainingArgs()
|
args := dispenser.RemainingArgs()
|
||||||
dispenser.Delete()
|
dispenser.Delete()
|
||||||
@@ -318,10 +333,15 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
|
|||||||
HandlersRaw: []json.RawMessage{caddyconfig.JSONModuleObject(redirHandler, "handler", "static_response", nil)},
|
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
|
// route to rewrite to PHP index file
|
||||||
rewriteMatcherSet := caddy.ModuleMap{
|
rewriteMatcherSet := caddy.ModuleMap{
|
||||||
"file": h.JSON(fileserver.MatchFile{
|
"file": h.JSON(fileserver.MatchFile{
|
||||||
TryFiles: []string{"{http.request.uri.path}", "{http.request.uri.path}/" + indexFile, indexFile},
|
TryFiles: tryFiles,
|
||||||
SplitPath: extensions,
|
SplitPath: extensions,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -445,7 +444,7 @@ func (c *FCGIClient) Request(p map[string]string, req io.Reader) (resp *http.Res
|
|||||||
if chunked(resp.TransferEncoding) {
|
if chunked(resp.TransferEncoding) {
|
||||||
resp.Body = clientCloser{c, httputil.NewChunkedReader(rb)}
|
resp.Body = clientCloser{c, httputil.NewChunkedReader(rb)}
|
||||||
} else {
|
} else {
|
||||||
resp.Body = clientCloser{c, ioutil.NopCloser(rb)}
|
resp.Body = clientCloser{c, io.NopCloser(rb)}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
@@ -166,7 +165,7 @@ func sendFcgi(reqType int, fcgiParams map[string]string, data []byte, posts map[
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
content, _ = ioutil.ReadAll(resp.Body)
|
content, _ = io.ReadAll(resp.Body)
|
||||||
|
|
||||||
log.Println("c: send data length ≈", length, string(content))
|
log.Println("c: send data length ≈", length, string(content))
|
||||||
fcgi.Close()
|
fcgi.Close()
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -282,7 +281,7 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, host H
|
|||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
// drain any remaining body so connection could be re-used
|
// drain any remaining body so connection could be re-used
|
||||||
_, _ = io.Copy(ioutil.Discard, body)
|
_, _ = io.Copy(io.Discard, body)
|
||||||
resp.Body.Close()
|
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 body does not match regex, mark down
|
||||||
if h.HealthChecks.Active.bodyRegexp != nil {
|
if h.HealthChecks.Active.bodyRegexp != nil {
|
||||||
bodyBytes, err := ioutil.ReadAll(body)
|
bodyBytes, err := io.ReadAll(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.HealthChecks.Active.logger.Info("failed to read response body",
|
h.HealthChecks.Active.logger.Info("failed to read response body",
|
||||||
zap.String("host", hostAddr),
|
zap.String("host", hostAddr),
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
weakrand "math/rand"
|
weakrand "math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -364,7 +364,7 @@ func (t TLSConfig) MakeTLSClientConfig(ctx caddy.Context) (*tls.Config, error) {
|
|||||||
rootPool.AddCert(caCert)
|
rootPool.AddCert(caCert)
|
||||||
}
|
}
|
||||||
for _, pemFile := range t.RootCAPEMFiles {
|
for _, pemFile := range t.RootCAPEMFiles {
|
||||||
pemData, err := ioutil.ReadFile(pemFile)
|
pemData, err := os.ReadFile(pemFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed reading ca cert: %v", err)
|
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)
|
// should not permanently change r.Host; issue #3509)
|
||||||
reqHost := r.Host
|
reqHost := r.Host
|
||||||
reqHeader := r.Header
|
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() {
|
defer func() {
|
||||||
r.Host = reqHost // TODO: data race, see #4038
|
r.Host = reqHost // TODO: data race, see #4038
|
||||||
r.Header = reqHeader // TODO: data race, see #4038
|
r.Header = reqHeader // TODO: data race, see #4038
|
||||||
|
r.URL.Scheme = origURLScheme
|
||||||
|
r.URL.Host = origURLHost
|
||||||
}()
|
}()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
@@ -574,12 +588,11 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, repl *
|
|||||||
duration := time.Since(start)
|
duration := time.Since(start)
|
||||||
logger := h.logger.With(
|
logger := h.logger.With(
|
||||||
zap.String("upstream", di.Upstream.String()),
|
zap.String("upstream", di.Upstream.String()),
|
||||||
|
zap.Duration("duration", duration),
|
||||||
zap.Object("request", caddyhttp.LoggableHTTPRequest{Request: req}),
|
zap.Object("request", caddyhttp.LoggableHTTPRequest{Request: req}),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Debug("upstream roundtrip",
|
logger.Debug("upstream roundtrip", zap.Error(err))
|
||||||
zap.Duration("duration", duration),
|
|
||||||
zap.Error(err))
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Debug("upstream roundtrip",
|
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)
|
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
|
// see if any response handler is configured for this response from the backend
|
||||||
for i, rh := range h.HandleResponse {
|
for i, rh := range h.HandleResponse {
|
||||||
if rh.Match != nil && !rh.Match.Match(res.StatusCode, res.Header) {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
res.Body.Close()
|
|
||||||
|
|
||||||
// set up the replacer so that parts of the original response can be
|
// set up the replacer so that parts of the original response can be
|
||||||
// used for routing decisions
|
// used for routing decisions
|
||||||
for field, value := range res.Header {
|
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)
|
repl.Set("http.reverse_proxy.status_text", res.Status)
|
||||||
|
|
||||||
h.logger.Debug("handling response", zap.Int("handler", i))
|
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
|
// wrap error in roundtripSucceeded so caller knows that
|
||||||
// the roundtrip was successful and to not retry
|
// the roundtrip was successful and to not retry
|
||||||
return roundtripSucceeded{routeErr}
|
return roundtripSucceeded{routeErr}
|
||||||
@@ -691,15 +717,17 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, repl *
|
|||||||
}
|
}
|
||||||
|
|
||||||
rw.WriteHeader(res.StatusCode)
|
rw.WriteHeader(res.StatusCode)
|
||||||
err = h.copyResponse(rw, res.Body, h.flushInterval(req, res))
|
if !bodyClosed {
|
||||||
res.Body.Close() // close now, instead of defer, to populate res.Trailer
|
err = h.copyResponse(rw, res.Body, h.flushInterval(req, res))
|
||||||
if err != nil {
|
res.Body.Close() // close now, instead of defer, to populate res.Trailer
|
||||||
// we're streaming the response and we've already written headers, so
|
if err != nil {
|
||||||
// there's nothing an error handler can do to recover at this point;
|
// we're streaming the response and we've already written headers, so
|
||||||
// the standard lib's proxy panics at this point, but we'll just log
|
// there's nothing an error handler can do to recover at this point;
|
||||||
// the error and abort the stream here
|
// the standard lib's proxy panics at this point, but we'll just log
|
||||||
h.logger.Error("aborting with incomplete response", zap.Error(err))
|
// the error and abort the stream here
|
||||||
return nil
|
h.logger.Error("aborting with incomplete response", zap.Error(err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(res.Trailer) > 0 {
|
if len(res.Trailer) > 0 {
|
||||||
|
|||||||
@@ -200,6 +200,15 @@ func wrapRoute(route Route) Middleware {
|
|||||||
|
|
||||||
// route must match at least one of the matcher sets
|
// route must match at least one of the matcher sets
|
||||||
if !route.MatcherSets.AnyMatch(req) {
|
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)
|
return nextCopy.ServeHTTP(rw, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ package caddyhttp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -44,7 +44,7 @@ func TestStaticResponseHandler(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resp := w.Result()
|
resp := w.Result()
|
||||||
respBody, _ := ioutil.ReadAll(resp.Body)
|
respBody, _ := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusNotFound {
|
if resp.StatusCode != http.StatusNotFound {
|
||||||
t.Errorf("expected status %d but got %d", http.StatusNotFound, resp.StatusCode)
|
t.Errorf("expected status %d but got %d", http.StatusNotFound, resp.StatusCode)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package templates
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -90,9 +91,25 @@ func init() {
|
|||||||
// {{httpInclude "/foo/bar?q=val"}}
|
// {{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`
|
// ##### `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
|
// {{include "path/to/file.html"}} // no arguments
|
||||||
@@ -220,7 +237,8 @@ type Templates struct {
|
|||||||
// Default is text/plain, text/markdown, and text/html.
|
// Default is text/plain, text/markdown, and text/html.
|
||||||
MIMETypes []string `json:"mime_types,omitempty"`
|
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"`
|
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())
|
err := ctx.executeTemplateInBuffer(r.URL.Path, rr.Buffer())
|
||||||
if err != nil {
|
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)
|
return caddyhttp.Error(http.StatusInternalServerError, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,24 +46,26 @@ type TemplateContext struct {
|
|||||||
RespHeader WrappedHeader
|
RespHeader WrappedHeader
|
||||||
|
|
||||||
config *Templates
|
config *Templates
|
||||||
|
tpl *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTemplate returns a new template intended to be evaluated with this
|
// NewTemplate returns a new template intended to be evaluated with this
|
||||||
// context, as it is initialized with configuration from this context.
|
// context, as it is initialized with configuration from this context.
|
||||||
func (c TemplateContext) NewTemplate(tplName string) *template.Template {
|
func (c *TemplateContext) NewTemplate(tplName string) *template.Template {
|
||||||
tpl := template.New(tplName)
|
c.tpl = template.New(tplName)
|
||||||
|
|
||||||
// customize delimiters, if applicable
|
// customize delimiters, if applicable
|
||||||
if c.config != nil && len(c.config.Delimiters) == 2 {
|
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
|
// add sprig library
|
||||||
tpl.Funcs(sprigFuncMap)
|
c.tpl.Funcs(sprigFuncMap)
|
||||||
|
|
||||||
// add our own library
|
// add our own library
|
||||||
tpl.Funcs(template.FuncMap{
|
c.tpl.Funcs(template.FuncMap{
|
||||||
"include": c.funcInclude,
|
"include": c.funcInclude,
|
||||||
|
"import": c.funcImport,
|
||||||
"httpInclude": c.funcHTTPInclude,
|
"httpInclude": c.funcHTTPInclude,
|
||||||
"stripHTML": c.funcStripHTML,
|
"stripHTML": c.funcStripHTML,
|
||||||
"markdown": c.funcMarkdown,
|
"markdown": c.funcMarkdown,
|
||||||
@@ -74,8 +76,7 @@ func (c TemplateContext) NewTemplate(tplName string) *template.Template {
|
|||||||
"fileExists": c.funcFileExists,
|
"fileExists": c.funcFileExists,
|
||||||
"httpError": c.funcHTTPError,
|
"httpError": c.funcHTTPError,
|
||||||
})
|
})
|
||||||
|
return c.tpl
|
||||||
return tpl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OriginalReq returns the original, unmodified, un-rewritten request as
|
// OriginalReq returns the original, unmodified, un-rewritten request as
|
||||||
@@ -85,26 +86,13 @@ func (c TemplateContext) OriginalReq() http.Request {
|
|||||||
return or
|
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
|
// 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
|
// trusted files. If it is not trusted, be sure to use escaping functions
|
||||||
// in your template.
|
// in your template.
|
||||||
func (c TemplateContext) funcInclude(filename string, args ...interface{}) (string, error) {
|
func (c TemplateContext) funcInclude(filename string, args ...interface{}) (string, error) {
|
||||||
if c.Root == nil {
|
bodyBuf, err := c.readFileToBuffer(filename)
|
||||||
return "", fmt.Errorf("root file system not specified")
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -119,6 +107,30 @@ func (c TemplateContext) funcInclude(filename string, args ...interface{}) (stri
|
|||||||
return bodyBuf.String(), nil
|
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
|
// funcHTTPInclude returns the body of a virtual (lightweight) request
|
||||||
// to the given URI on the same server. Note that included bodies
|
// to the given URI on the same server. Note that included bodies
|
||||||
// are NOT escaped, so you should only include trusted resources.
|
// 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.Host = c.Req.Host
|
||||||
virtReq.Header = c.Req.Header.Clone()
|
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.Trailer = c.Req.Trailer.Clone()
|
||||||
virtReq.Header.Set(recursionPreventionHeader, strconv.Itoa(recursionCount))
|
virtReq.Header.Set(recursionPreventionHeader, strconv.Itoa(recursionCount))
|
||||||
|
|
||||||
@@ -167,17 +180,34 @@ func (c TemplateContext) funcHTTPInclude(uri string) (string, error) {
|
|||||||
return buf.String(), nil
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c TemplateContext) executeTemplateInBuffer(tplName string, buf *bytes.Buffer) error {
|
// funcImport parses the filename into the current template stack. The imported
|
||||||
tpl := c.NewTemplate(tplName)
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.Reset() // reuse buffer for output
|
buf.Reset() // reuse buffer for output
|
||||||
|
|
||||||
return parsedTpl.Execute(buf, c)
|
return c.tpl.Execute(buf, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c TemplateContext) funcPlaceholder(name string) string {
|
func (c TemplateContext) funcPlaceholder(name string) string {
|
||||||
@@ -350,9 +380,8 @@ func (c TemplateContext) funcFileExists(filename string) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// funcHTTPError returns a structured HTTP handler error. EXPERIMENTAL.
|
// funcHTTPError returns a structured HTTP handler error. EXPERIMENTAL; SUBJECT TO CHANGE.
|
||||||
// TODO: Requires https://github.com/golang/go/issues/34201 to be fixed (Go 1.17).
|
// Example usage: `{{if not (fileExists $includeFile)}}{{httpError 404}}{{end}}`
|
||||||
// Example usage might be: `{{if not (fileExists $includeFile)}}{{httpError 404}}{{end}}`
|
|
||||||
func (c TemplateContext) funcHTTPError(statusCode int) (bool, error) {
|
func (c TemplateContext) funcHTTPError(statusCode int) (bool, error) {
|
||||||
return false, caddyhttp.Error(statusCode, nil)
|
return false, caddyhttp.Error(statusCode, nil)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ package templates
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -26,10 +26,49 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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) {
|
func TestMarkdown(t *testing.T) {
|
||||||
context := getContextOrFail(t)
|
tplContext := getContextOrFail(t)
|
||||||
|
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
body string
|
body string
|
||||||
@@ -40,7 +79,7 @@ func TestMarkdown(t *testing.T) {
|
|||||||
expect: "<ul>\n<li>str1</li>\n<li>str2</li>\n</ul>\n",
|
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 {
|
if result != test.expect {
|
||||||
t.Errorf("Test %d: expected '%s' but got '%s'", i, test.expect, result)
|
t.Errorf("Test %d: expected '%s' but got '%s'", i, test.expect, result)
|
||||||
}
|
}
|
||||||
@@ -81,9 +120,9 @@ func TestCookie(t *testing.T) {
|
|||||||
expect: "cookieValue",
|
expect: "cookieValue",
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
context := getContextOrFail(t)
|
tplContext := getContextOrFail(t)
|
||||||
context.Req.AddCookie(test.cookie)
|
tplContext.Req.AddCookie(test.cookie)
|
||||||
actual := context.Cookie(test.cookieName)
|
actual := tplContext.Cookie(test.cookieName)
|
||||||
if actual != test.expect {
|
if actual != test.expect {
|
||||||
t.Errorf("Test %d: Expected cookie value '%s' but got '%s' for cookie with name '%s'",
|
t.Errorf("Test %d: Expected cookie value '%s' but got '%s' for cookie with name '%s'",
|
||||||
i, test.expect, actual, test.cookieName)
|
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) {
|
func TestCookieMultipleCookies(t *testing.T) {
|
||||||
context := getContextOrFail(t)
|
tplContext := getContextOrFail(t)
|
||||||
|
|
||||||
cookieNameBase, cookieValueBase := "cookieName", "cookieValue"
|
cookieNameBase, cookieValueBase := "cookieName", "cookieValue"
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
context.Req.AddCookie(&http.Cookie{
|
tplContext.Req.AddCookie(&http.Cookie{
|
||||||
Name: fmt.Sprintf("%s%d", cookieNameBase, i),
|
Name: fmt.Sprintf("%s%d", cookieNameBase, i),
|
||||||
Value: fmt.Sprintf("%s%d", cookieValueBase, i),
|
Value: fmt.Sprintf("%s%d", cookieValueBase, i),
|
||||||
})
|
})
|
||||||
@@ -105,7 +278,7 @@ func TestCookieMultipleCookies(t *testing.T) {
|
|||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
expectedCookieVal := fmt.Sprintf("%s%d", cookieValueBase, 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 {
|
if actualCookieVal != expectedCookieVal {
|
||||||
t.Errorf("Expected cookie value %s, found %s", expectedCookieVal, actualCookieVal)
|
t.Errorf("Expected cookie value %s, found %s", expectedCookieVal, actualCookieVal)
|
||||||
}
|
}
|
||||||
@@ -113,7 +286,7 @@ func TestCookieMultipleCookies(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIP(t *testing.T) {
|
func TestIP(t *testing.T) {
|
||||||
context := getContextOrFail(t)
|
tplContext := getContextOrFail(t)
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
inputRemoteAddr string
|
inputRemoteAddr string
|
||||||
expect string
|
expect string
|
||||||
@@ -124,15 +297,15 @@ func TestIP(t *testing.T) {
|
|||||||
{"[2001:db8:a0b:12f0::1]", "[2001:db8:a0b:12f0::1]"},
|
{"[2001:db8:a0b:12f0::1]", "[2001:db8:a0b:12f0::1]"},
|
||||||
{`[fe80:1::3%eth0]:44`, `fe80:1::3%eth0`},
|
{`[fe80:1::3%eth0]:44`, `fe80:1::3%eth0`},
|
||||||
} {
|
} {
|
||||||
context.Req.RemoteAddr = test.inputRemoteAddr
|
tplContext.Req.RemoteAddr = test.inputRemoteAddr
|
||||||
if actual := context.RemoteIP(); actual != test.expect {
|
if actual := tplContext.RemoteIP(); actual != test.expect {
|
||||||
t.Errorf("Test %d: Expected %s but got %s", i, test.expect, actual)
|
t.Errorf("Test %d: Expected %s but got %s", i, test.expect, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStripHTML(t *testing.T) {
|
func TestStripHTML(t *testing.T) {
|
||||||
context := getContextOrFail(t)
|
tplContext := getContextOrFail(t)
|
||||||
|
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
input string
|
input string
|
||||||
@@ -169,7 +342,7 @@ func TestStripHTML(t *testing.T) {
|
|||||||
expect: `<h1hi`,
|
expect: `<h1hi`,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
actual := context.funcStripHTML(test.input)
|
actual := tplContext.funcStripHTML(test.input)
|
||||||
if actual != test.expect {
|
if actual != test.expect {
|
||||||
t.Errorf("Test %d: Expected %s, found %s. Input was StripHTML(%s)", i, test.expect, actual, test.input)
|
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,
|
verifyErr: os.IsNotExist,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
context := getContextOrFail(t)
|
tplContext := getContextOrFail(t)
|
||||||
var dirPath string
|
var dirPath string
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// create files for test case
|
// create files for test case
|
||||||
if test.fileNames != nil {
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Test %d: Expected no error creating directory, got: '%s'", i, err.Error())
|
t.Fatalf("Test %d: Expected no error creating directory, got: '%s'", i, err.Error())
|
||||||
}
|
}
|
||||||
for _, name := range test.fileNames {
|
for _, name := range test.fileNames {
|
||||||
absFilePath := filepath.Join(dirPath, name)
|
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)
|
os.RemoveAll(dirPath)
|
||||||
t.Fatalf("Test %d: Expected no error creating file, got: '%s'", i, err.Error())
|
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
|
// perform test
|
||||||
input := filepath.ToSlash(filepath.Join(filepath.Base(dirPath), test.inputBase))
|
input := filepath.ToSlash(filepath.Join(filepath.Base(dirPath), test.inputBase))
|
||||||
actual, err := context.funcListFiles(input)
|
actual, err := tplContext.funcListFiles(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !test.shouldErr {
|
if !test.shouldErr {
|
||||||
t.Errorf("Test %d: Expected no error, got: '%s'", i, err)
|
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) {
|
func TestSplitFrontMatter(t *testing.T) {
|
||||||
context := getContextOrFail(t)
|
tplContext := getContextOrFail(t)
|
||||||
|
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
input string
|
input string
|
||||||
@@ -332,7 +505,7 @@ title = "Welcome"
|
|||||||
body: "\n### Test",
|
body: "\n### Test",
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
result, _ := context.funcSplitFrontMatter(test.input)
|
result, _ := tplContext.funcSplitFrontMatter(test.input)
|
||||||
if result.Meta["title"] != test.expect {
|
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)
|
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 {
|
func getContextOrFail(t *testing.T) TemplateContext {
|
||||||
context, err := initTestContext()
|
tplContext, err := initTestContext()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to prepare test context: %v", err)
|
t.Fatalf("failed to prepare test context: %v", err)
|
||||||
}
|
}
|
||||||
return context
|
return tplContext
|
||||||
}
|
}
|
||||||
|
|
||||||
func initTestContext() (TemplateContext, error) {
|
func initTestContext() (TemplateContext, error) {
|
||||||
|
|||||||
@@ -29,9 +29,14 @@ func init() {
|
|||||||
caddy.RegisterModule(MatchVarsRE{})
|
caddy.RegisterModule(MatchVarsRE{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// VarsMiddleware is an HTTP middleware which sets variables
|
// VarsMiddleware is an HTTP middleware which sets variables to
|
||||||
// in the context, mainly for use by placeholders. The
|
// have values that can be used in the HTTP request handler
|
||||||
// placeholders have the form: `{http.vars.variable_name}`
|
// 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
|
type VarsMiddleware map[string]string
|
||||||
|
|
||||||
// CaddyModule returns the Caddy module information.
|
// CaddyModule returns the Caddy module information.
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -137,11 +137,11 @@ type KeyPair struct {
|
|||||||
func (kp KeyPair) Load() (*x509.Certificate, interface{}, error) {
|
func (kp KeyPair) Load() (*x509.Certificate, interface{}, error) {
|
||||||
switch kp.Format {
|
switch kp.Format {
|
||||||
case "", "pem_file":
|
case "", "pem_file":
|
||||||
certData, err := ioutil.ReadFile(kp.Certificate)
|
certData, err := os.ReadFile(kp.Certificate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
keyData, err := ioutil.ReadFile(kp.PrivateKey)
|
keyData, err := os.ReadFile(kp.PrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,15 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PKI provides Public Key Infrastructure facilities for Caddy.
|
// 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 {
|
type PKI struct {
|
||||||
// The CAs to manage. Each CA is keyed by an ID that is used
|
// The certificate authorities to manage. Each CA is keyed by an
|
||||||
// to uniquely identify it from other CAs. The default CA ID
|
// ID that is used to uniquely identify it from other CAs.
|
||||||
// is "local".
|
// The default CA ID is "local".
|
||||||
CAs map[string]*CA `json:"certificate_authorities,omitempty"`
|
CAs map[string]*CA `json:"certificate_authorities,omitempty"`
|
||||||
|
|
||||||
ctx caddy.Context
|
ctx caddy.Context
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -36,20 +36,16 @@ func init() {
|
|||||||
caddy.RegisterModule(ACMEIssuer{})
|
caddy.RegisterModule(ACMEIssuer{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACMEIssuer makes an ACME manager
|
// ACMEIssuer manages certificates using the ACME protocol (RFC 8555).
|
||||||
// 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...
|
|
||||||
type ACMEIssuer struct {
|
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"`
|
CA string `json:"ca,omitempty"`
|
||||||
|
|
||||||
// The URL to the test CA's ACME directory endpoint.
|
// The URL to the test CA's ACME directory endpoint.
|
||||||
// This endpoint is only used during retries if there
|
// 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"`
|
TestCA string `json:"test_ca,omitempty"`
|
||||||
|
|
||||||
// Your email address, so the CA can contact you if necessary.
|
// 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"`
|
ExternalAccount *acme.EAB `json:"external_account,omitempty"`
|
||||||
|
|
||||||
// Time to wait before timing out an ACME operation.
|
// Time to wait before timing out an ACME operation.
|
||||||
|
// Default: 0 (no timeout)
|
||||||
ACMETimeout caddy.Duration `json:"acme_timeout,omitempty"`
|
ACMETimeout caddy.Duration `json:"acme_timeout,omitempty"`
|
||||||
|
|
||||||
// Configures the various ACME challenge types.
|
// Configures the various ACME challenge types.
|
||||||
@@ -155,7 +152,7 @@ func (iss *ACMEIssuer) Provision(ctx caddy.Context) error {
|
|||||||
if len(iss.TrustedRootsPEMFiles) > 0 {
|
if len(iss.TrustedRootsPEMFiles) > 0 {
|
||||||
iss.rootPool = x509.NewCertPool()
|
iss.rootPool = x509.NewCertPool()
|
||||||
for _, pemFile := range iss.TrustedRootsPEMFiles {
|
for _, pemFile := range iss.TrustedRootsPEMFiles {
|
||||||
pemData, err := ioutil.ReadFile(pemFile)
|
pemData, err := os.ReadFile(pemFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("loading trusted root CA's PEM file: %s: %v", pemFile, err)
|
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.
|
// AutomationConfig governs the automated management of TLS certificates.
|
||||||
type AutomationConfig struct {
|
type AutomationConfig struct {
|
||||||
// The list of automation policies. The first matching
|
// The list of automation policies. The first policy matching
|
||||||
// policy will be applied for a given certificate/name.
|
// a certificate or subject name will be applied.
|
||||||
Policies []*AutomationPolicy `json:"policies,omitempty"`
|
Policies []*AutomationPolicy `json:"policies,omitempty"`
|
||||||
|
|
||||||
// On-Demand TLS defers certificate operations to the
|
// On-Demand TLS defers certificate operations to the
|
||||||
@@ -39,7 +39,7 @@ type AutomationConfig struct {
|
|||||||
// In 2015, Caddy became the first web server to
|
// In 2015, Caddy became the first web server to
|
||||||
// implement this experimental technology.
|
// 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 only configures it for when it is used. To enable
|
||||||
// it, create an automation policy with `on_demand`.
|
// it, create an automation policy with `on_demand`.
|
||||||
OnDemand *OnDemandConfig `json:"on_demand,omitempty"`
|
OnDemand *OnDemandConfig `json:"on_demand,omitempty"`
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/caddyserver/caddy/v2"
|
"github.com/caddyserver/caddy/v2"
|
||||||
@@ -369,7 +369,7 @@ func (clientauth *ClientAuthentication) ConfigureTLSConfig(cfg *tls.Config) erro
|
|||||||
caPool.AddCert(clientCA)
|
caPool.AddCert(clientCA)
|
||||||
}
|
}
|
||||||
for _, pemFile := range clientauth.TrustedCACertPEMFiles {
|
for _, pemFile := range clientauth.TrustedCACertPEMFiles {
|
||||||
pemContents, err := ioutil.ReadFile(pemFile)
|
pemContents, err := os.ReadFile(pemFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading %s: %v", pemFile, err)
|
return fmt.Errorf("reading %s: %v", pemFile, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ package caddytls
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"os"
|
||||||
|
|
||||||
"github.com/caddyserver/caddy/v2"
|
"github.com/caddyserver/caddy/v2"
|
||||||
)
|
)
|
||||||
@@ -59,11 +59,11 @@ type CertKeyFilePair struct {
|
|||||||
func (fl FileLoader) LoadCertificates() ([]Certificate, error) {
|
func (fl FileLoader) LoadCertificates() ([]Certificate, error) {
|
||||||
certs := make([]Certificate, 0, len(fl))
|
certs := make([]Certificate, 0, len(fl))
|
||||||
for _, pair := range fl {
|
for _, pair := range fl {
|
||||||
certData, err := ioutil.ReadFile(pair.Certificate)
|
certData, err := os.ReadFile(pair.Certificate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
keyData, err := ioutil.ReadFile(pair.Key)
|
keyData, err := os.ReadFile(pair.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -79,7 +78,7 @@ func (fl FolderLoader) LoadCertificates() ([]Certificate, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func x509CertFromCertAndKeyPEMFile(fpath string) (tls.Certificate, error) {
|
func x509CertFromCertAndKeyPEMFile(fpath string) (tls.Certificate, error) {
|
||||||
bundle, err := ioutil.ReadFile(fpath)
|
bundle, err := os.ReadFile(fpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tls.Certificate{}, err
|
return tls.Certificate{}, err
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-18
@@ -47,7 +47,7 @@ type TLS struct {
|
|||||||
// have to be refreshed manually before they expire.
|
// have to be refreshed manually before they expire.
|
||||||
CertificatesRaw caddy.ModuleMap `json:"certificates,omitempty" caddy:"namespace=tls.certificates"`
|
CertificatesRaw caddy.ModuleMap `json:"certificates,omitempty" caddy:"namespace=tls.certificates"`
|
||||||
|
|
||||||
// Configures the automation of certificate management.
|
// Configures certificate automation.
|
||||||
Automation *AutomationConfig `json:"automation,omitempty"`
|
Automation *AutomationConfig `json:"automation,omitempty"`
|
||||||
|
|
||||||
// Configures session ticket ephemeral keys (STEKs).
|
// Configures session ticket ephemeral keys (STEKs).
|
||||||
@@ -458,20 +458,17 @@ func (t *TLS) cleanStorageUnits() {
|
|||||||
defer storageCleanMu.Unlock()
|
defer storageCleanMu.Unlock()
|
||||||
|
|
||||||
// If storage was cleaned recently, don't do it again for now. Although the ticker
|
// 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
|
// calling this function drops missed ticks for us, config reloads discard the old
|
||||||
// with a new one, possibly invoking a cleaning to happen again too soon.
|
// ticker and replace it with a new one, possibly invoking a cleaning to happen again
|
||||||
// (We divide the interval by 2 because the actual cleaning takes non-zero time,
|
// too soon. (We divide the interval by 2 because the actual cleaning takes non-zero
|
||||||
// and we don't want to skip cleanings if we don't have to; whereas if a cleaning
|
// 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
|
// 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
|
// constantly cleaning. This allows cleanings to take up to half the interval's
|
||||||
// duration before we decide to skip the next one.)
|
// duration before we decide to skip the next one.)
|
||||||
if !storageClean.IsZero() && time.Since(storageClean) < t.storageCleanInterval()/2 {
|
if !storageClean.IsZero() && time.Since(storageClean) < t.storageCleanInterval()/2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark when storage cleaning was last initiated
|
|
||||||
storageClean = time.Now()
|
|
||||||
|
|
||||||
options := certmagic.CleanStorageOptions{
|
options := certmagic.CleanStorageOptions{
|
||||||
OCSPStaples: true,
|
OCSPStaples: true,
|
||||||
ExpiredCerts: 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")
|
t.logger.Info("finished cleaning storage units")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,14 +527,14 @@ type Certificate struct {
|
|||||||
Tags []string
|
Tags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// AutomateLoader will automatically manage certificates for the names
|
// AutomateLoader will automatically manage certificates for the names in the
|
||||||
// in the list, including obtaining and renewing certificates. Automated
|
// list, including obtaining and renewing certificates. Automated certificates
|
||||||
// certificates are managed according to their matching automation policy,
|
// are managed according to their matching automation policy, configured
|
||||||
// configured elsewhere in this app.
|
// elsewhere in this app.
|
||||||
//
|
//
|
||||||
// This is a no-op certificate loader module that is treated as a special
|
// Technically, this is a no-op certificate loader module that is treated as
|
||||||
// case: it uses this app's automation features to load certificates for the
|
// a special case: it uses this app's automation features to load certificates
|
||||||
// list of hostnames, rather than loading certificates manually.
|
// for the list of hostnames, rather than loading certificates manually.
|
||||||
type AutomateLoader []string
|
type AutomateLoader []string
|
||||||
|
|
||||||
// CaddyModule returns the Caddy module information.
|
// CaddyModule returns the Caddy module information.
|
||||||
@@ -549,8 +549,7 @@ func (AutomateLoader) CaddyModule() caddy.ModuleInfo {
|
|||||||
type CertCacheOptions struct {
|
type CertCacheOptions struct {
|
||||||
// Maximum number of certificates to allow in the
|
// Maximum number of certificates to allow in the
|
||||||
// cache. If reached, certificates will be randomly
|
// cache. If reached, certificates will be randomly
|
||||||
// evicted to make room for new ones. Default: 0
|
// evicted to make room for new ones. Default: 10,000
|
||||||
// (no limit).
|
|
||||||
Capacity int `json:"capacity,omitempty"`
|
Capacity int `json:"capacity,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user