@@ -4,9 +4,11 @@ import (
44 "fmt"
55 "net/http"
66 "net/url"
7+ "regexp"
78 "strings"
89
910 "github.com/gorilla/mux"
11+ "github.com/justinas/alice"
1012 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
1113 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/app/pagewriter"
1214 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
@@ -25,7 +27,9 @@ func NewProxy(upstreams options.Upstreams, sigData *options.SignatureData, write
2527
2628 for _, upstream := range upstreams {
2729 if upstream.Static {
28− m.registerStaticResponseHandler(upstream)
30+ if err := m.registerStaticResponseHandler(upstream, writer); err != nil {
31+ return nil, fmt.Errorf("could not register static upstream %q: %v", upstream.ID, err)
32+ }
2933 continue
3034 }
3135
@@ -35,9 +39,13 @@ func NewProxy(upstreams options.Upstreams, sigData *options.SignatureData, write
3539 }
3640 switch u.Scheme {
3741 case fileScheme:
38− m.registerFileServer(upstream, u)
42+ if err := m.registerFileServer(upstream, u, writer); err != nil {
43+ return nil, fmt.Errorf("could not register file upstream %q: %v", upstream.ID, err)
44+ }
3945 case httpScheme, httpsScheme:
40− m.registerHTTPUpstreamProxy(upstream, u, sigData, writer)
46+ if err := m.registerHTTPUpstreamProxy(upstream, u, sigData, writer); err != nil {
47+ return nil, fmt.Errorf("could not register HTTP upstream %q: %v", upstream.ID, err)
48+ }
4149 default:
4250 return nil, fmt.Errorf("unknown scheme for upstream %q: %q", upstream.ID, u.Scheme)
4351 }
@@ -57,21 +65,31 @@ func (m *multiUpstreamProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request
5765}
5866
5967// registerStaticResponseHandler registers a static response handler with at the given path.
60−func (m *multiUpstreamProxy) registerStaticResponseHandler(upstream options.Upstream) {
68+func (m *multiUpstreamProxy) registerStaticResponseHandler(upstream options.Upstream, writer pagewriter.Writer) error {
6169 logger.Printf("mapping path %q => static response %d", upstream.Path, derefStaticCode(upstream.StaticCode))
62− m.registerSimpleHandler(upstream.Path, newStaticResponseHandler(upstream.ID, upstream.StaticCode))
70+ return m.registerHandler(upstream, newStaticResponseHandler(upstream.ID, upstream.StaticCode), writer)
6371}
6472
6573// registerFileServer registers a new fileServer based on the configuration given.
66−func (m *multiUpstreamProxy) registerFileServer(upstream options.Upstream, u *url.URL) {
74+func (m *multiUpstreamProxy) registerFileServer(upstream options.Upstream, u *url.URL, writer pagewriter.Writer) error {
6775 logger.Printf("mapping path %q => file system %q", upstream.Path, u.Path)
68− m.registerSimpleHandler(upstream.Path, newFileServer(upstream.ID, upstream.Path, u.Path))
76+ return m.registerHandler(upstream, newFileServer(upstream.ID, upstream.Path, u.Path), writer)
6977}
7078
7179// registerHTTPUpstreamProxy registers a new httpUpstreamProxy based on the configuration given.
72−func (m *multiUpstreamProxy) registerHTTPUpstreamProxy(upstream options.Upstream, u *url.URL, sigData *options.SignatureData, writer pagewriter.Writer) {
80+func (m *multiUpstreamProxy) registerHTTPUpstreamProxy(upstream options.Upstream, u *url.URL, sigData *options.SignatureData, writer pagewriter.Writer) error {
7381 logger.Printf("mapping path %q => upstream %q", upstream.Path, upstream.URI)
74− m.registerSimpleHandler(upstream.Path, newHTTPUpstreamProxy(upstream, u, sigData, writer.ProxyErrorHandler))
82+ return m.registerHandler(upstream, newHTTPUpstreamProxy(upstream, u, sigData, writer.ProxyErrorHandler), writer)
83+}
84+
85+// registerHandler ensures the given handler is regiestered with the serveMux.
86+func (m *multiUpstreamProxy) registerHandler(upstream options.Upstream, handler http.Handler, writer pagewriter.Writer) error {
87+ if upstream.RewriteTarget == "" {
88+ m.registerSimpleHandler(upstream.Path, handler)
89+ return nil
90+ }
91+
92+ return m.registerRewriteHandler(upstream, handler, writer)
7593}
7694
7795// registerSimpleHandler maintains the behaviour of the go standard serveMux
@@ -83,3 +101,22 @@ func (m *multiUpstreamProxy) registerSimpleHandler(path string, handler http.Han
83101 m.serveMux.Path(path).Handler(handler)
84102 }
85103}
104+
105+// registerRewriteHandler ensures the handler is registered for all paths
106+// which match the regex defined in the Path.
107+// Requests to the handler will have the request path rewritten before the
108+// request is made to the next handler.
109+func (m *multiUpstreamProxy) registerRewriteHandler(upstream options.Upstream, handler http.Handler, writer pagewriter.Writer) error {
110+ rewriteRegExp, err := regexp.Compile(upstream.Path)
111+ if err != nil {
112+ return fmt.Errorf("invalid path %q for upstream: %v", upstream.Path, err)
113+ }
114+
115+ rewrite := newRewritePath(rewriteRegExp, upstream.RewriteTarget, writer)
116+ h := alice.New(rewrite).Then(handler)
117+ m.serveMux.MatcherFunc(func(req *http.Request, match *mux.RouteMatch) bool {
118+ return rewriteRegExp.MatchString(req.URL.Path)
119+ }).Handler(h)
120+
121+ return nil
122+}