git.iko.soy/typeable/oauth2-proxy
on master help sign in
Don't use http.StripPrefix when a file: upstream has rewriteTarget
cb53401Ian Roberts
pkg/upstream/file.go+39−5
@@ -2,9 +2,12 @@ package upstream
2
2
3import (
3import (
4 "net/http"
4 "net/http"
5+ "net/url"
5 "runtime"
6 "runtime"
6 "strings"
7 "strings"
7
8
9+ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
10+
8 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
11 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
9)
12)
10
13
@@ -12,22 +15,53 @@ const fileScheme = "file"
12
15
13// newFileServer creates a new fileServer that can serve requests
16// newFileServer creates a new fileServer that can serve requests
14// to a file system location.
17// to a file system location.
15−func newFileServer(id, path, fileSystemPath string) http.Handler {
18+func newFileServer(upstream options.Upstream, fileSystemPath string) http.Handler {
19+ handler := newFileServerForPath(fileSystemPath)
20+
21+ if upstream.RewriteTarget == "" {
22+ // if the upstream does not have a rewrite target, strip off the Path prefix
23+ // (so e.g. a request for /static/some-file.html looks for some-file.html
24+ // relative to the fileSystemPath rather than static/some-file.html).
25+ handler = http.StripPrefix(upstream.Path, handler)
26+ } else {
27+ // if the upstream *does* have a rewrite target then that means the target
28+ // path relative to the fileSystemPath will be the one in the (rewritten)
29+ // RequestURI.
30+ handler = requestURIToURL(handler)
31+ }
16 return &fileServer{
32 return &fileServer{
17− upstream: id,
33+ upstream: upstream.ID,
18− handler: newFileServerForPath(path, fileSystemPath),
34+ handler: handler,
19 }
35 }
20}
36}
21
37
22// newFileServerForPath creates a http.Handler to serve files from the filesystem
38// newFileServerForPath creates a http.Handler to serve files from the filesystem
23−func newFileServerForPath(path string, filesystemPath string) http.Handler {
39+func newFileServerForPath(filesystemPath string) http.Handler {
24 // Windows fileSSystemPath will be be prefixed with `/`, eg`/C:/...,
40 // Windows fileSSystemPath will be be prefixed with `/`, eg`/C:/...,
25 // if they were parsed by url.Parse`
41 // if they were parsed by url.Parse`
26 if runtime.GOOS == "windows" {
42 if runtime.GOOS == "windows" {
27 filesystemPath = strings.TrimPrefix(filesystemPath, "/")
43 filesystemPath = strings.TrimPrefix(filesystemPath, "/")
28 }
44 }
29
45
30− return http.StripPrefix(path, http.FileServer(http.Dir(filesystemPath)))
46+ return http.FileServer(http.Dir(filesystemPath))
47+}
48+
49+// requestURIToURL returns a Handler that replaces the URL in its request with
50+// the result of parsing req.RequestURI. This is necessary for file handlers
51+// that have a rewrite target, since http.FileServer uses req.URL.Path when
52+// looking for the target file, but the rewrite handler only updates the
53+// RequestURI, leaving the original path in the URL.
54+func requestURIToURL(handler http.Handler) http.Handler {
55+ return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
56+ reqURL, err := url.ParseRequestURI(req.RequestURI)
57+ if err != nil {
58+ http.Error(rw, "500 Internal Server Error", http.StatusInternalServerError)
59+ return
60+ }
61+
62+ req.URL = reqURL
63+ handler.ServeHTTP(rw, req)
64+ })
31}
65}
32
66
33// fileServer represents a single filesystem upstream proxy
67// fileServer represents a single filesystem upstream proxy
pkg/upstream/file_test.go+7−1
@@ -7,6 +7,8 @@ import (
7 "net/http/httptest"
7 "net/http/httptest"
8 "os"
8 "os"
9
9
10+ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
11+
10 middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
12 middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
11 . "github.com/onsi/ginkgo/v2"
13 . "github.com/onsi/ginkgo/v2"
12 . "github.com/onsi/gomega"
14 . "github.com/onsi/gomega"
@@ -31,8 +33,12 @@ var _ = Describe("File Server Suite", func() {
31 _, err := io.ReadFull(rand.Reader, idBytes)
33 _, err := io.ReadFull(rand.Reader, idBytes)
32 Expect(err).ToNot(HaveOccurred())
34 Expect(err).ToNot(HaveOccurred())
33 id = string(idBytes)
35 id = string(idBytes)
36+ upstream := options.Upstream{
37+ ID: id,
38+ Path: "/files",
39+ }
34
40
35− handler = newFileServer(id, "/files", filesDir)
41+ handler = newFileServer(upstream, filesDir)
36 })
42 })
37
43
38 AfterEach(func() {
44 AfterEach(func() {
pkg/upstream/proxy.go+1−1
@@ -81,7 +81,7 @@ func (m *multiUpstreamProxy) registerStaticResponseHandler(upstream options.Upst
81// registerFileServer registers a new fileServer based on the configuration given.
81// registerFileServer registers a new fileServer based on the configuration given.
82func (m *multiUpstreamProxy) registerFileServer(upstream options.Upstream, u *url.URL, writer pagewriter.Writer) error {
82func (m *multiUpstreamProxy) registerFileServer(upstream options.Upstream, u *url.URL, writer pagewriter.Writer) error {
83 logger.Printf("mapping path %q => file system %q", upstream.Path, u.Path)
83 logger.Printf("mapping path %q => file system %q", upstream.Path, u.Path)
84− return m.registerHandler(upstream, newFileServer(upstream.ID, upstream.Path, u.Path), writer)
84+ return m.registerHandler(upstream, newFileServer(upstream, u.Path), writer)
85}
85}
86
86
87// registerHTTPUpstreamProxy registers a new httpUpstreamProxy based on the configuration given.
87// registerHTTPUpstreamProxy registers a new httpUpstreamProxy based on the configuration given.