From 9c0bf311f93218e8f899cd3c6102868be18a4d1c Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Thu, 10 Oct 2019 15:38:30 -0600 Subject: [PATCH] Miscellaneous cleanups / comments --- context.go | 2 +- modules/caddyhttp/caddyhttp.go | 2 +- modules/caddyhttp/replacer.go | 45 ++++++++++++++++--- .../caddyhttp/reverseproxy/fastcgi/fastcgi.go | 1 + .../caddyhttp/reverseproxy/reverseproxy.go | 2 + modules/caddyhttp/routes.go | 3 ++ replacer.go | 7 +++ storage.go | 3 ++ 8 files changed, 56 insertions(+), 9 deletions(-) diff --git a/context.go b/context.go index c29aa1d13..d196c71b6 100644 --- a/context.go +++ b/context.go @@ -30,7 +30,7 @@ import ( // with care and wrapped with derivation functions from the // standard context package only if you don't need the Caddy // specific features. These contexts are cancelled when the -// lifetime of the modules loaded from it are over. +// lifetime of the modules loaded from it is over. // // Use NewContext() to get a valid value (but most modules will // not actually need to do this). diff --git a/modules/caddyhttp/caddyhttp.go b/modules/caddyhttp/caddyhttp.go index 410b42c9a..191f803be 100644 --- a/modules/caddyhttp/caddyhttp.go +++ b/modules/caddyhttp/caddyhttp.go @@ -348,7 +348,7 @@ func (app *App) automaticHTTPS() error { }) // manage their certificates - log.Printf("[INFO] Enabling automatic HTTPS certificates for %v", domainsForCerts) + log.Printf("[INFO] Enabling automatic TLS certificate management for %v", domainsForCerts) err := tlsApp.Manage(domainsForCerts) if err != nil { return fmt.Errorf("%s: managing certificate for %s: %s", srvName, domains, err) diff --git a/modules/caddyhttp/replacer.go b/modules/caddyhttp/replacer.go index d4baa3f0c..205e4ed5f 100644 --- a/modules/caddyhttp/replacer.go +++ b/modules/caddyhttp/replacer.go @@ -19,6 +19,7 @@ import ( "net" "net/http" "net/textproto" + "net/url" "path" "strconv" "strings" @@ -59,6 +60,15 @@ func addHTTPVarsToReplacer(repl caddy.Replacer, req *http.Request, w http.Respon } switch key { + case "http.request.method": + return req.Method, true + case "http.request.scheme": + if req.TLS != nil { + return "https", true + } + return "http", true + case "http.request.proto": + return req.Proto, true case "http.request.host": host, _, err := net.SplitHostPort(req.Host) if err != nil { @@ -81,13 +91,8 @@ func addHTTPVarsToReplacer(repl caddy.Replacer, req *http.Request, w http.Respon case "http.request.remote.port": _, port, _ := net.SplitHostPort(req.RemoteAddr) return port, true - case "http.request.method": - return req.Method, true - case "http.request.scheme": - if req.TLS != nil { - return "https", true - } - return "http", true + + // current URI, including any internal rewrites case "http.request.uri": return req.URL.RequestURI(), true case "http.request.uri.path": @@ -106,6 +111,32 @@ func addHTTPVarsToReplacer(repl caddy.Replacer, req *http.Request, w http.Respon qs = "?" + qs } return qs, true + + // original URI, before any internal changes + case "http.request.orig_uri": + u, _ := req.Context().Value(OriginalURLCtxKey).(url.URL) + return u.RequestURI(), true + case "http.request.orig_uri.path": + u, _ := req.Context().Value(OriginalURLCtxKey).(url.URL) + return u.Path, true + case "http.request.orig_uri.path.file": + u, _ := req.Context().Value(OriginalURLCtxKey).(url.URL) + _, file := path.Split(u.Path) + return file, true + case "http.request.orig_uri.path.dir": + u, _ := req.Context().Value(OriginalURLCtxKey).(url.URL) + dir, _ := path.Split(u.Path) + return dir, true + case "http.request.orig_uri.query": + u, _ := req.Context().Value(OriginalURLCtxKey).(url.URL) + return u.RawQuery, true + case "http.request.orig_uri.query_string": + u, _ := req.Context().Value(OriginalURLCtxKey).(url.URL) + qs := u.Query().Encode() + if qs != "" { + qs = "?" + qs + } + return qs, true } // hostname labels diff --git a/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go b/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go index 9df6585ed..eaf1f8644 100644 --- a/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go +++ b/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go @@ -110,6 +110,7 @@ func (t Transport) RoundTrip(r *http.Request) (*http.Response, error) { fcgiBackend, err := DialContext(ctx, network, address) if err != nil { + // TODO: wrap in a special error type if the dial failed, so retries can happen if enabled return nil, fmt.Errorf("dialing backend: %v", err) } // fcgiBackend gets closed when response body is closed (see clientCloser) diff --git a/modules/caddyhttp/reverseproxy/reverseproxy.go b/modules/caddyhttp/reverseproxy/reverseproxy.go index a733d681f..45c0690be 100644 --- a/modules/caddyhttp/reverseproxy/reverseproxy.go +++ b/modules/caddyhttp/reverseproxy/reverseproxy.go @@ -243,6 +243,8 @@ func (h *Handler) Cleanup() error { close(h.HealthChecks.Active.stopChan) } + // TODO: Close keepalive connections on reload? https://github.com/caddyserver/caddy/pull/2507/files#diff-70219fd88fe3f36834f474ce6537ed26R762 + // remove hosts from our config from the pool for _, upstream := range h.Upstreams { hosts.Delete(upstream.dialInfo.String()) diff --git a/modules/caddyhttp/routes.go b/modules/caddyhttp/routes.go index 9dca1071c..550b14e50 100644 --- a/modules/caddyhttp/routes.go +++ b/modules/caddyhttp/routes.go @@ -141,6 +141,9 @@ func (routes RouteList) BuildCompositeRoute(req *http.Request) Handler { func wrapMiddleware(mh MiddlewareHandler) Middleware { return func(next HandlerFunc) HandlerFunc { return func(w http.ResponseWriter, r *http.Request) error { + // TODO: We could wait to evaluate matchers here, just eval + // the next matcher and choose the next route... + // TODO: This is where request tracing could be implemented; also // see below to trace the responder as well // TODO: Trace a diff of the request, would be cool too! see what changed since the last middleware (host, headers, URI...) diff --git a/replacer.go b/replacer.go index d7beeab69..420259bb1 100644 --- a/replacer.go +++ b/replacer.go @@ -19,6 +19,7 @@ import ( "path/filepath" "runtime" "strings" + "time" ) // Replacer can replace values in strings. @@ -156,11 +157,17 @@ func globalDefaultReplacements(key string) (string, bool) { return runtime.GOOS, true case "system.arch": return runtime.GOARCH, true + case "time.now.common_log": + return nowFunc().Format("02/Jan/2006:15:04:05 -0700"), true } return "", false } +// nowFunc is a variable so tests can change it +// in order to obtain a deterministic time. +var nowFunc = time.Now + // ReplacerCtxKey is the context key for a replacer. const ReplacerCtxKey CtxKey = "replacer" diff --git a/storage.go b/storage.go index b325b7bb0..670a47163 100644 --- a/storage.go +++ b/storage.go @@ -59,3 +59,6 @@ func dataDir() string { } return filepath.Join(baseDir, "caddy") } + +// TODO: Consider using Go 1.13's os.UserConfigDir() (https://golang.org/pkg/os/#UserConfigDir) +// if we are going to store the last-loaded config anywhere