From b1cd0bfeffe0c585557fd1e0c26c0f092396723e Mon Sep 17 00:00:00 2001 From: Abiola Ibrahim Date: Wed, 29 Jun 2016 13:41:52 +0100 Subject: [PATCH] Support for placeholders in fastcgi env vars. --- caddyhttp/fastcgi/fastcgi.go | 4 +- caddyhttp/fastcgi/fastcgi_test.go | 77 ++++++++++++++++++++------- caddyhttp/httpserver/replacer.go | 5 ++ caddyhttp/httpserver/replacer_test.go | 2 +- 4 files changed, 67 insertions(+), 21 deletions(-) diff --git a/caddyhttp/fastcgi/fastcgi.go b/caddyhttp/fastcgi/fastcgi.go index 0ac886b6..30426b33 100644 --- a/caddyhttp/fastcgi/fastcgi.go +++ b/caddyhttp/fastcgi/fastcgi.go @@ -254,9 +254,11 @@ func (h Handler) buildEnv(r *http.Request, rule Rule, fpath string) (map[string] env["HTTPS"] = "on" } + replacer := httpserver.NewReplacer(r, nil, "") // Add env variables from config for _, envVar := range rule.EnvVars { - env[envVar[0]] = envVar[1] + // replace request placeholders in environment variables + env[envVar[0]] = replacer.Replace(envVar[1]) } // Add all HTTP headers to env variables diff --git a/caddyhttp/fastcgi/fastcgi_test.go b/caddyhttp/fastcgi/fastcgi_test.go index e1e39491..8b813c24 100644 --- a/caddyhttp/fastcgi/fastcgi_test.go +++ b/caddyhttp/fastcgi/fastcgi_test.go @@ -123,38 +123,77 @@ func TestBuildEnv(t *testing.T) { t.Error("Unexpected error:", err.Error()) } - r := http.Request{ - Method: "GET", - URL: url, - Proto: "HTTP/1.1", - ProtoMajor: 1, - ProtoMinor: 1, - Host: "localhost:2015", - RemoteAddr: "[2b02:1810:4f2d:9400:70ab:f822:be8a:9093]:51688", - RequestURI: "/fgci_test.php", + var newReq = func() *http.Request { + return &http.Request{ + Method: "GET", + URL: url, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Host: "localhost:2015", + RemoteAddr: "[2b02:1810:4f2d:9400:70ab:f822:be8a:9093]:51688", + RequestURI: "/fgci_test.php", + } } fpath := "/fgci_test.php" - var envExpected = map[string]string{ - "REMOTE_ADDR": "2b02:1810:4f2d:9400:70ab:f822:be8a:9093", - "REMOTE_PORT": "51688", - "SERVER_PROTOCOL": "HTTP/1.1", - "QUERY_STRING": "test=blabla", - "REQUEST_METHOD": "GET", - "HTTP_HOST": "localhost:2015", + var newEnv = func() map[string]string { + return map[string]string{ + "REMOTE_ADDR": "2b02:1810:4f2d:9400:70ab:f822:be8a:9093", + "REMOTE_PORT": "51688", + "SERVER_PROTOCOL": "HTTP/1.1", + "QUERY_STRING": "test=blabla", + "REQUEST_METHOD": "GET", + "HTTP_HOST": "localhost:2015", + } } + // request + var r *http.Request + + // expected environment variables + var envExpected map[string]string + // 1. Test for full canonical IPv6 address - testBuildEnv(&r, rule, fpath, envExpected) + r = newReq() + testBuildEnv(r, rule, fpath, envExpected) // 2. Test for shorthand notation of IPv6 address + r = newReq() r.RemoteAddr = "[::1]:51688" + envExpected = newEnv() envExpected["REMOTE_ADDR"] = "::1" - testBuildEnv(&r, rule, fpath, envExpected) + testBuildEnv(r, rule, fpath, envExpected) // 3. Test for IPv4 address + r = newReq() r.RemoteAddr = "192.168.0.10:51688" + envExpected = newEnv() envExpected["REMOTE_ADDR"] = "192.168.0.10" - testBuildEnv(&r, rule, fpath, envExpected) + testBuildEnv(r, rule, fpath, envExpected) + + // 4. Test for environment variable + r = newReq() + rule.EnvVars = [][2]string{ + {"HTTP_HOST", "localhost:2016"}, + {"REQUEST_METHOD", "POST"}, + } + envExpected = newEnv() + envExpected["HTTP_HOST"] = "localhost:2016" + envExpected["REQUEST_METHOD"] = "POST" + testBuildEnv(r, rule, fpath, envExpected) + + // 5. Test for environment variable placeholders + r = newReq() + rule.EnvVars = [][2]string{ + {"HTTP_HOST", "{host}"}, + {"CUSTOM_URI", "custom_uri{uri}"}, + {"CUSTOM_QUERY", "custom=true&{query}"}, + } + envExpected = newEnv() + envExpected["HTTP_HOST"] = "localhost:2015" + envExpected["CUSTOM_URI"] = "custom_uri/fgci_test.php?test=blabla" + envExpected["CUSTOM_QUERY"] = "custom=true&test=blabla" + testBuildEnv(r, rule, fpath, envExpected) } diff --git a/caddyhttp/httpserver/replacer.go b/caddyhttp/httpserver/replacer.go index cae5870f..64cd1801 100644 --- a/caddyhttp/httpserver/replacer.go +++ b/caddyhttp/httpserver/replacer.go @@ -127,6 +127,11 @@ func NewReplacer(r *http.Request, rr *ResponseRecorder, emptyValue string) Repla // Replace performs a replacement of values on s and returns // the string with the replaced values. func (r *replacer) Replace(s string) string { + // Do not attempt replacements if no placeholder is found. + if !strings.ContainsAny(s, "{}") { + return s + } + // Make response placeholders now if r.responseRecorder != nil { r.replacements["{status}"] = strconv.Itoa(r.responseRecorder.status) diff --git a/caddyhttp/httpserver/replacer_test.go b/caddyhttp/httpserver/replacer_test.go index 3b80af43..5768c42f 100644 --- a/caddyhttp/httpserver/replacer_test.go +++ b/caddyhttp/httpserver/replacer_test.go @@ -32,7 +32,7 @@ func TestNewReplacer(t *testing.T) { if got, want := v.replacements["{status}"], ""; got != want { t.Errorf("Expected status to NOT be set before Replace() is called; was: %s", got) } - rep.Replace("foobar") + rep.Replace("{foobar}") if got, want := v.replacements["{status}"], "200"; got != want { t.Errorf("Expected status to be %s, was: %s", want, got) }