Small fixes and enhancements

This commit is contained in:
Darren Shepherd 2020-02-20 16:06:43 -07:00
parent 265a7a8763
commit 5b94b82bc6
5 changed files with 99 additions and 5 deletions

View File

@ -1,7 +1,6 @@
package proxy package proxy
import ( import (
"fmt"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
@ -124,7 +123,6 @@ func stripLeaveSlash(prefix string, h http.Handler) http.Handler {
p = "/" + p p = "/" + p
} }
req.URL.Path = p req.URL.Path = p
fmt.Println(req.Method, " ", req.URL.String())
h.ServeHTTP(w, req) h.ServeHTTP(w, req)
}) })
} }

View File

@ -3,6 +3,7 @@ package server
import ( import (
"net/http" "net/http"
"github.com/rancher/steve/pkg/schemaserver/builtin"
"github.com/rancher/steve/pkg/schemaserver/handlers" "github.com/rancher/steve/pkg/schemaserver/handlers"
"github.com/rancher/steve/pkg/schemaserver/parse" "github.com/rancher/steve/pkg/schemaserver/parse"
"github.com/rancher/steve/pkg/schemaserver/types" "github.com/rancher/steve/pkg/schemaserver/types"
@ -39,7 +40,7 @@ type Defaults struct {
func DefaultAPIServer() *Server { func DefaultAPIServer() *Server {
s := &Server{ s := &Server{
Schemas: types.EmptyAPISchemas(), Schemas: types.EmptyAPISchemas().MustAddSchemas(builtin.Schemas),
ResponseWriters: map[string]types.ResponseWriter{ ResponseWriters: map[string]types.ResponseWriter{
"json": &writer.EncodingResponseWriter{ "json": &writer.EncodingResponseWriter{
ContentType: "application/json", ContentType: "application/json",
@ -150,6 +151,10 @@ func (s *Server) Handle(apiOp *types.APIRequest) {
} }
func (s *Server) handle(apiOp *types.APIRequest, parser parse.Parser) { 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 { if err := parser(apiOp, parse.MuxURLParser); err != nil {
// ensure defaults set so writer is assigned // ensure defaults set so writer is assigned
s.setDefaults(apiOp) s.setDefaults(apiOp)

View File

@ -38,9 +38,17 @@ func (a *APISchemas) MustImportAndCustomize(obj interface{}, f func(*APISchema))
Schema: schema, Schema: schema,
} }
a.Schemas[schema.ID] = apiSchema a.Schemas[schema.ID] = apiSchema
a.addToIndex(apiSchema)
f(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 { func (a *APISchemas) AddSchemas(schema *APISchemas) error {
for _, schema := range schema.Schemas { for _, schema := range schema.Schemas {
if err := a.AddSchema(*schema); err != nil { if err := a.AddSchema(*schema); err != nil {
@ -50,14 +58,18 @@ func (a *APISchemas) AddSchemas(schema *APISchemas) error {
return nil 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 { func (a *APISchemas) AddSchema(schema APISchema) error {
if err := a.InternalSchemas.AddSchema(*schema.Schema); err != nil { if err := a.InternalSchemas.AddSchema(*schema.Schema); err != nil {
return err return err
} }
schema.Schema = a.InternalSchemas.Schema(schema.ID) schema.Schema = a.InternalSchemas.Schema(schema.ID)
a.Schemas[schema.ID] = &schema a.Schemas[schema.ID] = &schema
a.index[strings.ToLower(schema.ID)] = &schema a.addToIndex(&schema)
a.index[strings.ToLower(schema.PluralName)] = &schema
return nil return nil
} }

View File

@ -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
}

View File

@ -4,6 +4,7 @@ import (
"net/http" "net/http"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/rancher/steve/pkg/schemaserver/urlbuilder"
) )
type RouterFunc func(h Handlers) http.Handler type RouterFunc func(h Handlers) http.Handler
@ -20,6 +21,7 @@ func Routes(h Handlers) http.Handler {
m := mux.NewRouter() m := mux.NewRouter()
m.UseEncodedPath() m.UseEncodedPath()
m.StrictSlash(true) m.StrictSlash(true)
m.Use(urlbuilder.RedirectRewrite)
m.Path("/").Handler(h.APIRoot).HeadersRegexp("Accepts", ".*json.*") m.Path("/").Handler(h.APIRoot).HeadersRegexp("Accepts", ".*json.*")
m.Path("/{name:v1}").Handler(h.APIRoot) m.Path("/{name:v1}").Handler(h.APIRoot)