From f9d93ead4ef6e099ba7e00318dce6509b0f1eda4 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Tue, 14 May 2019 14:14:05 -0600 Subject: Rename and export some types, other minor changes --- modules/caddyhttp/replacer.go | 80 +++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 30 deletions(-) (limited to 'modules/caddyhttp/replacer.go') diff --git a/modules/caddyhttp/replacer.go b/modules/caddyhttp/replacer.go index 644cfc1..1fd3428 100644 --- a/modules/caddyhttp/replacer.go +++ b/modules/caddyhttp/replacer.go @@ -5,18 +5,31 @@ import ( "net/http" "os" "strings" + + "bitbucket.org/lightcodelabs/caddy2" ) // Replacer can replace values in strings based // on a request and/or response writer. The zero -// Replacer is not valid; it must be initialized -// within this package. +// Replacer is not valid; use NewReplacer() to +// initialize one. type Replacer struct { req *http.Request resp http.ResponseWriter custom map[string]string } +// NewReplacer makes a new Replacer, initializing all necessary +// fields. The request and response writer are optional, but +// necessary for most replacements to work. +func NewReplacer(req *http.Request, rw http.ResponseWriter) *Replacer { + return &Replacer{ + req: req, + resp: rw, + custom: make(map[string]string), + } +} + // Map sets a custom variable mapping to a value. func (r *Replacer) Map(variable, value string) { r.custom[variable] = value @@ -48,51 +61,58 @@ func (r *Replacer) replaceAll(input, empty string, mapping map[string]string) st func (r *Replacer) defaults() map[string]string { m := map[string]string{ - "request.host": func() string { + "system.hostname": func() string { + // OK if there is an error; just return empty string + name, _ := os.Hostname() + return name + }(), + } + + if r.req != nil { + m["request.host"] = func() string { host, _, err := net.SplitHostPort(r.req.Host) if err != nil { return r.req.Host // OK; there probably was no port } return host - }(), - "request.hostport": r.req.Host, // may include both host and port - "request.method": r.req.Method, - "request.port": func() string { + }() + m["request.hostport"] = r.req.Host // may include both host and port + m["request.method"] = r.req.Method + m["request.port"] = func() string { // if there is no port, there will be an error; in // that case, port is the empty string anyway _, port, _ := net.SplitHostPort(r.req.Host) return port - }(), - "request.scheme": func() string { + }() + m["request.scheme"] = func() string { if r.req.TLS != nil { return "https" } return "http" - }(), - "request.uri": r.req.URL.RequestURI(), - "system.hostname": func() string { - // OK if there is an error; just return empty string - name, _ := os.Hostname() - return name - }(), - } + }() + m["request.uri"] = r.req.URL.RequestURI() + m["request.uri.path"] = r.req.URL.Path - // TODO: why should header fields, cookies, and query params get special treatment like this? - // maybe they should be scoped by words like "request.header." just like everything else. - for field, vals := range r.req.Header { - m[">"+strings.ToLower(field)] = strings.Join(vals, ",") - } - for field, vals := range r.resp.Header() { - m["<"+strings.ToLower(field)] = strings.Join(vals, ",") - } - for _, cookie := range r.req.Cookies() { - m["~"+cookie.Name] = cookie.Value - } - for param, vals := range r.req.URL.Query() { - m["?"+param] = strings.Join(vals, ",") + // TODO: why should header fields, cookies, and query params get special treatment like this? + // maybe they should be scoped by words like "request.header." just like everything else. + for field, vals := range r.req.Header { + m[">"+strings.ToLower(field)] = strings.Join(vals, ",") + } + for field, vals := range r.resp.Header() { + m["<"+strings.ToLower(field)] = strings.Join(vals, ",") + } + for _, cookie := range r.req.Cookies() { + m["~"+cookie.Name] = cookie.Value + } + for param, vals := range r.req.URL.Query() { + m["?"+param] = strings.Join(vals, ",") + } } return m } const phOpen, phClose = "{", "}" + +// ReplacerCtxKey is the context key for the request's replacer. +const ReplacerCtxKey caddy2.CtxKey = "replacer" -- cgit v1.2.3