From 05d7c2e3b34a8de31f205bb165ab0640410f6282 Mon Sep 17 00:00:00 2001 From: Marcel Ludwig Date: Fri, 30 Oct 2020 12:57:27 +0100 Subject: [PATCH] Fix missing hosts handling for defined files block #59 --- config/runtime/mux.go | 10 ++-------- config/runtime/server.go | 24 ++++++++++++++++-------- handler/file.go | 11 ++++++++--- handler/file_test.go | 5 ++++- server/mux.go | 40 ++++++++++++++++++++++++---------------- 5 files changed, 54 insertions(+), 36 deletions(-) diff --git a/config/runtime/mux.go b/config/runtime/mux.go index 97c8993bf..f613d81cc 100644 --- a/config/runtime/mux.go +++ b/config/runtime/mux.go @@ -3,11 +3,9 @@ package runtime import ( "net/http" "path" - "path/filepath" "github.com/avenga/couper/config" "github.com/avenga/couper/errors" - "github.com/avenga/couper/handler" "github.com/avenga/couper/utils" ) @@ -16,8 +14,8 @@ type MuxOptions struct { APIPath string EndpointRoutes map[string]http.Handler FileBasePath string - FileHandler http.Handler FileErrTpl *errors.Template + FileRoutes map[string]http.Handler SPARoutes map[string]http.Handler } @@ -26,6 +24,7 @@ func NewMuxOptions(conf *config.Server) (*MuxOptions, error) { APIErrTpl: errors.DefaultJSON, FileErrTpl: errors.DefaultHTML, EndpointRoutes: make(map[string]http.Handler), + FileRoutes: make(map[string]http.Handler), SPARoutes: make(map[string]http.Handler), } @@ -50,12 +49,7 @@ func NewMuxOptions(conf *config.Server) (*MuxOptions, error) { options.FileErrTpl = tpl } - absPath, err := filepath.Abs(conf.Files.DocumentRoot) - if err != nil { - return nil, err - } options.FileBasePath = utils.JoinPath("/", conf.BasePath, conf.Files.BasePath) - options.FileHandler = handler.NewFile(options.FileBasePath, absPath, options.FileErrTpl) } return options, nil diff --git a/config/runtime/server.go b/config/runtime/server.go index 541e122fb..695201422 100644 --- a/config/runtime/server.go +++ b/config/runtime/server.go @@ -79,6 +79,11 @@ func NewServerConfiguration(conf *config.Gateway, httpConf *HTTPConfig, log *log if err != nil { log.Fatal(err) } + + spaHandler = configureProtectedHandler(accessControls, errors.DefaultHTML, // TODO: server err tpl + config.NewAccessControl(srvConf.AccessControl, srvConf.DisableAccessControl), + config.NewAccessControl(srvConf.Spa.AccessControl, srvConf.Spa.DisableAccessControl), spaHandler) + for _, spaPath := range srvConf.Spa.Paths { for _, p := range getPathsFromHosts(defaultPort, srvConf.Hosts, utils.JoinPath("/", srvConf.BasePath, srvConf.Spa.BasePath, spaPath)) { @@ -87,16 +92,19 @@ func NewServerConfiguration(conf *config.Gateway, httpConf *HTTPConfig, log *log } } - if muxOptions.FileHandler != nil { - muxOptions.FileHandler = configureProtectedHandler(accessControls, muxOptions.FileErrTpl, - config.NewAccessControl(srvConf.AccessControl, srvConf.DisableAccessControl), - config.NewAccessControl(srvConf.Files.AccessControl, srvConf.Files.DisableAccessControl), muxOptions.FileHandler) - } + if srvConf.Files != nil { + fileHandler, err := handler.NewFile(muxOptions.FileBasePath, srvConf.Files.DocumentRoot, muxOptions.FileErrTpl) + if err != nil { + log.Fatal(err) + } - if spaHandler != nil { - spaHandler = configureProtectedHandler(accessControls, errors.DefaultHTML, // TODO: server err tpl + protectedFileHandler := configureProtectedHandler(accessControls, muxOptions.FileErrTpl, config.NewAccessControl(srvConf.AccessControl, srvConf.DisableAccessControl), - config.NewAccessControl(srvConf.Spa.AccessControl, srvConf.Spa.DisableAccessControl), spaHandler) + config.NewAccessControl(srvConf.Files.AccessControl, srvConf.Files.DisableAccessControl), fileHandler) + + for _, p := range getPathsFromHosts(defaultPort, srvConf.Hosts, muxOptions.FileBasePath) { + muxOptions.FileRoutes[p] = protectedFileHandler + } } if srvConf.API == nil { diff --git a/handler/file.go b/handler/file.go index 002ea7e21..c48fa58d7 100644 --- a/handler/file.go +++ b/handler/file.go @@ -4,6 +4,7 @@ import ( "net/http" "os" "path" + "path/filepath" "strings" "github.com/avenga/couper/errors" @@ -28,14 +29,18 @@ type File struct { rootDir http.Dir } -func NewFile(basePath, docRoot string, errTpl *errors.Template) *File { +func NewFile(basePath, docRoot string, errTpl *errors.Template) (*File, error) { + dir, err := filepath.Abs(docRoot) + if err != nil { + return nil, err + } f := &File{ basePath: basePath, errorTpl: errTpl, - rootDir: http.Dir(docRoot), + rootDir: http.Dir(dir), } - return f + return f, nil } func (f *File) ServeHTTP(rw http.ResponseWriter, req *http.Request) { diff --git a/handler/file_test.go b/handler/file_test.go index 256779ad3..f785ba79c 100644 --- a/handler/file_test.go +++ b/handler/file_test.go @@ -39,7 +39,10 @@ func TestFile_ServeHTTP(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - f := NewFile(tt.fields.basePath, path.Join(wd, tt.fields.docRootDir), errors.DefaultHTML) + f, err := NewFile(tt.fields.basePath, path.Join(wd, tt.fields.docRootDir), errors.DefaultHTML) + if err != nil { + t.Fatal(err) + } rec := httptest.NewRecorder() f.ServeHTTP(rec, tt.req) diff --git a/server/mux.go b/server/mux.go index 610dcdeb6..1f639cba0 100644 --- a/server/mux.go +++ b/server/mux.go @@ -20,12 +20,12 @@ import ( // Mux is a http request router and dispatches requests // to their corresponding http handlers. type Mux struct { - apiPath string apiErrHandler *errors.Template + apiPath string endpointRoot *pathpattern.Node fileBasePath string - fileHandler http.Handler fileErrHandler *errors.Template + fileRoot *pathpattern.Node router *openapi3filter.Router spaRoot *pathpattern.Node } @@ -50,12 +50,12 @@ func NewMux(options *runtime.MuxOptions) *Mux { } mux := &Mux{ - apiPath: opts.APIPath, apiErrHandler: opts.APIErrTpl, + apiPath: opts.APIPath, + endpointRoot: &pathpattern.Node{}, fileBasePath: opts.FileBasePath, - fileHandler: opts.FileHandler, fileErrHandler: opts.FileErrTpl, - endpointRoot: &pathpattern.Node{}, + fileRoot: &pathpattern.Node{}, spaRoot: &pathpattern.Node{}, } @@ -64,6 +64,10 @@ func NewMux(options *runtime.MuxOptions) *Mux { mux.mustAddRoute(mux.endpointRoot, allowedMethods, path, h) } + for path, h := range opts.FileRoutes { + mux.mustAddRoute(mux.fileRoot, []string{http.MethodGet}, utils.JoinPath(path, "/**"), h) + } + for path, h := range opts.SPARoutes { mux.mustAddRoute(mux.spaRoot, []string{http.MethodGet}, path, h) } @@ -128,13 +132,14 @@ func (m *Mux) FindHandler(req *http.Request) http.Handler { return m.apiErrHandler.ServeError(errors.APIRouteNotFound) } - if m.hasFileResponse(req) { - return m.fileHandler + fileHandler, exist := m.hasFileResponse(req) + if exist { + return fileHandler } node, paramValues = m.match(m.spaRoot, req) if node == nil { - if m.fileHandler != nil && strings.HasPrefix(req.URL.Path, m.fileBasePath) { + if fileHandler != nil && strings.HasPrefix(req.URL.Path, m.fileBasePath) { return m.fileErrHandler.ServeError(errors.FilesRouteNotFound) } // TODO: server err handler @@ -183,18 +188,21 @@ func (m *Mux) match(root *pathpattern.Node, req *http.Request) (*pathpattern.Nod return node, paramValues } -func (m *Mux) hasFileResponse(req *http.Request) bool { - if m.fileHandler == nil { - return false +func (m *Mux) hasFileResponse(req *http.Request) (http.Handler, bool) { + node, _ := m.match(m.fileRoot, req) + if node == nil { + return nil, false } - fileHandler := m.fileHandler - if p, isProtected := m.fileHandler.(ac.ProtectedHandler); isProtected { + route := node.Value.(*openapi3filter.Route) + fileHandler := route.Handler + if p, isProtected := fileHandler.(ac.ProtectedHandler); isProtected { fileHandler = p.Child() } - if fh, ok := fileHandler.(handler.HasResponse); ok && fh.HasResponse(req) { - return true + + if fh, ok := fileHandler.(handler.HasResponse); ok { + return fileHandler, fh.HasResponse(req) } - return false + return fileHandler, false }