mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2024-11-24 08:52:25 +02:00
Allow request paths to be rewritten before proxying to upstream server
This commit is contained in:
parent
d2d62bb452
commit
6c62b25bf1
@ -371,7 +371,8 @@ Requests will be proxied to this upstream if the path matches the request path.
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `id` | _string_ | ID should be a unique identifier for the upstream.<br/>This value is required for all upstreams. |
|
||||
| `path` | _string_ | Path is used to map requests to the upstream server.<br/>The closest match will take precedence and all Paths must be unique. |
|
||||
| `path` | _string_ | Path is used to map requests to the upstream server.<br/>The closest match will take precedence and all Paths must be unique.<br/>Path can also take a pattern when used with RewriteTarget.<br/>Path segments can be captured and matched using regular experessions.<br/>Eg:<br/>- `^/foo$`: Match only the explicit path `/foo`<br/>- `^/bar/$`: Match any path prefixed with `/bar/`<br/>- `^/baz/(.*)$`: Match any path prefixed with `/baz` and capture the remaining path for use with RewriteTarget |
|
||||
| `rewriteTarget` | _string_ | RewriteTarget allows users to rewrite the request path before it is sent to<br/>the upstream server.<br/>Use the Path to capture segments for reuse within the rewrite target.<br/>Eg: With a Path of `^/baz/(.*)`, a RewriteTarget of `/foo/$1` would rewrite<br/>the request `/baz/abc/123` to `/foo/abc/123` before proxying to the<br/>upstream server. |
|
||||
| `uri` | _string_ | The URI of the upstream server. This may be an HTTP(S) server of a File<br/>based URL. It may include a path, in which case all requests will be served<br/>under that path.<br/>Eg:<br/>- http://localhost:8080<br/>- https://service.localhost<br/>- https://service.localhost/path<br/>- file://host/path<br/>If the URI's path is "/base" and the incoming request was for "/dir",<br/>the upstream request will be for "/base/dir". |
|
||||
| `insecureSkipTLSVerify` | _bool_ | InsecureSkipTLSVerify will skip TLS verification of upstream HTTPS hosts.<br/>This option is insecure and will allow potential Man-In-The-Middle attacks<br/>betweem OAuth2 Proxy and the usptream server.<br/>Defaults to false. |
|
||||
| `static` | _bool_ | Static will make all requests to this upstream have a static response.<br/>The response will have a body of "Authenticated" and a response code<br/>matching StaticCode.<br/>If StaticCode is not set, the response will return a 200 response. |
|
||||
|
4
go.mod
4
go.mod
@ -31,8 +31,8 @@ require (
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.11
|
||||
github.com/yhat/wsutil v0.0.0-20170731153501-1d66fa95c997
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
||||
google.golang.org/api v0.20.0
|
||||
|
6
go.sum
6
go.sum
@ -460,8 +460,9 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20200908183739-ae8ad444f925/go.mod h1:1phAWC201xIgDyaFpmDeZkgf70Q4Pd/CNqfRtVPtxNw=
|
||||
@ -503,8 +504,9 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -19,8 +19,22 @@ type Upstream struct {
|
||||
|
||||
// Path is used to map requests to the upstream server.
|
||||
// The closest match will take precedence and all Paths must be unique.
|
||||
// Path can also take a pattern when used with RewriteTarget.
|
||||
// Path segments can be captured and matched using regular experessions.
|
||||
// Eg:
|
||||
// - `^/foo$`: Match only the explicit path `/foo`
|
||||
// - `^/bar/$`: Match any path prefixed with `/bar/`
|
||||
// - `^/baz/(.*)$`: Match any path prefixed with `/baz` and capture the remaining path for use with RewriteTarget
|
||||
Path string `json:"path,omitempty"`
|
||||
|
||||
// RewriteTarget allows users to rewrite the request path before it is sent to
|
||||
// the upstream server.
|
||||
// Use the Path to capture segments for reuse within the rewrite target.
|
||||
// Eg: With a Path of `^/baz/(.*)`, a RewriteTarget of `/foo/$1` would rewrite
|
||||
// the request `/baz/abc/123` to `/foo/abc/123` before proxying to the
|
||||
// upstream server.
|
||||
RewriteTarget string `json:"rewriteTarget,omitempty"`
|
||||
|
||||
// The URI of the upstream server. This may be an HTTP(S) server of a File
|
||||
// based URL. It may include a path, in which case all requests will be served
|
||||
// under that path.
|
||||
|
@ -4,9 +4,11 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/justinas/alice"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/app/pagewriter"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||
@ -25,7 +27,9 @@ func NewProxy(upstreams options.Upstreams, sigData *options.SignatureData, write
|
||||
|
||||
for _, upstream := range upstreams {
|
||||
if upstream.Static {
|
||||
m.registerStaticResponseHandler(upstream)
|
||||
if err := m.registerStaticResponseHandler(upstream, writer); err != nil {
|
||||
return nil, fmt.Errorf("could not register static upstream %q: %v", upstream.ID, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@ -35,9 +39,13 @@ func NewProxy(upstreams options.Upstreams, sigData *options.SignatureData, write
|
||||
}
|
||||
switch u.Scheme {
|
||||
case fileScheme:
|
||||
m.registerFileServer(upstream, u)
|
||||
if err := m.registerFileServer(upstream, u, writer); err != nil {
|
||||
return nil, fmt.Errorf("could not register file upstream %q: %v", upstream.ID, err)
|
||||
}
|
||||
case httpScheme, httpsScheme:
|
||||
m.registerHTTPUpstreamProxy(upstream, u, sigData, writer)
|
||||
if err := m.registerHTTPUpstreamProxy(upstream, u, sigData, writer); err != nil {
|
||||
return nil, fmt.Errorf("could not register HTTP upstream %q: %v", upstream.ID, err)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown scheme for upstream %q: %q", upstream.ID, u.Scheme)
|
||||
}
|
||||
@ -57,21 +65,31 @@ func (m *multiUpstreamProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request
|
||||
}
|
||||
|
||||
// registerStaticResponseHandler registers a static response handler with at the given path.
|
||||
func (m *multiUpstreamProxy) registerStaticResponseHandler(upstream options.Upstream) {
|
||||
func (m *multiUpstreamProxy) registerStaticResponseHandler(upstream options.Upstream, writer pagewriter.Writer) error {
|
||||
logger.Printf("mapping path %q => static response %d", upstream.Path, derefStaticCode(upstream.StaticCode))
|
||||
m.registerSimpleHandler(upstream.Path, newStaticResponseHandler(upstream.ID, upstream.StaticCode))
|
||||
return m.registerHandler(upstream, newStaticResponseHandler(upstream.ID, upstream.StaticCode), writer)
|
||||
}
|
||||
|
||||
// registerFileServer registers a new fileServer based on the configuration given.
|
||||
func (m *multiUpstreamProxy) registerFileServer(upstream options.Upstream, u *url.URL) {
|
||||
func (m *multiUpstreamProxy) registerFileServer(upstream options.Upstream, u *url.URL, writer pagewriter.Writer) error {
|
||||
logger.Printf("mapping path %q => file system %q", upstream.Path, u.Path)
|
||||
m.registerSimpleHandler(upstream.Path, newFileServer(upstream.ID, upstream.Path, u.Path))
|
||||
return m.registerHandler(upstream, newFileServer(upstream.ID, upstream.Path, u.Path), writer)
|
||||
}
|
||||
|
||||
// registerHTTPUpstreamProxy registers a new httpUpstreamProxy based on the configuration given.
|
||||
func (m *multiUpstreamProxy) registerHTTPUpstreamProxy(upstream options.Upstream, u *url.URL, sigData *options.SignatureData, writer pagewriter.Writer) {
|
||||
func (m *multiUpstreamProxy) registerHTTPUpstreamProxy(upstream options.Upstream, u *url.URL, sigData *options.SignatureData, writer pagewriter.Writer) error {
|
||||
logger.Printf("mapping path %q => upstream %q", upstream.Path, upstream.URI)
|
||||
m.registerSimpleHandler(upstream.Path, newHTTPUpstreamProxy(upstream, u, sigData, writer.ProxyErrorHandler))
|
||||
return m.registerHandler(upstream, newHTTPUpstreamProxy(upstream, u, sigData, writer.ProxyErrorHandler), writer)
|
||||
}
|
||||
|
||||
// registerHandler ensures the given handler is regiestered with the serveMux.
|
||||
func (m *multiUpstreamProxy) registerHandler(upstream options.Upstream, handler http.Handler, writer pagewriter.Writer) error {
|
||||
if upstream.RewriteTarget == "" {
|
||||
m.registerSimpleHandler(upstream.Path, handler)
|
||||
return nil
|
||||
}
|
||||
|
||||
return m.registerRewriteHandler(upstream, handler, writer)
|
||||
}
|
||||
|
||||
// registerSimpleHandler maintains the behaviour of the go standard serveMux
|
||||
@ -83,3 +101,22 @@ func (m *multiUpstreamProxy) registerSimpleHandler(path string, handler http.Han
|
||||
m.serveMux.Path(path).Handler(handler)
|
||||
}
|
||||
}
|
||||
|
||||
// registerRewriteHandler ensures the handler is registered for all paths
|
||||
// which match the regex defined in the Path.
|
||||
// Requests to the handler will have the request path rewritten before the
|
||||
// request is made to the next handler.
|
||||
func (m *multiUpstreamProxy) registerRewriteHandler(upstream options.Upstream, handler http.Handler, writer pagewriter.Writer) error {
|
||||
rewriteRegExp, err := regexp.Compile(upstream.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid path %q for upstream: %v", upstream.Path, err)
|
||||
}
|
||||
|
||||
rewrite := newRewritePath(rewriteRegExp, upstream.RewriteTarget, writer)
|
||||
h := alice.New(rewrite).Then(handler)
|
||||
m.serveMux.MatcherFunc(func(req *http.Request, match *mux.RouteMatch) bool {
|
||||
return rewriteRegExp.MatchString(req.URL.Path)
|
||||
}).Handler(h)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -58,6 +58,12 @@ var _ = Describe("Proxy Suite", func() {
|
||||
Static: true,
|
||||
StaticCode: &ok,
|
||||
},
|
||||
{
|
||||
ID: "backend-with-rewrite-prefix",
|
||||
Path: "^/rewrite-prefix/(.*)",
|
||||
RewriteTarget: "/different/backend/path/$1",
|
||||
URI: serverAddr,
|
||||
},
|
||||
}
|
||||
|
||||
var err error
|
||||
@ -187,5 +193,47 @@ var _ = Describe("Proxy Suite", func() {
|
||||
raw: "404 page not found\n",
|
||||
},
|
||||
}),
|
||||
Entry("with a request to the rewrite prefix server", &proxyTableInput{
|
||||
target: "http://example.localhost/rewrite-prefix/1234",
|
||||
response: testHTTPResponse{
|
||||
code: 200,
|
||||
header: map[string][]string{
|
||||
contentType: {applicationJSON},
|
||||
},
|
||||
request: testHTTPRequest{
|
||||
Method: "GET",
|
||||
URL: "http://example.localhost/different/backend/path/1234",
|
||||
Header: map[string][]string{
|
||||
"Gap-Auth": {""},
|
||||
"Gap-Signature": {"sha256 jeAeM7wHSj2ab/l9YPvtTJ9l/8q1tpY2V/iwXF48bgw="},
|
||||
},
|
||||
Body: []byte{},
|
||||
Host: "example.localhost",
|
||||
RequestURI: "http://example.localhost/different/backend/path/1234",
|
||||
},
|
||||
},
|
||||
upstream: "backend-with-rewrite-prefix",
|
||||
}),
|
||||
Entry("with a request to a subpath of the rewrite prefix server", &proxyTableInput{
|
||||
target: "http://example.localhost/rewrite-prefix/1234/abc",
|
||||
response: testHTTPResponse{
|
||||
code: 200,
|
||||
header: map[string][]string{
|
||||
contentType: {applicationJSON},
|
||||
},
|
||||
request: testHTTPRequest{
|
||||
Method: "GET",
|
||||
URL: "http://example.localhost/different/backend/path/1234/abc",
|
||||
Header: map[string][]string{
|
||||
"Gap-Auth": {""},
|
||||
"Gap-Signature": {"sha256 rAkAc9gp7EndoOppJuvbuPnYuBcqrTkBnQx6iPS8xTA="},
|
||||
},
|
||||
Body: []byte{},
|
||||
Host: "example.localhost",
|
||||
RequestURI: "http://example.localhost/different/backend/path/1234/abc",
|
||||
},
|
||||
},
|
||||
upstream: "backend-with-rewrite-prefix",
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
80
pkg/upstream/rewrite.go
Normal file
80
pkg/upstream/rewrite.go
Normal file
@ -0,0 +1,80 @@
|
||||
package upstream
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/justinas/alice"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/app/pagewriter"
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||
)
|
||||
|
||||
// newRewritePath creates a new middleware that will rewrite the request URI
|
||||
// path before handing the request to the next server.
|
||||
func newRewritePath(rewriteRegExp *regexp.Regexp, rewriteTarget string, writer pagewriter.Writer) alice.Constructor {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return rewritePath(rewriteRegExp, rewriteTarget, writer, next)
|
||||
}
|
||||
}
|
||||
|
||||
// rewritePath uses the regexp to rewrite the request URI based on the provided
|
||||
// rewriteTarget.
|
||||
func rewritePath(rewriteRegExp *regexp.Regexp, rewriteTarget string, writer pagewriter.Writer, next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
reqURL, err := url.ParseRequestURI(req.RequestURI)
|
||||
if err != nil {
|
||||
logger.Errorf("could not parse request URI: %v", err)
|
||||
writer.WriteErrorPage(rw, pagewriter.ErrorPageOpts{
|
||||
Status: http.StatusInternalServerError,
|
||||
RequestID: middleware.GetRequestScope(req).RequestID,
|
||||
AppError: fmt.Sprintf("Could not parse request URI: %v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Use the regex to rewrite the request path before proxying to the upstream.
|
||||
newURI := rewriteRegExp.ReplaceAllString(reqURL.Path, rewriteTarget)
|
||||
reqURL.Path, reqURL.RawQuery, err = splitPathAndQuery(reqURL.Query(), newURI)
|
||||
if err != nil {
|
||||
logger.Errorf("could not parse rewrite URI: %v", err)
|
||||
writer.WriteErrorPage(rw, pagewriter.ErrorPageOpts{
|
||||
Status: http.StatusInternalServerError,
|
||||
RequestID: middleware.GetRequestScope(req).RequestID,
|
||||
AppError: fmt.Sprintf("Could not parse rewrite URI: %v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
req.RequestURI = reqURL.String()
|
||||
next.ServeHTTP(rw, req)
|
||||
})
|
||||
}
|
||||
|
||||
// splitPathAndQuery splits the rewritten path into the URL Path and the URL
|
||||
// raw query. Any rewritten query values are appended to the original query
|
||||
// values.
|
||||
// This relies on the underlying URL library to encode the query string.
|
||||
// For duplicate values it appends each as a separate value, e.g. ?foo=bar&foo=baz.
|
||||
func splitPathAndQuery(originalQuery url.Values, raw string) (string, string, error) {
|
||||
s := strings.SplitN(raw, "?", 2)
|
||||
if len(s) == 1 {
|
||||
return s[0], originalQuery.Encode(), nil
|
||||
}
|
||||
|
||||
queryValues, err := url.ParseQuery(s[1])
|
||||
if err != nil {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
for key, values := range queryValues {
|
||||
for _, value := range values {
|
||||
originalQuery.Add(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
return s[0], originalQuery.Encode(), nil
|
||||
}
|
60
pkg/upstream/rewrite_test.go
Normal file
60
pkg/upstream/rewrite_test.go
Normal file
@ -0,0 +1,60 @@
|
||||
package upstream
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"regexp"
|
||||
|
||||
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/app/pagewriter"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/extensions/table"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Rewrite", func() {
|
||||
type rewritePathTableInput struct {
|
||||
rewriteRegex *regexp.Regexp
|
||||
rewriteTarget string
|
||||
requestTarget string
|
||||
expectedRequestURI string
|
||||
}
|
||||
|
||||
DescribeTable("should rewrite the request path",
|
||||
func(in rewritePathTableInput) {
|
||||
req := httptest.NewRequest("", in.requestTarget, nil)
|
||||
rw := httptest.NewRecorder()
|
||||
|
||||
var gotRequestURI string
|
||||
handler := newRewritePath(in.rewriteRegex, in.rewriteTarget, &pagewriter.WriterFuncs{})(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotRequestURI = r.RequestURI
|
||||
}))
|
||||
handler.ServeHTTP(rw, req)
|
||||
|
||||
Expect(gotRequestURI).To(Equal(in.expectedRequestURI))
|
||||
},
|
||||
Entry("when the path matches the regexp", rewritePathTableInput{
|
||||
rewriteRegex: regexp.MustCompile("^/http/(.*)"),
|
||||
rewriteTarget: "/$1",
|
||||
requestTarget: "http://example.com/http/foo/bar",
|
||||
expectedRequestURI: "http://example.com/foo/bar",
|
||||
}),
|
||||
Entry("when the path does not match the regexp", rewritePathTableInput{
|
||||
rewriteRegex: regexp.MustCompile("^/http/(.*)"),
|
||||
rewriteTarget: "/$1",
|
||||
requestTarget: "https://example.com/https/foo/bar",
|
||||
expectedRequestURI: "https://example.com/https/foo/bar",
|
||||
}),
|
||||
Entry("when the regexp is not anchored", rewritePathTableInput{
|
||||
rewriteRegex: regexp.MustCompile("/http/(.*)"),
|
||||
rewriteTarget: "/$1",
|
||||
requestTarget: "http://example.com/bar/http/foo/bar",
|
||||
expectedRequestURI: "http://example.com/bar/foo/bar",
|
||||
}),
|
||||
Entry("when the regexp is rewriting to a query", rewritePathTableInput{
|
||||
rewriteRegex: regexp.MustCompile(`/articles/([a-z0-9\-]*)`),
|
||||
rewriteTarget: "/article?id=$1",
|
||||
requestTarget: "http://example.com/articles/blog-2021-01-01",
|
||||
expectedRequestURI: "http://example.com/article?id=blog-2021-01-01",
|
||||
}),
|
||||
)
|
||||
})
|
Loading…
Reference in New Issue
Block a user