2017-11-11 04:44:02 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
|
2017-11-21 20:46:30 +00:00
|
|
|
"sync"
|
|
|
|
|
2017-11-11 04:44:02 +00:00
|
|
|
"github.com/rancher/norman/api/builtin"
|
2017-11-21 20:46:30 +00:00
|
|
|
"github.com/rancher/norman/api/handler"
|
2017-11-11 04:44:02 +00:00
|
|
|
"github.com/rancher/norman/api/writer"
|
|
|
|
"github.com/rancher/norman/authorization"
|
|
|
|
"github.com/rancher/norman/httperror"
|
|
|
|
"github.com/rancher/norman/parse"
|
2017-11-21 20:46:30 +00:00
|
|
|
"github.com/rancher/norman/store/wrapper"
|
2017-11-11 04:44:02 +00:00
|
|
|
"github.com/rancher/norman/types"
|
|
|
|
)
|
|
|
|
|
2017-11-21 20:46:30 +00:00
|
|
|
type StoreWrapper func(types.Store) types.Store
|
|
|
|
|
2017-11-11 04:44:02 +00:00
|
|
|
type Parser func(rw http.ResponseWriter, req *http.Request) (*types.APIContext, error)
|
|
|
|
|
|
|
|
type Server struct {
|
2017-11-21 20:46:30 +00:00
|
|
|
initBuiltin sync.Once
|
|
|
|
IgnoreBuiltin bool
|
|
|
|
Parser Parser
|
|
|
|
Resolver parse.ResolverFunc
|
|
|
|
SubContextAttributeProvider types.SubContextAttributeProvider
|
|
|
|
ResponseWriters map[string]ResponseWriter
|
|
|
|
schemas *types.Schemas
|
|
|
|
QueryFilter types.QueryFilter
|
|
|
|
StoreWrapper StoreWrapper
|
|
|
|
Defaults Defaults
|
2017-11-11 04:44:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Defaults struct {
|
|
|
|
ActionHandler types.ActionHandler
|
|
|
|
ListHandler types.RequestHandler
|
|
|
|
LinkHandler types.RequestHandler
|
|
|
|
CreateHandler types.RequestHandler
|
|
|
|
DeleteHandler types.RequestHandler
|
|
|
|
UpdateHandler types.RequestHandler
|
|
|
|
Store types.Store
|
|
|
|
ErrorHandler types.ErrorHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewAPIServer() *Server {
|
|
|
|
s := &Server{
|
|
|
|
schemas: types.NewSchemas(),
|
|
|
|
ResponseWriters: map[string]ResponseWriter{
|
|
|
|
"json": &writer.JSONResponseWriter{},
|
|
|
|
"html": &writer.HTMLResponseWriter{},
|
|
|
|
},
|
2017-11-21 20:46:30 +00:00
|
|
|
SubContextAttributeProvider: &parse.DefaultSubContextAttributeProvider{},
|
|
|
|
Resolver: parse.DefaultResolver,
|
2017-11-11 04:44:02 +00:00
|
|
|
Defaults: Defaults{
|
2017-11-21 20:46:30 +00:00
|
|
|
CreateHandler: handler.CreateHandler,
|
|
|
|
DeleteHandler: handler.DeleteHandler,
|
|
|
|
UpdateHandler: handler.UpdateHandler,
|
|
|
|
ListHandler: handler.ListHandler,
|
2017-11-11 04:44:02 +00:00
|
|
|
LinkHandler: func(*types.APIContext) error {
|
2017-11-21 20:46:30 +00:00
|
|
|
return httperror.NewAPIError(httperror.NotFound, "Link not found")
|
2017-11-11 04:44:02 +00:00
|
|
|
},
|
|
|
|
ErrorHandler: httperror.ErrorHandler,
|
|
|
|
},
|
2017-11-21 20:46:30 +00:00
|
|
|
StoreWrapper: wrapper.Wrap,
|
|
|
|
QueryFilter: handler.QueryFilter,
|
2017-11-11 04:44:02 +00:00
|
|
|
}
|
|
|
|
|
2017-11-21 20:46:30 +00:00
|
|
|
s.Parser = s.parser
|
|
|
|
return s
|
|
|
|
}
|
2017-11-11 04:44:02 +00:00
|
|
|
|
2017-11-21 20:46:30 +00:00
|
|
|
func (s *Server) parser(rw http.ResponseWriter, req *http.Request) (*types.APIContext, error) {
|
|
|
|
ctx, err := parse.Parse(rw, req, s.schemas, s.Resolver)
|
|
|
|
ctx.ResponseWriter = s.ResponseWriters[ctx.ResponseFormat]
|
|
|
|
if ctx.ResponseWriter == nil {
|
|
|
|
ctx.ResponseWriter = s.ResponseWriters["json"]
|
|
|
|
}
|
2017-11-11 04:44:02 +00:00
|
|
|
|
2017-11-21 20:46:30 +00:00
|
|
|
if ctx.QueryFilter == nil {
|
|
|
|
ctx.QueryFilter = s.QueryFilter
|
2017-11-11 04:44:02 +00:00
|
|
|
}
|
|
|
|
|
2017-11-21 20:46:30 +00:00
|
|
|
if ctx.SubContextAttributeProvider == nil {
|
|
|
|
ctx.SubContextAttributeProvider = s.SubContextAttributeProvider
|
|
|
|
}
|
2017-11-11 04:44:02 +00:00
|
|
|
|
2017-11-21 20:46:30 +00:00
|
|
|
ctx.AccessControl = &authorization.AllAccess{}
|
|
|
|
|
|
|
|
return ctx, err
|
2017-11-11 04:44:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) AddSchemas(schemas *types.Schemas) error {
|
|
|
|
if schemas.Err() != nil {
|
|
|
|
return schemas.Err()
|
|
|
|
}
|
|
|
|
|
2017-11-21 20:46:30 +00:00
|
|
|
s.initBuiltin.Do(func() {
|
|
|
|
if s.IgnoreBuiltin {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, schema := range builtin.Schemas.Schemas() {
|
|
|
|
s.setupDefaults(schema)
|
|
|
|
s.schemas.AddSchema(schema)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2017-11-11 04:44:02 +00:00
|
|
|
for _, schema := range schemas.Schemas() {
|
|
|
|
s.setupDefaults(schema)
|
|
|
|
s.schemas.AddSchema(schema)
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.schemas.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) setupDefaults(schema *types.Schema) {
|
|
|
|
if schema.ActionHandler == nil {
|
|
|
|
schema.ActionHandler = s.Defaults.ActionHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
if schema.Store == nil {
|
|
|
|
schema.Store = s.Defaults.Store
|
|
|
|
}
|
|
|
|
|
|
|
|
if schema.ListHandler == nil {
|
|
|
|
schema.ListHandler = s.Defaults.ListHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
if schema.LinkHandler == nil {
|
|
|
|
schema.LinkHandler = s.Defaults.LinkHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
if schema.CreateHandler == nil {
|
|
|
|
schema.CreateHandler = s.Defaults.CreateHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
if schema.UpdateHandler == nil {
|
|
|
|
schema.UpdateHandler = s.Defaults.UpdateHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
if schema.DeleteHandler == nil {
|
|
|
|
schema.DeleteHandler = s.Defaults.DeleteHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
if schema.ErrorHandler == nil {
|
|
|
|
schema.ErrorHandler = s.Defaults.ErrorHandler
|
|
|
|
}
|
2017-11-21 20:46:30 +00:00
|
|
|
|
|
|
|
if schema.Store != nil && s.StoreWrapper != nil {
|
|
|
|
schema.Store = s.StoreWrapper(schema.Store)
|
|
|
|
}
|
2017-11-11 04:44:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
|
|
if apiResponse, err := s.handle(rw, req); err != nil {
|
|
|
|
s.handleError(apiResponse, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) handle(rw http.ResponseWriter, req *http.Request) (*types.APIContext, error) {
|
|
|
|
apiRequest, err := s.Parser(rw, req)
|
|
|
|
if err != nil {
|
|
|
|
return apiRequest, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := CheckCSRF(rw, req); err != nil {
|
|
|
|
return apiRequest, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := addCommonResponseHeader(apiRequest); err != nil {
|
|
|
|
return apiRequest, err
|
|
|
|
}
|
|
|
|
|
|
|
|
action, err := ValidateAction(apiRequest)
|
|
|
|
if err != nil {
|
|
|
|
return apiRequest, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if apiRequest.Schema == nil {
|
|
|
|
return apiRequest, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if action == nil && apiRequest.Type != "" {
|
|
|
|
var handler types.RequestHandler
|
|
|
|
switch apiRequest.Method {
|
|
|
|
case http.MethodGet:
|
|
|
|
handler = apiRequest.Schema.ListHandler
|
|
|
|
case http.MethodPost:
|
|
|
|
handler = apiRequest.Schema.CreateHandler
|
|
|
|
case http.MethodPut:
|
|
|
|
handler = apiRequest.Schema.UpdateHandler
|
|
|
|
case http.MethodDelete:
|
|
|
|
handler = apiRequest.Schema.DeleteHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return apiRequest, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if handler == nil {
|
2017-11-21 20:46:30 +00:00
|
|
|
return apiRequest, httperror.NewAPIError(httperror.NotFound, "")
|
2017-11-11 04:44:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return apiRequest, handler(apiRequest)
|
|
|
|
} else if action != nil {
|
|
|
|
return apiRequest, handleAction(action, apiRequest)
|
|
|
|
}
|
|
|
|
|
|
|
|
return apiRequest, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func handleAction(action *types.Action, request *types.APIContext) error {
|
|
|
|
return request.Schema.ActionHandler(request.Action, action, request)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) handleError(apiRequest *types.APIContext, err error) {
|
|
|
|
if apiRequest.Schema == nil {
|
|
|
|
s.Defaults.ErrorHandler(apiRequest, err)
|
|
|
|
} else if apiRequest.Schema.ErrorHandler != nil {
|
|
|
|
apiRequest.Schema.ErrorHandler(apiRequest, err)
|
|
|
|
}
|
|
|
|
}
|