From 5b94b82bc6c8b3b00cde9d64fa537747eb062f8a Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Thu, 20 Feb 2020 16:06:43 -0700 Subject: [PATCH] Small fixes and enhancements --- pkg/proxy/proxy.go | 2 - pkg/schemaserver/server/server.go | 7 ++- pkg/schemaserver/types/schemas.go | 16 ++++- pkg/schemaserver/urlbuilder/redirect.go | 77 +++++++++++++++++++++++++ pkg/server/router/router.go | 2 + 5 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 pkg/schemaserver/urlbuilder/redirect.go diff --git a/pkg/proxy/proxy.go b/pkg/proxy/proxy.go index 382cc83..9a205bb 100644 --- a/pkg/proxy/proxy.go +++ b/pkg/proxy/proxy.go @@ -1,7 +1,6 @@ package proxy import ( - "fmt" "net/http" "net/url" "strings" @@ -124,7 +123,6 @@ func stripLeaveSlash(prefix string, h http.Handler) http.Handler { p = "/" + p } req.URL.Path = p - fmt.Println(req.Method, " ", req.URL.String()) h.ServeHTTP(w, req) }) } diff --git a/pkg/schemaserver/server/server.go b/pkg/schemaserver/server/server.go index 2b32717..b2db4d7 100644 --- a/pkg/schemaserver/server/server.go +++ b/pkg/schemaserver/server/server.go @@ -3,6 +3,7 @@ package server import ( "net/http" + "github.com/rancher/steve/pkg/schemaserver/builtin" "github.com/rancher/steve/pkg/schemaserver/handlers" "github.com/rancher/steve/pkg/schemaserver/parse" "github.com/rancher/steve/pkg/schemaserver/types" @@ -39,7 +40,7 @@ type Defaults struct { func DefaultAPIServer() *Server { s := &Server{ - Schemas: types.EmptyAPISchemas(), + Schemas: types.EmptyAPISchemas().MustAddSchemas(builtin.Schemas), ResponseWriters: map[string]types.ResponseWriter{ "json": &writer.EncodingResponseWriter{ ContentType: "application/json", @@ -150,6 +151,10 @@ func (s *Server) Handle(apiOp *types.APIRequest) { } func (s *Server) handle(apiOp *types.APIRequest, parser parse.Parser) { + if apiOp.Schemas == nil { + apiOp.Schemas = s.Schemas + } + if err := parser(apiOp, parse.MuxURLParser); err != nil { // ensure defaults set so writer is assigned s.setDefaults(apiOp) diff --git a/pkg/schemaserver/types/schemas.go b/pkg/schemaserver/types/schemas.go index 9f429e0..f24cf86 100644 --- a/pkg/schemaserver/types/schemas.go +++ b/pkg/schemaserver/types/schemas.go @@ -38,9 +38,17 @@ func (a *APISchemas) MustImportAndCustomize(obj interface{}, f func(*APISchema)) Schema: schema, } a.Schemas[schema.ID] = apiSchema + a.addToIndex(apiSchema) f(apiSchema) } +func (a *APISchemas) MustAddSchemas(schemas *APISchemas) *APISchemas { + if err := a.AddSchemas(schemas); err != nil { + logrus.Fatalf("failed to add schemas: %v", err) + } + return a +} + func (a *APISchemas) AddSchemas(schema *APISchemas) error { for _, schema := range schema.Schemas { if err := a.AddSchema(*schema); err != nil { @@ -50,14 +58,18 @@ func (a *APISchemas) AddSchemas(schema *APISchemas) error { return nil } +func (a *APISchemas) addToIndex(schema *APISchema) { + a.index[strings.ToLower(schema.ID)] = schema + a.index[strings.ToLower(schema.PluralName)] = schema +} + func (a *APISchemas) AddSchema(schema APISchema) error { if err := a.InternalSchemas.AddSchema(*schema.Schema); err != nil { return err } schema.Schema = a.InternalSchemas.Schema(schema.ID) a.Schemas[schema.ID] = &schema - a.index[strings.ToLower(schema.ID)] = &schema - a.index[strings.ToLower(schema.PluralName)] = &schema + a.addToIndex(&schema) return nil } diff --git a/pkg/schemaserver/urlbuilder/redirect.go b/pkg/schemaserver/urlbuilder/redirect.go new file mode 100644 index 0000000..6ab3098 --- /dev/null +++ b/pkg/schemaserver/urlbuilder/redirect.go @@ -0,0 +1,77 @@ +package urlbuilder + +import ( + "bytes" + "net/http" + "net/url" + "strings" +) + +func RedirectRewrite(next http.Handler) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + prefix := req.Header.Get(PrefixHeader) + if prefix == "" { + next.ServeHTTP(rw, req) + return + } + r := &redirector{ + ResponseWriter: rw, + prefix: prefix, + } + next.ServeHTTP(r, req) + r.Close() + }) +} + +type redirector struct { + http.ResponseWriter + prefix string + from, to string + tempBuffer *bytes.Buffer +} + +func (r *redirector) Write(content []byte) (int, error) { + if r.tempBuffer == nil { + return r.ResponseWriter.Write(content) + } + return r.tempBuffer.Write(content) +} + +func (r *redirector) Close() error { + if r.tempBuffer == nil || r.from == "" || r.to == "" { + return nil + } + + content := bytes.Replace(r.tempBuffer.Bytes(), []byte(r.from), []byte(r.to), -1) + _, err := r.ResponseWriter.Write(content) + r.tempBuffer = nil + return err +} + +func (r *redirector) WriteHeader(statusCode int) { + defer func() { + // the anonymous func is so that we take the new value of statusCode, + // not copy it at invocation + r.ResponseWriter.WriteHeader(statusCode) + }() + + if statusCode != http.StatusMovedPermanently && statusCode != http.StatusFound { + return + } + + l := r.Header().Get("Location") + if l == "" { + return + } + + u, _ := url.Parse(l) + if !strings.HasPrefix(u.Path, r.prefix) { + r.from = u.Path + u.Path = r.prefix + u.Path + r.Header().Set("Location", u.String()) + r.to = u.Path + r.tempBuffer = &bytes.Buffer{} + } + + statusCode = http.StatusFound +} diff --git a/pkg/server/router/router.go b/pkg/server/router/router.go index 622798b..d73343e 100644 --- a/pkg/server/router/router.go +++ b/pkg/server/router/router.go @@ -4,6 +4,7 @@ import ( "net/http" "github.com/gorilla/mux" + "github.com/rancher/steve/pkg/schemaserver/urlbuilder" ) type RouterFunc func(h Handlers) http.Handler @@ -20,6 +21,7 @@ func Routes(h Handlers) http.Handler { m := mux.NewRouter() m.UseEncodedPath() m.StrictSlash(true) + m.Use(urlbuilder.RedirectRewrite) m.Path("/").Handler(h.APIRoot).HeadersRegexp("Accepts", ".*json.*") m.Path("/{name:v1}").Handler(h.APIRoot)