mirror of
https://github.com/caddyserver/caddy.git
synced 2025-02-25 17:29:16 +01:00
Merge branch 'master' into acmev2
# Conflicts: # caddyhttp/httpserver/replacer.go # caddyhttp/httpserver/replacer_test.go
This commit is contained in:
commit
2ed1dd6afc
9 changed files with 258 additions and 46 deletions
|
@ -33,8 +33,11 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"crypto/tls"
|
||||||
|
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||||
|
"github.com/mholt/caddy/caddytls"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler is a middleware type that can handle requests as a FastCGI client.
|
// Handler is a middleware type that can handle requests as a FastCGI client.
|
||||||
|
@ -323,6 +326,19 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, fpath string) (map[string]
|
||||||
// Some web apps rely on knowing HTTPS or not
|
// Some web apps rely on knowing HTTPS or not
|
||||||
if r.TLS != nil {
|
if r.TLS != nil {
|
||||||
env["HTTPS"] = "on"
|
env["HTTPS"] = "on"
|
||||||
|
// and pass the protocol details in a manner compatible with apache's mod_ssl
|
||||||
|
// (which is why they have a SSL_ prefix and not TLS_).
|
||||||
|
v, ok := tlsProtocolStringToMap[r.TLS.Version]
|
||||||
|
if ok {
|
||||||
|
env["SSL_PROTOCOL"] = v
|
||||||
|
}
|
||||||
|
// and pass the cipher suite in a manner compatible with apache's mod_ssl
|
||||||
|
for k, v := range caddytls.SupportedCiphersMap {
|
||||||
|
if v == r.TLS.CipherSuite {
|
||||||
|
env["SSL_CIPHER"] = k
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add env variables from config (with support for placeholders in values)
|
// Add env variables from config (with support for placeholders in values)
|
||||||
|
@ -465,3 +481,11 @@ type LogError string
|
||||||
func (l LogError) Error() string {
|
func (l LogError) Error() string {
|
||||||
return string(l)
|
return string(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map of supported protocols to Apache ssl_mod format
|
||||||
|
// Note that these are slightly different from SupportedProtocols in caddytls/config.go's
|
||||||
|
var tlsProtocolStringToMap = map[uint16]string{
|
||||||
|
tls.VersionTLS10: "TLSv1",
|
||||||
|
tls.VersionTLS11: "TLSv1.1",
|
||||||
|
tls.VersionTLS12: "TLSv1.2",
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
|
"github.com/mholt/caddy/caddytls"
|
||||||
)
|
)
|
||||||
|
|
||||||
// requestReplacer is a strings.Replacer which is used to
|
// requestReplacer is a strings.Replacer which is used to
|
||||||
|
@ -140,6 +141,14 @@ func canLogRequest(r *http.Request) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unescapeBraces finds escaped braces in s and returns
|
||||||
|
// a string with those braces unescaped.
|
||||||
|
func unescapeBraces(s string) string {
|
||||||
|
s = strings.Replace(s, "\\{", "{", -1)
|
||||||
|
s = strings.Replace(s, "\\}", "}", -1)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// Replace performs a replacement of values on s and returns
|
// Replace performs a replacement of values on s and returns
|
||||||
// the string with the replaced values.
|
// the string with the replaced values.
|
||||||
func (r *replacer) Replace(s string) string {
|
func (r *replacer) Replace(s string) string {
|
||||||
|
@ -149,32 +158,59 @@ func (r *replacer) Replace(s string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
result := ""
|
result := ""
|
||||||
|
Placeholders: // process each placeholder in sequence
|
||||||
for {
|
for {
|
||||||
idxStart := strings.Index(s, "{")
|
var idxStart, idxEnd int
|
||||||
if idxStart == -1 {
|
|
||||||
// no placeholder anymore
|
|
||||||
break
|
|
||||||
}
|
|
||||||
idxEnd := strings.Index(s[idxStart:], "}")
|
|
||||||
if idxEnd == -1 {
|
|
||||||
// unpaired placeholder
|
|
||||||
break
|
|
||||||
}
|
|
||||||
idxEnd += idxStart
|
|
||||||
|
|
||||||
// get a replacement
|
idxOffset := 0
|
||||||
placeholder := s[idxStart : idxEnd+1]
|
for { // find first unescaped opening brace
|
||||||
|
searchSpace := s[idxOffset:]
|
||||||
|
idxStart = strings.Index(searchSpace, "{")
|
||||||
|
if idxStart == -1 {
|
||||||
|
// no more placeholders
|
||||||
|
break Placeholders
|
||||||
|
}
|
||||||
|
if idxStart == 0 || searchSpace[idxStart-1] != '\\' {
|
||||||
|
// preceding character is not an escape
|
||||||
|
idxStart += idxOffset
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// the brace we found was escaped
|
||||||
|
// search the rest of the string next
|
||||||
|
idxOffset += idxStart + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
idxOffset = 0
|
||||||
|
for { // find first unescaped closing brace
|
||||||
|
searchSpace := s[idxStart+idxOffset:]
|
||||||
|
idxEnd = strings.Index(searchSpace, "}")
|
||||||
|
if idxEnd == -1 {
|
||||||
|
// unpaired placeholder
|
||||||
|
break Placeholders
|
||||||
|
}
|
||||||
|
if idxEnd == 0 || searchSpace[idxEnd-1] != '\\' {
|
||||||
|
// preceding character is not an escape
|
||||||
|
idxEnd += idxOffset + idxStart
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// the brace we found was escaped
|
||||||
|
// search the rest of the string next
|
||||||
|
idxOffset += idxEnd + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a replacement for the unescaped placeholder
|
||||||
|
placeholder := unescapeBraces(s[idxStart : idxEnd+1])
|
||||||
replacement := r.getSubstitution(placeholder)
|
replacement := r.getSubstitution(placeholder)
|
||||||
|
|
||||||
// append prefix + replacement
|
// append unescaped prefix + replacement
|
||||||
result += s[:idxStart] + replacement
|
result += strings.TrimPrefix(unescapeBraces(s[:idxStart]), "\\") + replacement
|
||||||
|
|
||||||
// strip out scanned parts
|
// strip out scanned parts
|
||||||
s = s[idxEnd+1:]
|
s = s[idxEnd+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// append unscanned parts
|
// append unscanned parts
|
||||||
return result + s
|
return result + unescapeBraces(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func roundDuration(d time.Duration) time.Duration {
|
func roundDuration(d time.Duration) time.Duration {
|
||||||
|
@ -375,6 +411,26 @@ func (r *replacer) getSubstitution(key string) string {
|
||||||
}
|
}
|
||||||
elapsedDuration := time.Since(r.responseRecorder.start)
|
elapsedDuration := time.Since(r.responseRecorder.start)
|
||||||
return strconv.FormatInt(convertToMilliseconds(elapsedDuration), 10)
|
return strconv.FormatInt(convertToMilliseconds(elapsedDuration), 10)
|
||||||
|
case "{tls_protocol}":
|
||||||
|
if r.request.TLS != nil {
|
||||||
|
for k, v := range caddytls.SupportedProtocols {
|
||||||
|
if v == r.request.TLS.Version {
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "tls" // this should never happen, but guard in case
|
||||||
|
}
|
||||||
|
return r.emptyValue // because not using a secure channel
|
||||||
|
case "{tls_cipher}":
|
||||||
|
if r.request.TLS != nil {
|
||||||
|
for k, v := range caddytls.SupportedCiphersMap {
|
||||||
|
if v == r.request.TLS.CipherSuite {
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "UNKNOWN" // this should never happen, but guard in case
|
||||||
|
}
|
||||||
|
return r.emptyValue
|
||||||
default:
|
default:
|
||||||
// {labelN}
|
// {labelN}
|
||||||
if strings.HasPrefix(key, "{label") {
|
if strings.HasPrefix(key, "{label") {
|
||||||
|
@ -394,7 +450,7 @@ func (r *replacer) getSubstitution(key string) string {
|
||||||
return r.emptyValue
|
return r.emptyValue
|
||||||
}
|
}
|
||||||
|
|
||||||
//convertToMilliseconds returns the number of milliseconds in the given duration
|
// convertToMilliseconds returns the number of milliseconds in the given duration
|
||||||
func convertToMilliseconds(d time.Duration) int64 {
|
func convertToMilliseconds(d time.Duration) int64 {
|
||||||
return d.Nanoseconds() / 1e6
|
return d.Nanoseconds() / 1e6
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ func TestReplace(t *testing.T) {
|
||||||
{"Missing query string argument is {?missing}", "Missing query string argument is "},
|
{"Missing query string argument is {?missing}", "Missing query string argument is "},
|
||||||
{"{label1} {label2} {label3} {label4}", "localhost local - -"},
|
{"{label1} {label2} {label3} {label4}", "localhost local - -"},
|
||||||
{"Label with missing number is {label} or {labelQQ}", "Label with missing number is - or -"},
|
{"Label with missing number is {label} or {labelQQ}", "Label with missing number is - or -"},
|
||||||
|
{"\\{ 'hostname': '{hostname}' \\}", "{ 'hostname': '" + hostname + "' }"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range testCases {
|
for _, c := range testCases {
|
||||||
|
@ -146,6 +147,70 @@ func TestReplace(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkReplace(b *testing.B) {
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
recordRequest := NewResponseRecorder(w)
|
||||||
|
reader := strings.NewReader(`{"username": "dennis"}`)
|
||||||
|
|
||||||
|
request, err := http.NewRequest("POST", "http://localhost/?foo=bar", reader)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Failed to make request: %v", err)
|
||||||
|
}
|
||||||
|
ctx := context.WithValue(request.Context(), OriginalURLCtxKey, *request.URL)
|
||||||
|
request = request.WithContext(ctx)
|
||||||
|
|
||||||
|
request.Header.Set("Custom", "foobarbaz")
|
||||||
|
request.Header.Set("ShorterVal", "1")
|
||||||
|
repl := NewReplacer(request, recordRequest, "-")
|
||||||
|
// add some headers after creating replacer
|
||||||
|
request.Header.Set("CustomAdd", "caddy")
|
||||||
|
request.Header.Set("Cookie", "foo=bar; taste=delicious")
|
||||||
|
|
||||||
|
// add some respons headers
|
||||||
|
recordRequest.Header().Set("Custom", "CustomResponseHeader")
|
||||||
|
|
||||||
|
now = func() time.Time {
|
||||||
|
return time.Date(2006, 1, 2, 15, 4, 5, 02, time.FixedZone("hardcoded", -7))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
repl.Replace("This hostname is {hostname}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkReplaceEscaped(b *testing.B) {
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
recordRequest := NewResponseRecorder(w)
|
||||||
|
reader := strings.NewReader(`{"username": "dennis"}`)
|
||||||
|
|
||||||
|
request, err := http.NewRequest("POST", "http://localhost/?foo=bar", reader)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Failed to make request: %v", err)
|
||||||
|
}
|
||||||
|
ctx := context.WithValue(request.Context(), OriginalURLCtxKey, *request.URL)
|
||||||
|
request = request.WithContext(ctx)
|
||||||
|
|
||||||
|
request.Header.Set("Custom", "foobarbaz")
|
||||||
|
request.Header.Set("ShorterVal", "1")
|
||||||
|
repl := NewReplacer(request, recordRequest, "-")
|
||||||
|
// add some headers after creating replacer
|
||||||
|
request.Header.Set("CustomAdd", "caddy")
|
||||||
|
request.Header.Set("Cookie", "foo=bar; taste=delicious")
|
||||||
|
|
||||||
|
// add some respons headers
|
||||||
|
recordRequest.Header().Set("Custom", "CustomResponseHeader")
|
||||||
|
|
||||||
|
now = func() time.Time {
|
||||||
|
return time.Date(2006, 1, 2, 15, 4, 5, 02, time.FixedZone("hardcoded", -7))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
repl.Replace("\\{ 'hostname': '{hostname}' \\}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestResponseRecorderNil(t *testing.T) {
|
func TestResponseRecorderNil(t *testing.T) {
|
||||||
|
|
||||||
reader := strings.NewReader(`{"username": "dennis"}`)
|
reader := strings.NewReader(`{"username": "dennis"}`)
|
||||||
|
|
|
@ -422,13 +422,21 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error)
|
||||||
func trimPathPrefix(u *url.URL, prefix string) *url.URL {
|
func trimPathPrefix(u *url.URL, prefix string) *url.URL {
|
||||||
// We need to use URL.EscapedPath() when trimming the pathPrefix as
|
// We need to use URL.EscapedPath() when trimming the pathPrefix as
|
||||||
// URL.Path is ambiguous about / or %2f - see docs. See #1927
|
// URL.Path is ambiguous about / or %2f - see docs. See #1927
|
||||||
trimmed := strings.TrimPrefix(u.EscapedPath(), prefix)
|
trimmedPath := strings.TrimPrefix(u.EscapedPath(), prefix)
|
||||||
if !strings.HasPrefix(trimmed, "/") {
|
if !strings.HasPrefix(trimmedPath, "/") {
|
||||||
trimmed = "/" + trimmed
|
trimmedPath = "/" + trimmedPath
|
||||||
}
|
}
|
||||||
trimmedURL, err := url.Parse(trimmed)
|
// After trimming path reconstruct uri string with Query before parsing
|
||||||
|
trimmedURI := trimmedPath
|
||||||
|
if u.RawQuery != "" || u.ForceQuery == true {
|
||||||
|
trimmedURI = trimmedPath + "?" + u.RawQuery
|
||||||
|
}
|
||||||
|
if u.Fragment != "" {
|
||||||
|
trimmedURI = trimmedURI + "#" + u.Fragment
|
||||||
|
}
|
||||||
|
trimmedURL, err := url.Parse(trimmedURI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] Unable to parse trimmed URL %s: %v", trimmed, err)
|
log.Printf("[ERROR] Unable to parse trimmed URL %s: %v", trimmedURI, err)
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
return trimmedURL
|
return trimmedURL
|
||||||
|
|
|
@ -129,88 +129,108 @@ func TestMakeHTTPServerWithTimeouts(t *testing.T) {
|
||||||
|
|
||||||
func TestTrimPathPrefix(t *testing.T) {
|
func TestTrimPathPrefix(t *testing.T) {
|
||||||
for i, pt := range []struct {
|
for i, pt := range []struct {
|
||||||
path string
|
url string
|
||||||
prefix string
|
prefix string
|
||||||
expected string
|
expected string
|
||||||
shouldFail bool
|
shouldFail bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
path: "/my/path",
|
url: "/my/path",
|
||||||
prefix: "/my",
|
prefix: "/my",
|
||||||
expected: "/path",
|
expected: "/path",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/my/%2f/path",
|
url: "/my/%2f/path",
|
||||||
prefix: "/my",
|
prefix: "/my",
|
||||||
expected: "/%2f/path",
|
expected: "/%2f/path",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/my/path",
|
url: "/my/path",
|
||||||
prefix: "/my/",
|
prefix: "/my/",
|
||||||
expected: "/path",
|
expected: "/path",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/my///path",
|
url: "/my///path",
|
||||||
prefix: "/my",
|
prefix: "/my",
|
||||||
expected: "/path",
|
expected: "/path",
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/my///path",
|
url: "/my///path",
|
||||||
prefix: "/my",
|
prefix: "/my",
|
||||||
expected: "///path",
|
expected: "///path",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/my/path///slash",
|
url: "/my/path///slash",
|
||||||
prefix: "/my",
|
prefix: "/my",
|
||||||
expected: "/path///slash",
|
expected: "/path///slash",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/my/%2f/path/%2f",
|
url: "/my/%2f/path/%2f",
|
||||||
prefix: "/my",
|
prefix: "/my",
|
||||||
expected: "/%2f/path/%2f",
|
expected: "/%2f/path/%2f",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
}, {
|
}, {
|
||||||
path: "/my/%20/path",
|
url: "/my/%20/path",
|
||||||
prefix: "/my",
|
prefix: "/my",
|
||||||
expected: "/%20/path",
|
expected: "/%20/path",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
}, {
|
}, {
|
||||||
path: "/path",
|
url: "/path",
|
||||||
prefix: "",
|
prefix: "",
|
||||||
expected: "/path",
|
expected: "/path",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
}, {
|
}, {
|
||||||
path: "/path/my/",
|
url: "/path/my/",
|
||||||
prefix: "/my",
|
prefix: "/my",
|
||||||
expected: "/path/my/",
|
expected: "/path/my/",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
}, {
|
}, {
|
||||||
path: "",
|
url: "",
|
||||||
prefix: "/my",
|
prefix: "/my",
|
||||||
expected: "/",
|
expected: "/",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
}, {
|
}, {
|
||||||
path: "/apath",
|
url: "/apath",
|
||||||
prefix: "",
|
prefix: "",
|
||||||
expected: "/apath",
|
expected: "/apath",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
|
}, {
|
||||||
|
url: "/my/path/page.php?akey=value",
|
||||||
|
prefix: "/my",
|
||||||
|
expected: "/path/page.php?akey=value",
|
||||||
|
shouldFail: false,
|
||||||
|
}, {
|
||||||
|
url: "/my/path/page?key=value#fragment",
|
||||||
|
prefix: "/my",
|
||||||
|
expected: "/path/page?key=value#fragment",
|
||||||
|
shouldFail: false,
|
||||||
|
}, {
|
||||||
|
url: "/my/path/page#fragment",
|
||||||
|
prefix: "/my",
|
||||||
|
expected: "/path/page#fragment",
|
||||||
|
shouldFail: false,
|
||||||
|
}, {
|
||||||
|
url: "/my/apath?",
|
||||||
|
prefix: "/my",
|
||||||
|
expected: "/apath?",
|
||||||
|
shouldFail: false,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
|
|
||||||
u, _ := url.Parse(pt.path)
|
u, _ := url.Parse(pt.url)
|
||||||
if got, want := trimPathPrefix(u, pt.prefix), pt.expected; got.EscapedPath() != want {
|
if got, want := trimPathPrefix(u, pt.prefix), pt.expected; got.String() != want {
|
||||||
if !pt.shouldFail {
|
if !pt.shouldFail {
|
||||||
|
|
||||||
t.Errorf("Test %d: Expected='%s', but was '%s' ", i, want, got.EscapedPath())
|
t.Errorf("Test %d: Expected='%s', but was '%s' ", i, want, got.String())
|
||||||
}
|
}
|
||||||
} else if pt.shouldFail {
|
} else if pt.shouldFail {
|
||||||
t.Errorf("SHOULDFAIL Test %d: Expected='%s', and was '%s' but should fail", i, want, got.EscapedPath())
|
t.Errorf("SHOULDFAIL Test %d: Expected='%s', and was '%s' but should fail", i, want, got.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -569,7 +569,8 @@ var supportedKeyTypes = map[string]acme.KeyType{
|
||||||
|
|
||||||
// Map of supported protocols.
|
// Map of supported protocols.
|
||||||
// HTTP/2 only supports TLS 1.2 and higher.
|
// HTTP/2 only supports TLS 1.2 and higher.
|
||||||
var supportedProtocols = map[string]uint16{
|
// If updating this map, also update tlsProtocolStringToMap in caddyhttp/fastcgi/fastcgi.go
|
||||||
|
var SupportedProtocols = map[string]uint16{
|
||||||
"tls1.0": tls.VersionTLS10,
|
"tls1.0": tls.VersionTLS10,
|
||||||
"tls1.1": tls.VersionTLS11,
|
"tls1.1": tls.VersionTLS11,
|
||||||
"tls1.2": tls.VersionTLS12,
|
"tls1.2": tls.VersionTLS12,
|
||||||
|
@ -585,7 +586,7 @@ var supportedProtocols = map[string]uint16{
|
||||||
// it is always added (even though it is not technically a cipher suite).
|
// it is always added (even though it is not technically a cipher suite).
|
||||||
//
|
//
|
||||||
// This map, like any map, is NOT ORDERED. Do not range over this map.
|
// This map, like any map, is NOT ORDERED. Do not range over this map.
|
||||||
var supportedCiphersMap = map[string]uint16{
|
var SupportedCiphersMap = map[string]uint16{
|
||||||
"ECDHE-ECDSA-AES256-GCM-SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
"ECDHE-ECDSA-AES256-GCM-SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||||
"ECDHE-RSA-AES256-GCM-SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
"ECDHE-RSA-AES256-GCM-SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
"ECDHE-ECDSA-AES128-GCM-SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
"ECDHE-ECDSA-AES128-GCM-SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
|
|
@ -106,19 +106,19 @@ func setupTLS(c *caddy.Controller) error {
|
||||||
case "protocols":
|
case "protocols":
|
||||||
args := c.RemainingArgs()
|
args := c.RemainingArgs()
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
value, ok := supportedProtocols[strings.ToLower(args[0])]
|
value, ok := SupportedProtocols[strings.ToLower(args[0])]
|
||||||
if !ok {
|
if !ok {
|
||||||
return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0])
|
return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
config.ProtocolMinVersion, config.ProtocolMaxVersion = value, value
|
config.ProtocolMinVersion, config.ProtocolMaxVersion = value, value
|
||||||
} else {
|
} else {
|
||||||
value, ok := supportedProtocols[strings.ToLower(args[0])]
|
value, ok := SupportedProtocols[strings.ToLower(args[0])]
|
||||||
if !ok {
|
if !ok {
|
||||||
return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0])
|
return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[0])
|
||||||
}
|
}
|
||||||
config.ProtocolMinVersion = value
|
config.ProtocolMinVersion = value
|
||||||
value, ok = supportedProtocols[strings.ToLower(args[1])]
|
value, ok = SupportedProtocols[strings.ToLower(args[1])]
|
||||||
if !ok {
|
if !ok {
|
||||||
return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[1])
|
return c.Errf("Wrong protocol name or protocol not supported: '%s'", args[1])
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ func setupTLS(c *caddy.Controller) error {
|
||||||
}
|
}
|
||||||
case "ciphers":
|
case "ciphers":
|
||||||
for c.NextArg() {
|
for c.NextArg() {
|
||||||
value, ok := supportedCiphersMap[strings.ToUpper(c.Val())]
|
value, ok := SupportedCiphersMap[strings.ToUpper(c.Val())]
|
||||||
if !ok {
|
if !ok {
|
||||||
return c.Errf("Wrong cipher name or cipher not supported: '%s'", c.Val())
|
return c.Errf("Wrong cipher name or cipher not supported: '%s'", c.Val())
|
||||||
}
|
}
|
||||||
|
|
32
plugins.go
32
plugins.go
|
@ -39,7 +39,7 @@ var (
|
||||||
|
|
||||||
// eventHooks is a map of hook name to Hook. All hooks plugins
|
// eventHooks is a map of hook name to Hook. All hooks plugins
|
||||||
// must have a name.
|
// must have a name.
|
||||||
eventHooks = sync.Map{}
|
eventHooks = &sync.Map{}
|
||||||
|
|
||||||
// parsingCallbacks maps server type to map of directive
|
// parsingCallbacks maps server type to map of directive
|
||||||
// to list of callback functions. These aren't really
|
// to list of callback functions. These aren't really
|
||||||
|
@ -271,6 +271,36 @@ func EmitEvent(event EventName, info interface{}) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cloneEventHooks return a clone of the event hooks *sync.Map
|
||||||
|
func cloneEventHooks() *sync.Map {
|
||||||
|
c := &sync.Map{}
|
||||||
|
eventHooks.Range(func(k, v interface{}) bool {
|
||||||
|
c.Store(k, v)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// purgeEventHooks purges all event hooks from the map
|
||||||
|
func purgeEventHooks() {
|
||||||
|
eventHooks.Range(func(k, _ interface{}) bool {
|
||||||
|
eventHooks.Delete(k)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// restoreEventHooks restores eventHooks with a provided *sync.Map
|
||||||
|
func restoreEventHooks(m *sync.Map) {
|
||||||
|
// Purge old event hooks
|
||||||
|
purgeEventHooks()
|
||||||
|
|
||||||
|
// Restore event hooks
|
||||||
|
m.Range(func(k, v interface{}) bool {
|
||||||
|
eventHooks.Store(k, v)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// ParsingCallback is a function that is called after
|
// ParsingCallback is a function that is called after
|
||||||
// a directive's setup functions have been executed
|
// a directive's setup functions have been executed
|
||||||
// for all the server blocks.
|
// for all the server blocks.
|
||||||
|
|
|
@ -76,9 +76,17 @@ func trapSignalsPosix() {
|
||||||
caddyfileToUse = newCaddyfile
|
caddyfileToUse = newCaddyfile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backup old event hooks
|
||||||
|
oldEventHooks := cloneEventHooks()
|
||||||
|
|
||||||
|
// Purge the old event hooks
|
||||||
|
purgeEventHooks()
|
||||||
|
|
||||||
// Kick off the restart; our work is done
|
// Kick off the restart; our work is done
|
||||||
_, err = inst.Restart(caddyfileToUse)
|
_, err = inst.Restart(caddyfileToUse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
restoreEventHooks(oldEventHooks)
|
||||||
|
|
||||||
log.Printf("[ERROR] SIGUSR1: %v", err)
|
log.Printf("[ERROR] SIGUSR1: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue