diff --git a/caddyhttp/httpserver/replacer_test.go b/caddyhttp/httpserver/replacer_test.go index b6f2f458a..3b80af437 100644 --- a/caddyhttp/httpserver/replacer_test.go +++ b/caddyhttp/httpserver/replacer_test.go @@ -58,54 +58,45 @@ func TestReplace(t *testing.T) { if err != nil { t.Fatal("Failed to determine hostname\n") } - if expected, actual := "This hostname is "+hostname, repl.Replace("This hostname is {hostname}"); expected != actual { - t.Errorf("{hostname} replacement: expected '%s', got '%s'", expected, actual) + + testCases := []struct { + template string + expect string + }{ + {"This hostname is {hostname}", "This hostname is " + hostname}, + {"This host is {host}.", "This host is localhost."}, + {"This request method is {method}.", "This request method is POST."}, + {"The response status is {status}.", "The response status is 200."}, + {"The Custom header is {>Custom}.", "The Custom header is foobarbaz."}, + {"The request is {request}.", "The request is POST / HTTP/1.1\\r\\nHost: localhost\\r\\nCustom: foobarbaz\\r\\nShorterval: 1\\r\\n\\r\\n."}, + {"The cUsToM header is {>cUsToM}...", "The cUsToM header is foobarbaz..."}, + {"The Non-Existent header is {>Non-Existent}.", "The Non-Existent header is -."}, + {"Bad {host placeholder...", "Bad {host placeholder..."}, + {"Bad {>Custom placeholder", "Bad {>Custom placeholder"}, + {"Bad {>Custom placeholder {>ShorterVal}", "Bad -"}, } - if expected, actual := "This host is localhost.", repl.Replace("This host is {host}."); expected != actual { - t.Errorf("{host} replacement: expected '%s', got '%s'", expected, actual) - } - if expected, actual := "This request method is POST.", repl.Replace("This request method is {method}."); expected != actual { - t.Errorf("{method} replacement: expected '%s', got '%s'", expected, actual) - } - if expected, actual := "The response status is 200.", repl.Replace("The response status is {status}."); expected != actual { - t.Errorf("{status} replacement: expected '%s', got '%s'", expected, actual) - } - if expected, actual := "The Custom header is foobarbaz.", repl.Replace("The Custom header is {>Custom}."); expected != actual { - t.Errorf("{>Custom} replacement: expected '%s', got '%s'", expected, actual) - } - if expected, actual := "The request is POST / HTTP/1.1\\r\\nHost: localhost\\r\\nCustom: foobarbaz\\r\\nShorterval: 1\\r\\n\\r\\n.", repl.Replace("The request is {request}."); expected != actual { - t.Errorf("{request} replacement: expected '%s', got '%s'", expected, actual) + for _, c := range testCases { + if expected, actual := c.expect, repl.Replace(c.template); expected != actual { + t.Errorf("for template '%s', expected '%s', got '%s'", c.template, expected, actual) + } } - // Test header case-insensitivity - if expected, actual := "The cUsToM header is foobarbaz...", repl.Replace("The cUsToM header is {>cUsToM}..."); expected != actual { - t.Errorf("{>cUsToM} replacement: expected '%s', got '%s'", expected, actual) + complexCases := []struct { + template string + replacements map[string]string + expect string + }{ + {"/a{1}/{2}", map[string]string{"{1}": "12", "{2}": ""}, "/a12/"}, } - // Test non-existent header/value - if expected, actual := "The Non-Existent header is -.", repl.Replace("The Non-Existent header is {>Non-Existent}."); expected != actual { - t.Errorf("{>Non-Existent} replacement: expected '%s', got '%s'", expected, actual) - } - - // Test bad placeholder - if expected, actual := "Bad {host placeholder...", repl.Replace("Bad {host placeholder..."); expected != actual { - t.Errorf("bad placeholder: expected '%s', got '%s'", expected, actual) - } - - // Test bad header placeholder - if expected, actual := "Bad {>Custom placeholder", repl.Replace("Bad {>Custom placeholder"); expected != actual { - t.Errorf("bad header placeholder: expected '%s', got '%s'", expected, actual) - } - - // Test bad header placeholder with valid one later - if expected, actual := "Bad -", repl.Replace("Bad {>Custom placeholder {>ShorterVal}"); expected != actual { - t.Errorf("bad header placeholders: expected '%s', got '%s'", expected, actual) - } - - // Test shorter header value with multiple placeholders - if expected, actual := "Short value 1 then foobarbaz.", repl.Replace("Short value {>ShorterVal} then {>Custom}."); expected != actual { - t.Errorf("short value: expected '%s', got '%s'", expected, actual) + for _, c := range complexCases { + repl := &replacer{ + replacements: c.replacements, + } + if expected, actual := c.expect, repl.Replace(c.template); expected != actual { + t.Errorf("for template '%s', expected '%s', got '%s'", c.template, expected, actual) + } } } diff --git a/caddyhttp/rewrite/rewrite_test.go b/caddyhttp/rewrite/rewrite_test.go index 1ac03388b..ac74291fe 100644 --- a/caddyhttp/rewrite/rewrite_test.go +++ b/caddyhttp/rewrite/rewrite_test.go @@ -85,7 +85,7 @@ func TestRewrite(t *testing.T) { {"/abcde/abcde.html", "/a"}, {"/abcde/abcde.html#1234", "/a#1234"}, {"/ab/ab.jpg", "/ajpg"}, - {"/reggrp/ad/12", "/a12"}, + {"/reggrp/ad/12", "/a12/"}, {"/reggrp/ad/124a", "/a124/a"}, {"/reggrp/ad/124abc", "/a124/abc"}, {"/reg2grp/ad/124abc", "/ad/124abc"}, diff --git a/caddyhttp/rewrite/to.go b/caddyhttp/rewrite/to.go index c49d4da11..75f69400d 100644 --- a/caddyhttp/rewrite/to.go +++ b/caddyhttp/rewrite/to.go @@ -28,6 +28,10 @@ func To(fs http.FileSystem, r *http.Request, to string, replacer httpserver.Repl query = tparts[1] } + if strings.HasSuffix(tparts[0], "/") && !strings.HasSuffix(t, "/") { + t += "/" + } + // add trailing slash for directories, if present if strings.HasSuffix(v, "/") && !strings.HasSuffix(t, "/") { t += "/" diff --git a/caddyhttp/rewrite/to_test.go b/caddyhttp/rewrite/to_test.go index 75b7156d8..5100a5f8b 100644 --- a/caddyhttp/rewrite/to_test.go +++ b/caddyhttp/rewrite/to_test.go @@ -22,7 +22,8 @@ func TestTo(t *testing.T) { {"/?a=b", "/testfile /index.php?{query}", "/testfile?a=b"}, {"/?a=b", "/testdir /index.php?{query}", "/index.php?a=b"}, {"/?a=b", "/testdir/ /index.php?{query}", "/testdir/?a=b"}, - {"/test?url=http://caddyserver.com", " /p/{path}?{query}", "/p/test?url=http://caddyserver.com"}, + {"/test?url=http://", " /p/{path}?{query}", "/p/test?url=http://"}, + {"/test/?url=http://", " /{uri}", "/test/?url=http://"}, } uri := func(r *url.URL) string {