mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-05 07:24:08 +08:00
07ad4655db
Before, modifying the path might have affected how a new query string was built if the query string relied on the path. Now, we build each component in isolation and only change the URI on the request later. Also, prevent trailing & in query string.
270 lines
8.2 KiB
Go
270 lines
8.2 KiB
Go
// Copyright 2015 Matthew Holt and The Caddy Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package rewrite
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/caddyserver/caddy/v2"
|
|
)
|
|
|
|
func TestRewrite(t *testing.T) {
|
|
repl := caddy.NewReplacer()
|
|
|
|
for i, tc := range []struct {
|
|
input, expect *http.Request
|
|
rule Rewrite
|
|
}{
|
|
{
|
|
input: newRequest(t, "GET", "/"),
|
|
expect: newRequest(t, "GET", "/"),
|
|
},
|
|
{
|
|
rule: Rewrite{Method: "GET", URI: "/"},
|
|
input: newRequest(t, "GET", "/"),
|
|
expect: newRequest(t, "GET", "/"),
|
|
},
|
|
{
|
|
rule: Rewrite{Method: "POST"},
|
|
input: newRequest(t, "GET", "/"),
|
|
expect: newRequest(t, "POST", "/"),
|
|
},
|
|
|
|
{
|
|
rule: Rewrite{URI: "/foo"},
|
|
input: newRequest(t, "GET", "/"),
|
|
expect: newRequest(t, "GET", "/foo"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/foo"},
|
|
input: newRequest(t, "GET", "/bar"),
|
|
expect: newRequest(t, "GET", "/foo"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "foo"},
|
|
input: newRequest(t, "GET", "/"),
|
|
expect: newRequest(t, "GET", "foo"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/foo{http.request.uri.path}"},
|
|
input: newRequest(t, "GET", "/bar"),
|
|
expect: newRequest(t, "GET", "/foo/bar"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/index.php?p={http.request.uri.path}"},
|
|
input: newRequest(t, "GET", "/foo/bar"),
|
|
expect: newRequest(t, "GET", "/index.php?p=%2Ffoo%2Fbar"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "?a=b&{http.request.uri.query}"},
|
|
input: newRequest(t, "GET", "/"),
|
|
expect: newRequest(t, "GET", "/?a=b"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/?c=d"},
|
|
input: newRequest(t, "GET", "/"),
|
|
expect: newRequest(t, "GET", "/?c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/?c=d"},
|
|
input: newRequest(t, "GET", "/?a=b"),
|
|
expect: newRequest(t, "GET", "/?c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "?c=d"},
|
|
input: newRequest(t, "GET", "/foo"),
|
|
expect: newRequest(t, "GET", "/foo?c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/?c=d"},
|
|
input: newRequest(t, "GET", "/foo"),
|
|
expect: newRequest(t, "GET", "/?c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/?{http.request.uri.query}&c=d"},
|
|
input: newRequest(t, "GET", "/"),
|
|
expect: newRequest(t, "GET", "/?c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/foo?{http.request.uri.query}&c=d"},
|
|
input: newRequest(t, "GET", "/"),
|
|
expect: newRequest(t, "GET", "/foo?c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "?{http.request.uri.query}&c=d"},
|
|
input: newRequest(t, "GET", "/foo"),
|
|
expect: newRequest(t, "GET", "/foo?c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "{http.request.uri.path}?{http.request.uri.query}&c=d"},
|
|
input: newRequest(t, "GET", "/foo"),
|
|
expect: newRequest(t, "GET", "/foo?c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "{http.request.uri.path}?{http.request.uri.query}&c=d"},
|
|
input: newRequest(t, "GET", "/foo"),
|
|
expect: newRequest(t, "GET", "/foo?c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/index.php?{http.request.uri.query}&c=d"},
|
|
input: newRequest(t, "GET", "/foo"),
|
|
expect: newRequest(t, "GET", "/index.php?c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "?a=b&c=d"},
|
|
input: newRequest(t, "GET", "/foo"),
|
|
expect: newRequest(t, "GET", "/foo?a=b&c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/index.php?{http.request.uri.query}&c=d"},
|
|
input: newRequest(t, "GET", "/?a=b"),
|
|
expect: newRequest(t, "GET", "/index.php?a=b&c=d"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/index.php?c=d&{http.request.uri.query}"},
|
|
input: newRequest(t, "GET", "/?a=b"),
|
|
expect: newRequest(t, "GET", "/index.php?c=d&a=b"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/index.php?{http.request.uri.query}&p={http.request.uri.path}"},
|
|
input: newRequest(t, "GET", "/foo/bar?a=b"),
|
|
expect: newRequest(t, "GET", "/index.php?a=b&p=%2Ffoo%2Fbar"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "{http.request.uri.path}?"},
|
|
input: newRequest(t, "GET", "/foo/bar?a=b&c=d"),
|
|
expect: newRequest(t, "GET", "/foo/bar"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "?qs={http.request.uri.query}"},
|
|
input: newRequest(t, "GET", "/foo?a=b&c=d"),
|
|
expect: newRequest(t, "GET", "/foo?qs=a%3Db%26c%3Dd"),
|
|
},
|
|
{
|
|
rule: Rewrite{URI: "/foo?{http.request.uri.query}#frag"},
|
|
input: newRequest(t, "GET", "/foo/bar?a=b"),
|
|
expect: newRequest(t, "GET", "/foo?a=b#frag"),
|
|
},
|
|
|
|
{
|
|
rule: Rewrite{StripPathPrefix: "/prefix"},
|
|
input: newRequest(t, "GET", "/foo/bar"),
|
|
expect: newRequest(t, "GET", "/foo/bar"),
|
|
},
|
|
{
|
|
rule: Rewrite{StripPathPrefix: "/prefix"},
|
|
input: newRequest(t, "GET", "/prefix/foo/bar"),
|
|
expect: newRequest(t, "GET", "/foo/bar"),
|
|
},
|
|
{
|
|
rule: Rewrite{StripPathPrefix: "/prefix"},
|
|
input: newRequest(t, "GET", "/foo/prefix/bar"),
|
|
expect: newRequest(t, "GET", "/foo/prefix/bar"),
|
|
},
|
|
|
|
{
|
|
rule: Rewrite{StripPathSuffix: "/suffix"},
|
|
input: newRequest(t, "GET", "/foo/bar"),
|
|
expect: newRequest(t, "GET", "/foo/bar"),
|
|
},
|
|
{
|
|
rule: Rewrite{StripPathSuffix: "suffix"},
|
|
input: newRequest(t, "GET", "/foo/bar/suffix"),
|
|
expect: newRequest(t, "GET", "/foo/bar/"),
|
|
},
|
|
{
|
|
rule: Rewrite{StripPathSuffix: "/suffix"},
|
|
input: newRequest(t, "GET", "/foo/suffix/bar"),
|
|
expect: newRequest(t, "GET", "/foo/suffix/bar"),
|
|
},
|
|
|
|
{
|
|
rule: Rewrite{URISubstring: []replacer{{Find: "findme", Replace: "replaced"}}},
|
|
input: newRequest(t, "GET", "/foo/bar"),
|
|
expect: newRequest(t, "GET", "/foo/bar"),
|
|
},
|
|
{
|
|
rule: Rewrite{URISubstring: []replacer{{Find: "findme", Replace: "replaced"}}},
|
|
input: newRequest(t, "GET", "/foo/findme/bar"),
|
|
expect: newRequest(t, "GET", "/foo/replaced/bar"),
|
|
},
|
|
} {
|
|
// copy the original input just enough so that we can
|
|
// compare it after the rewrite to see if it changed
|
|
originalInput := &http.Request{
|
|
Method: tc.input.Method,
|
|
RequestURI: tc.input.RequestURI,
|
|
URL: &*tc.input.URL,
|
|
}
|
|
|
|
// populate the replacer just enough for our tests
|
|
repl.Set("http.request.uri.path", tc.input.URL.Path)
|
|
repl.Set("http.request.uri.query", tc.input.URL.RawQuery)
|
|
|
|
changed := tc.rule.rewrite(tc.input, repl, nil)
|
|
|
|
if expected, actual := !reqEqual(originalInput, tc.input), changed; expected != actual {
|
|
t.Errorf("Test %d: Expected changed=%t but was %t", i, expected, actual)
|
|
}
|
|
if expected, actual := tc.expect.Method, tc.input.Method; expected != actual {
|
|
t.Errorf("Test %d: Expected Method='%s' but got '%s'", i, expected, actual)
|
|
}
|
|
if expected, actual := tc.expect.RequestURI, tc.input.RequestURI; expected != actual {
|
|
t.Errorf("Test %d: Expected RequestURI='%s' but got '%s'", i, expected, actual)
|
|
}
|
|
if expected, actual := tc.expect.URL.String(), tc.input.URL.String(); expected != actual {
|
|
t.Errorf("Test %d: Expected URL='%s' but got '%s'", i, expected, actual)
|
|
}
|
|
if expected, actual := tc.expect.URL.RequestURI(), tc.input.URL.RequestURI(); expected != actual {
|
|
t.Errorf("Test %d: Expected URL.RequestURI()='%s' but got '%s'", i, expected, actual)
|
|
}
|
|
if expected, actual := tc.expect.URL.Fragment, tc.input.URL.Fragment; expected != actual {
|
|
t.Errorf("Test %d: Expected URL.Fragment='%s' but got '%s'", i, expected, actual)
|
|
}
|
|
}
|
|
}
|
|
|
|
func newRequest(t *testing.T, method, uri string) *http.Request {
|
|
req, err := http.NewRequest(method, uri, nil)
|
|
if err != nil {
|
|
t.Fatalf("error creating request: %v", err)
|
|
}
|
|
req.RequestURI = req.URL.RequestURI() // simulate incoming request
|
|
return req
|
|
}
|
|
|
|
// reqEqual if r1 and r2 are equal enough for our purposes.
|
|
func reqEqual(r1, r2 *http.Request) bool {
|
|
if r1.Method != r2.Method {
|
|
return false
|
|
}
|
|
if r1.RequestURI != r2.RequestURI {
|
|
return false
|
|
}
|
|
if (r1.URL == nil && r2.URL != nil) || (r1.URL != nil && r2.URL == nil) {
|
|
return false
|
|
}
|
|
if r1.URL == nil && r2.URL == nil {
|
|
return true
|
|
}
|
|
return r1.URL.Scheme == r2.URL.Scheme &&
|
|
r1.URL.Host == r2.URL.Host &&
|
|
r1.URL.Path == r2.URL.Path &&
|
|
r1.URL.RawPath == r2.URL.RawPath &&
|
|
r1.URL.RawQuery == r2.URL.RawQuery &&
|
|
r1.URL.Fragment == r2.URL.Fragment
|
|
}
|