mirror of https://github.com/k3s-io/k3s
Merge pull request #38625 from smarterclayton/bump_gorestful
Automatic merge from submit-queue Update to latest go-restful Enables us to remap the variable names swagger uses in output so we can avoid duplicates across type names. Part of #38071 @mbohloolpull/6/head
commit
9407bc5bbe
|
@ -897,18 +897,18 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/emicklei/go-restful",
|
||||
"Comment": "v1.2-79-g89ef8af",
|
||||
"Rev": "89ef8af493ab468a45a42bb0d89a06fccdd2fb22"
|
||||
"Comment": "v1.2-96-g09691a3",
|
||||
"Rev": "09691a3b6378b740595c1002f40c34dd5f218a22"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/emicklei/go-restful/log",
|
||||
"Comment": "v1.2-79-g89ef8af",
|
||||
"Rev": "89ef8af493ab468a45a42bb0d89a06fccdd2fb22"
|
||||
"Comment": "v1.2-96-g09691a3",
|
||||
"Rev": "09691a3b6378b740595c1002f40c34dd5f218a22"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/emicklei/go-restful/swagger",
|
||||
"Comment": "v1.2-79-g89ef8af",
|
||||
"Rev": "89ef8af493ab468a45a42bb0d89a06fccdd2fb22"
|
||||
"Comment": "v1.2-96-g09691a3",
|
||||
"Rev": "09691a3b6378b740595c1002f40c34dd5f218a22"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/evanphx/json-patch",
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
Change history of go-restful
|
||||
=
|
||||
2016-11-26
|
||||
- Default change! now use CurlyRouter (was RouterJSR311)
|
||||
- Default change! no more caching of request content
|
||||
- Default change! do not recover from panics
|
||||
|
||||
2016-09-22
|
||||
- fix the DefaultRequestContentType feature
|
||||
|
||||
2016-02-14
|
||||
- take the qualify factor of the Accept header mediatype into account when deciding the contentype of the response
|
||||
- add constructors for custom entity accessors for xml and json
|
||||
|
|
|
@ -25,10 +25,10 @@ type Container struct {
|
|||
ServeMux *http.ServeMux
|
||||
isRegisteredOnRoot bool
|
||||
containerFilters []FilterFunction
|
||||
doNotRecover bool // default is false
|
||||
doNotRecover bool // default is true
|
||||
recoverHandleFunc RecoverHandleFunction
|
||||
serviceErrorHandleFunc ServiceErrorHandleFunction
|
||||
router RouteSelector // default is a RouterJSR311, CurlyRouter is the faster alternative
|
||||
router RouteSelector // default is a CurlyRouter (RouterJSR311 is a slower alternative)
|
||||
contentEncodingEnabled bool // default is false
|
||||
}
|
||||
|
||||
|
@ -39,10 +39,10 @@ func NewContainer() *Container {
|
|||
ServeMux: http.NewServeMux(),
|
||||
isRegisteredOnRoot: false,
|
||||
containerFilters: []FilterFunction{},
|
||||
doNotRecover: false,
|
||||
doNotRecover: true,
|
||||
recoverHandleFunc: logStackOnRecover,
|
||||
serviceErrorHandleFunc: writeServiceError,
|
||||
router: RouterJSR311{},
|
||||
router: CurlyRouter{},
|
||||
contentEncodingEnabled: false}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ func (c *Container) ServiceErrorHandler(handler ServiceErrorHandleFunction) {
|
|||
|
||||
// DoNotRecover controls whether panics will be caught to return HTTP 500.
|
||||
// If set to true, Route functions are responsible for handling any error situation.
|
||||
// Default value is false = recover from panics. This has performance implications.
|
||||
// Default value is true.
|
||||
func (c *Container) DoNotRecover(doNot bool) {
|
||||
c.doNotRecover = doNot
|
||||
}
|
||||
|
|
|
@ -108,11 +108,13 @@ func (c CurlyRouter) regularMatchesPathToken(routeToken string, colon int, reque
|
|||
return (matched && err == nil), false
|
||||
}
|
||||
|
||||
var jsr311Router = RouterJSR311{}
|
||||
|
||||
// detectRoute selectes from a list of Route the first match by inspecting both the Accept and Content-Type
|
||||
// headers of the Request. See also RouterJSR311 in jsr311.go
|
||||
func (c CurlyRouter) detectRoute(candidateRoutes sortableCurlyRoutes, httpRequest *http.Request) (*Route, error) {
|
||||
// tracing is done inside detectRoute
|
||||
return RouterJSR311{}.detectRoute(candidateRoutes.routes(), httpRequest)
|
||||
return jsr311Router.detectRoute(candidateRoutes.routes(), httpRequest)
|
||||
}
|
||||
|
||||
// detectWebService returns the best matching webService given the list of path tokens.
|
||||
|
|
|
@ -145,22 +145,11 @@ Performance options
|
|||
|
||||
This package has several options that affect the performance of your service. It is important to understand them and how you can change it.
|
||||
|
||||
restful.DefaultContainer.Router(CurlyRouter{})
|
||||
|
||||
The default router is the RouterJSR311 which is an implementation of its spec (http://jsr311.java.net/nonav/releases/1.1/spec/spec.html).
|
||||
However, it uses regular expressions for all its routes which, depending on your usecase, may consume a significant amount of time.
|
||||
The CurlyRouter implementation is more lightweight that also allows you to use wildcards and expressions, but only if needed.
|
||||
|
||||
restful.DefaultContainer.DoNotRecover(true)
|
||||
restful.DefaultContainer.DoNotRecover(false)
|
||||
|
||||
DoNotRecover controls whether panics will be caught to return HTTP 500.
|
||||
If set to true, Route functions are responsible for handling any error situation.
|
||||
Default value is false; it will recover from panics. This has performance implications.
|
||||
|
||||
restful.SetCacheReadEntity(false)
|
||||
|
||||
SetCacheReadEntity controls whether the response data ([]byte) is cached such that ReadEntity is repeatable.
|
||||
If you expect to read large amounts of payload data, and you do not use this feature, you should set it to false.
|
||||
If set to false, the container will recover from panics.
|
||||
Default value is true
|
||||
|
||||
restful.SetCompressorProvider(NewBoundedCachedCompressors(20, 20))
|
||||
|
||||
|
|
|
@ -24,3 +24,12 @@ func (f *FilterChain) ProcessFilter(request *Request, response *Response) {
|
|||
|
||||
// FilterFunction definitions must call ProcessFilter on the FilterChain to pass on the control and eventually call the RouteFunction
|
||||
type FilterFunction func(*Request, *Response, *FilterChain)
|
||||
|
||||
// NoBrowserCacheFilter is a filter function to set HTTP headers that disable browser caching
|
||||
// See examples/restful-no-cache-filter.go for usage
|
||||
func NoBrowserCacheFilter(req *Request, resp *Response, chain *FilterChain) {
|
||||
resp.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // HTTP 1.1.
|
||||
resp.Header().Set("Pragma", "no-cache") // HTTP 1.0.
|
||||
resp.Header().Set("Expires", "0") // Proxies.
|
||||
chain.ProcessFilter(req, resp)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
var defaultRequestContentType string
|
||||
|
||||
var doCacheReadEntityBytes = true
|
||||
var doCacheReadEntityBytes = false
|
||||
|
||||
// Request is a wrapper for a http Request that provides convenience methods
|
||||
type Request struct {
|
||||
|
@ -107,10 +107,15 @@ func (r *Request) ReadEntity(entityPointer interface{}) (err error) {
|
|||
r.Request.Body = zlibReader
|
||||
}
|
||||
|
||||
// lookup the EntityReader
|
||||
// lookup the EntityReader, use defaultRequestContentType if needed and provided
|
||||
entityReader, ok := entityAccessRegistry.accessorAt(contentType)
|
||||
if !ok {
|
||||
return NewError(http.StatusBadRequest, "Unable to unmarshal content of type:"+contentType)
|
||||
if len(defaultRequestContentType) != 0 {
|
||||
entityReader, ok = entityAccessRegistry.accessorAt(defaultRequestContentType)
|
||||
}
|
||||
if !ok {
|
||||
return NewError(http.StatusBadRequest, "Unable to unmarshal content of type:"+contentType)
|
||||
}
|
||||
}
|
||||
return entityReader.Read(r, entityPointer)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package swagger
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
)
|
||||
|
@ -9,8 +10,13 @@ import (
|
|||
// PostBuildDeclarationMapFunc can be used to modify the api declaration map.
|
||||
type PostBuildDeclarationMapFunc func(apiDeclarationMap *ApiDeclarationList)
|
||||
|
||||
// MapSchemaFormatFunc can be used to modify typeName at definition time.
|
||||
type MapSchemaFormatFunc func(typeName string) string
|
||||
|
||||
// MapModelTypeNameFunc can be used to return the desired typeName for a given
|
||||
// type. It will return false if the default name should be used.
|
||||
type MapModelTypeNameFunc func(t reflect.Type) (string, bool)
|
||||
|
||||
type Config struct {
|
||||
// url where the services are available, e.g. http://localhost:8080
|
||||
// if left empty then the basePath of Swagger is taken from the actual request
|
||||
|
@ -33,6 +39,8 @@ type Config struct {
|
|||
PostBuildHandler PostBuildDeclarationMapFunc
|
||||
// Swagger global info struct
|
||||
Info Info
|
||||
// [optional] If set, model builder should call this handler to get addition typename-to-swagger-format-field convertion.
|
||||
// [optional] If set, model builder should call this handler to get addition typename-to-swagger-format-field conversion.
|
||||
SchemaFormatHandler MapSchemaFormatFunc
|
||||
// [optional] If set, model builder should call this handler to retrieve the name for a given type.
|
||||
ModelTypeNameHandler MapModelTypeNameFunc
|
||||
}
|
||||
|
|
|
@ -43,6 +43,12 @@ func (b modelBuilder) addModelFrom(sample interface{}) {
|
|||
}
|
||||
|
||||
func (b modelBuilder) addModel(st reflect.Type, nameOverride string) *Model {
|
||||
// Turn pointers into simpler types so further checks are
|
||||
// correct.
|
||||
if st.Kind() == reflect.Ptr {
|
||||
st = st.Elem()
|
||||
}
|
||||
|
||||
modelName := b.keyFrom(st)
|
||||
if nameOverride != "" {
|
||||
modelName = nameOverride
|
||||
|
@ -137,6 +143,11 @@ func (b modelBuilder) buildProperty(field reflect.StructField, model *Model, mod
|
|||
return "", "", prop
|
||||
}
|
||||
|
||||
if field.Name == "XMLName" && field.Type.String() == "xml.Name" {
|
||||
// property is metadata for the xml.Name attribute, can be skipped
|
||||
return "", "", prop
|
||||
}
|
||||
|
||||
if tag := field.Tag.Get("modelDescription"); tag != "" {
|
||||
modelDescription = tag
|
||||
}
|
||||
|
@ -155,7 +166,7 @@ func (b modelBuilder) buildProperty(field reflect.StructField, model *Model, mod
|
|||
prop.Type = &pType
|
||||
}
|
||||
if prop.Format == "" {
|
||||
prop.Format = b.jsonSchemaFormat(fieldType.String())
|
||||
prop.Format = b.jsonSchemaFormat(b.keyFrom(fieldType))
|
||||
}
|
||||
return jsonName, modelDescription, prop
|
||||
}
|
||||
|
@ -192,13 +203,14 @@ func (b modelBuilder) buildProperty(field reflect.StructField, model *Model, mod
|
|||
return jsonName, modelDescription, prop
|
||||
}
|
||||
|
||||
if b.isPrimitiveType(fieldType.String()) {
|
||||
mapped := b.jsonSchemaType(fieldType.String())
|
||||
fieldTypeName := b.keyFrom(fieldType)
|
||||
if b.isPrimitiveType(fieldTypeName) {
|
||||
mapped := b.jsonSchemaType(fieldTypeName)
|
||||
prop.Type = &mapped
|
||||
prop.Format = b.jsonSchemaFormat(fieldType.String())
|
||||
prop.Format = b.jsonSchemaFormat(fieldTypeName)
|
||||
return jsonName, modelDescription, prop
|
||||
}
|
||||
modelType := fieldType.String()
|
||||
modelType := b.keyFrom(fieldType)
|
||||
prop.Ref = &modelType
|
||||
|
||||
if fieldType.Name() == "" { // override type of anonymous structs
|
||||
|
@ -272,7 +284,7 @@ func (b modelBuilder) buildStructTypeProperty(field reflect.StructField, jsonNam
|
|||
}
|
||||
// simple struct
|
||||
b.addModel(fieldType, "")
|
||||
var pType = fieldType.String()
|
||||
var pType = b.keyFrom(fieldType)
|
||||
prop.Ref = &pType
|
||||
return jsonName, prop
|
||||
}
|
||||
|
@ -336,10 +348,11 @@ func (b modelBuilder) buildPointerTypeProperty(field reflect.StructField, jsonNa
|
|||
}
|
||||
} else {
|
||||
// non-array, pointer type
|
||||
var pType = b.jsonSchemaType(fieldType.String()[1:]) // no star, include pkg path
|
||||
if b.isPrimitiveType(fieldType.String()[1:]) {
|
||||
fieldTypeName := b.keyFrom(fieldType.Elem())
|
||||
var pType = b.jsonSchemaType(fieldTypeName) // no star, include pkg path
|
||||
if b.isPrimitiveType(fieldTypeName) {
|
||||
prop.Type = &pType
|
||||
prop.Format = b.jsonSchemaFormat(fieldType.String()[1:])
|
||||
prop.Format = b.jsonSchemaFormat(fieldTypeName)
|
||||
return jsonName, prop
|
||||
}
|
||||
prop.Ref = &pType
|
||||
|
@ -355,7 +368,7 @@ func (b modelBuilder) buildPointerTypeProperty(field reflect.StructField, jsonNa
|
|||
|
||||
func (b modelBuilder) getElementTypeName(modelName, jsonName string, t reflect.Type) string {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
return t.String()[1:]
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Name() == "" {
|
||||
return modelName + "." + jsonName
|
||||
|
@ -365,6 +378,11 @@ func (b modelBuilder) getElementTypeName(modelName, jsonName string, t reflect.T
|
|||
|
||||
func (b modelBuilder) keyFrom(st reflect.Type) string {
|
||||
key := st.String()
|
||||
if b.Config != nil && b.Config.ModelTypeNameHandler != nil {
|
||||
if name, ok := b.Config.ModelTypeNameHandler(st); ok {
|
||||
key = name
|
||||
}
|
||||
}
|
||||
if len(st.Name()) == 0 { // unnamed type
|
||||
// Swagger UI has special meaning for [
|
||||
key = strings.Replace(key, "[]", "||", -1)
|
||||
|
|
|
@ -33,6 +33,21 @@ func (prop *ModelProperty) setMaximum(field reflect.StructField) {
|
|||
|
||||
func (prop *ModelProperty) setType(field reflect.StructField) {
|
||||
if tag := field.Tag.Get("type"); tag != "" {
|
||||
// Check if the first two characters of the type tag are
|
||||
// intended to emulate slice/array behaviour.
|
||||
//
|
||||
// If type is intended to be a slice/array then add the
|
||||
// overriden type to the array item instead of the main property
|
||||
if len(tag) > 2 && tag[0:2] == "[]" {
|
||||
pType := "array"
|
||||
prop.Type = &pType
|
||||
prop.Items = new(Item)
|
||||
|
||||
iType := tag[2:]
|
||||
prop.Items.Type = &iType
|
||||
return
|
||||
}
|
||||
|
||||
prop.Type = &tag
|
||||
}
|
||||
}
|
||||
|
|
|
@ -277,7 +277,7 @@ func composeResponseMessages(route restful.Route, decl *ApiDeclaration, config *
|
|||
}
|
||||
// sort by code
|
||||
codes := sort.IntSlice{}
|
||||
for code, _ := range route.ResponseErrors {
|
||||
for code := range route.ResponseErrors {
|
||||
codes = append(codes, code)
|
||||
}
|
||||
codes.Sort()
|
||||
|
|
Loading…
Reference in New Issue