aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules/caddyhttp/replacer.go
diff options
context:
space:
mode:
authorMatthew Holt <[email protected]>2019-05-20 10:59:20 -0600
committerMatthew Holt <[email protected]>2019-05-20 10:59:20 -0600
commitfec7fa8bfda713e8042b9bbf9a480c7792b78c41 (patch)
tree53d86ab50ef7d15e9688c81b6618024c4243c98d /modules/caddyhttp/replacer.go
parent1a20fe330ecc39e8b98b5669b836f3b1b185f622 (diff)
downloadcaddy-fec7fa8bfda713e8042b9bbf9a480c7792b78c41.tar.gz
caddy-fec7fa8bfda713e8042b9bbf9a480c7792b78c41.zip
Implement most of static file server; refactor and improve Replacer
Diffstat (limited to 'modules/caddyhttp/replacer.go')
-rw-r--r--modules/caddyhttp/replacer.go164
1 files changed, 64 insertions, 100 deletions
diff --git a/modules/caddyhttp/replacer.go b/modules/caddyhttp/replacer.go
index e7aa250e0..6feb1437c 100644
--- a/modules/caddyhttp/replacer.go
+++ b/modules/caddyhttp/replacer.go
@@ -1,119 +1,83 @@
package caddyhttp
import (
+ "fmt"
"net"
"net/http"
- "os"
+ "path"
"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; 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
-}
-
-// Replace replaces placeholders in input with the value. If
-// the value is empty string, the placeholder is substituted
-// with the value empty.
-func (r *Replacer) Replace(input, empty string) string {
- if !strings.Contains(input, phOpen) {
- return input
- }
-
- input = r.replaceAll(input, empty, r.defaults())
- input = r.replaceAll(input, empty, r.custom)
-
- return input
-}
-
-func (r *Replacer) replaceAll(input, empty string, mapping map[string]string) string {
- for key, val := range mapping {
- if val == "" {
- val = empty
- }
- input = strings.ReplaceAll(input, phOpen+key+phClose, val)
- }
- return input
-}
-
-func (r *Replacer) defaults() map[string]string {
- m := map[string]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
+// TODO: A simple way to format or escape or encode each value would be nice
+// ... TODO: Should we just use templates? :-/ yeesh...
+
+func newReplacer(req *http.Request, w http.ResponseWriter) caddy2.Replacer {
+ repl := caddy2.NewReplacer()
+
+ httpVars := func() map[string]string {
+ m := make(map[string]string)
+ if req != nil {
+ m["http.request.host"] = func() string {
+ host, _, err := net.SplitHostPort(req.Host)
+ if err != nil {
+ return req.Host // OK; there probably was no port
+ }
+ return host
+ }()
+ m["http.request.hostport"] = req.Host // may include both host and port
+ m["http.request.method"] = req.Method
+ m["http.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(req.Host)
+ return port
+ }()
+ m["http.request.scheme"] = func() string {
+ if req.TLS != nil {
+ return "https"
+ }
+ return "http"
+ }()
+ m["http.request.uri"] = req.URL.RequestURI()
+ m["http.request.uri.path"] = req.URL.Path
+ m["http.request.uri.path.file"] = func() string {
+ _, file := path.Split(req.URL.Path)
+ return file
+ }()
+ m["http.request.uri.path.dir"] = func() string {
+ dir, _ := path.Split(req.URL.Path)
+ return dir
+ }()
+
+ for field, vals := range req.Header {
+ m["http.request.header."+strings.ToLower(field)] = strings.Join(vals, ",")
}
- return host
- }()
- 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
- }()
- m["request.scheme"] = func() string {
- if r.req.TLS != nil {
- return "https"
+ for _, cookie := range req.Cookies() {
+ m["http.request.cookie."+cookie.Name] = cookie.Value
+ }
+ for param, vals := range req.URL.Query() {
+ m["http.request.uri.query."+param] = strings.Join(vals, ",")
}
- return "http"
- }()
- m["request.uri"] = r.req.URL.RequestURI()
- m["request.uri.path"] = r.req.URL.Path
- for field, vals := range r.req.Header {
- m["request.header."+strings.ToLower(field)] = strings.Join(vals, ",")
- }
- for _, cookie := range r.req.Cookies() {
- m["request.cookie."+cookie.Name] = cookie.Value
- }
- for param, vals := range r.req.URL.Query() {
- m["request.uri.query."+param] = strings.Join(vals, ",")
+ hostLabels := strings.Split(req.Host, ".")
+ for i, label := range hostLabels {
+ key := fmt.Sprintf("http.request.host.labels.%d", len(hostLabels)-i-1)
+ m[key] = label
+ }
}
- }
- if r.resp != nil {
- for field, vals := range r.resp.Header() {
- m["response.header."+strings.ToLower(field)] = strings.Join(vals, ",")
+ if w != nil {
+ for field, vals := range w.Header() {
+ m["http.response.header."+strings.ToLower(field)] = strings.Join(vals, ",")
+ }
}
- }
- return m
-}
+ return m
+ }
-const phOpen, phClose = "{", "}"
+ repl.Map(httpVars)
-// ReplacerCtxKey is the context key for the request's replacer.
-const ReplacerCtxKey caddy2.CtxKey = "replacer"
+ return repl
+}