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",
|
"ImportPath": "github.com/emicklei/go-restful",
|
||||||
"Comment": "v1.2-79-g89ef8af",
|
"Comment": "v1.2-96-g09691a3",
|
||||||
"Rev": "89ef8af493ab468a45a42bb0d89a06fccdd2fb22"
|
"Rev": "09691a3b6378b740595c1002f40c34dd5f218a22"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/emicklei/go-restful/log",
|
"ImportPath": "github.com/emicklei/go-restful/log",
|
||||||
"Comment": "v1.2-79-g89ef8af",
|
"Comment": "v1.2-96-g09691a3",
|
||||||
"Rev": "89ef8af493ab468a45a42bb0d89a06fccdd2fb22"
|
"Rev": "09691a3b6378b740595c1002f40c34dd5f218a22"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/emicklei/go-restful/swagger",
|
"ImportPath": "github.com/emicklei/go-restful/swagger",
|
||||||
"Comment": "v1.2-79-g89ef8af",
|
"Comment": "v1.2-96-g09691a3",
|
||||||
"Rev": "89ef8af493ab468a45a42bb0d89a06fccdd2fb22"
|
"Rev": "09691a3b6378b740595c1002f40c34dd5f218a22"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/evanphx/json-patch",
|
"ImportPath": "github.com/evanphx/json-patch",
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
Change history of go-restful
|
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
|
2016-02-14
|
||||||
- take the qualify factor of the Accept header mediatype into account when deciding the contentype of the response
|
- 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
|
- add constructors for custom entity accessors for xml and json
|
||||||
|
|
|
@ -25,10 +25,10 @@ type Container struct {
|
||||||
ServeMux *http.ServeMux
|
ServeMux *http.ServeMux
|
||||||
isRegisteredOnRoot bool
|
isRegisteredOnRoot bool
|
||||||
containerFilters []FilterFunction
|
containerFilters []FilterFunction
|
||||||
doNotRecover bool // default is false
|
doNotRecover bool // default is true
|
||||||
recoverHandleFunc RecoverHandleFunction
|
recoverHandleFunc RecoverHandleFunction
|
||||||
serviceErrorHandleFunc ServiceErrorHandleFunction
|
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
|
contentEncodingEnabled bool // default is false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,10 +39,10 @@ func NewContainer() *Container {
|
||||||
ServeMux: http.NewServeMux(),
|
ServeMux: http.NewServeMux(),
|
||||||
isRegisteredOnRoot: false,
|
isRegisteredOnRoot: false,
|
||||||
containerFilters: []FilterFunction{},
|
containerFilters: []FilterFunction{},
|
||||||
doNotRecover: false,
|
doNotRecover: true,
|
||||||
recoverHandleFunc: logStackOnRecover,
|
recoverHandleFunc: logStackOnRecover,
|
||||||
serviceErrorHandleFunc: writeServiceError,
|
serviceErrorHandleFunc: writeServiceError,
|
||||||
router: RouterJSR311{},
|
router: CurlyRouter{},
|
||||||
contentEncodingEnabled: false}
|
contentEncodingEnabled: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ func (c *Container) ServiceErrorHandler(handler ServiceErrorHandleFunction) {
|
||||||
|
|
||||||
// DoNotRecover controls whether panics will be caught to return HTTP 500.
|
// DoNotRecover controls whether panics will be caught to return HTTP 500.
|
||||||
// If set to true, Route functions are responsible for handling any error situation.
|
// 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) {
|
func (c *Container) DoNotRecover(doNot bool) {
|
||||||
c.doNotRecover = doNot
|
c.doNotRecover = doNot
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,11 +108,13 @@ func (c CurlyRouter) regularMatchesPathToken(routeToken string, colon int, reque
|
||||||
return (matched && err == nil), false
|
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
|
// 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
|
// headers of the Request. See also RouterJSR311 in jsr311.go
|
||||||
func (c CurlyRouter) detectRoute(candidateRoutes sortableCurlyRoutes, httpRequest *http.Request) (*Route, error) {
|
func (c CurlyRouter) detectRoute(candidateRoutes sortableCurlyRoutes, httpRequest *http.Request) (*Route, error) {
|
||||||
// tracing is done inside detectRoute
|
// 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.
|
// 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.
|
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{})
|
restful.DefaultContainer.DoNotRecover(false)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
DoNotRecover controls whether panics will be caught to return HTTP 500.
|
DoNotRecover controls whether panics will be caught to return HTTP 500.
|
||||||
If set to true, Route functions are responsible for handling any error situation.
|
If set to false, the container will recover from panics.
|
||||||
Default value is false; it will recover from panics. This has performance implications.
|
Default value is true
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
restful.SetCompressorProvider(NewBoundedCachedCompressors(20, 20))
|
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
|
// FilterFunction definitions must call ProcessFilter on the FilterChain to pass on the control and eventually call the RouteFunction
|
||||||
type FilterFunction func(*Request, *Response, *FilterChain)
|
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 defaultRequestContentType string
|
||||||
|
|
||||||
var doCacheReadEntityBytes = true
|
var doCacheReadEntityBytes = false
|
||||||
|
|
||||||
// Request is a wrapper for a http Request that provides convenience methods
|
// Request is a wrapper for a http Request that provides convenience methods
|
||||||
type Request struct {
|
type Request struct {
|
||||||
|
@ -107,10 +107,15 @@ func (r *Request) ReadEntity(entityPointer interface{}) (err error) {
|
||||||
r.Request.Body = zlibReader
|
r.Request.Body = zlibReader
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookup the EntityReader
|
// lookup the EntityReader, use defaultRequestContentType if needed and provided
|
||||||
entityReader, ok := entityAccessRegistry.accessorAt(contentType)
|
entityReader, ok := entityAccessRegistry.accessorAt(contentType)
|
||||||
if !ok {
|
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)
|
return entityReader.Read(r, entityPointer)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package swagger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
)
|
)
|
||||||
|
@ -9,8 +10,13 @@ import (
|
||||||
// PostBuildDeclarationMapFunc can be used to modify the api declaration map.
|
// PostBuildDeclarationMapFunc can be used to modify the api declaration map.
|
||||||
type PostBuildDeclarationMapFunc func(apiDeclarationMap *ApiDeclarationList)
|
type PostBuildDeclarationMapFunc func(apiDeclarationMap *ApiDeclarationList)
|
||||||
|
|
||||||
|
// MapSchemaFormatFunc can be used to modify typeName at definition time.
|
||||||
type MapSchemaFormatFunc func(typeName string) string
|
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 {
|
type Config struct {
|
||||||
// url where the services are available, e.g. http://localhost:8080
|
// 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
|
// if left empty then the basePath of Swagger is taken from the actual request
|
||||||
|
@ -33,6 +39,8 @@ type Config struct {
|
||||||
PostBuildHandler PostBuildDeclarationMapFunc
|
PostBuildHandler PostBuildDeclarationMapFunc
|
||||||
// Swagger global info struct
|
// Swagger global info struct
|
||||||
Info Info
|
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
|
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 {
|
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)
|
modelName := b.keyFrom(st)
|
||||||
if nameOverride != "" {
|
if nameOverride != "" {
|
||||||
modelName = nameOverride
|
modelName = nameOverride
|
||||||
|
@ -137,6 +143,11 @@ func (b modelBuilder) buildProperty(field reflect.StructField, model *Model, mod
|
||||||
return "", "", prop
|
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 != "" {
|
if tag := field.Tag.Get("modelDescription"); tag != "" {
|
||||||
modelDescription = tag
|
modelDescription = tag
|
||||||
}
|
}
|
||||||
|
@ -155,7 +166,7 @@ func (b modelBuilder) buildProperty(field reflect.StructField, model *Model, mod
|
||||||
prop.Type = &pType
|
prop.Type = &pType
|
||||||
}
|
}
|
||||||
if prop.Format == "" {
|
if prop.Format == "" {
|
||||||
prop.Format = b.jsonSchemaFormat(fieldType.String())
|
prop.Format = b.jsonSchemaFormat(b.keyFrom(fieldType))
|
||||||
}
|
}
|
||||||
return jsonName, modelDescription, prop
|
return jsonName, modelDescription, prop
|
||||||
}
|
}
|
||||||
|
@ -192,13 +203,14 @@ func (b modelBuilder) buildProperty(field reflect.StructField, model *Model, mod
|
||||||
return jsonName, modelDescription, prop
|
return jsonName, modelDescription, prop
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.isPrimitiveType(fieldType.String()) {
|
fieldTypeName := b.keyFrom(fieldType)
|
||||||
mapped := b.jsonSchemaType(fieldType.String())
|
if b.isPrimitiveType(fieldTypeName) {
|
||||||
|
mapped := b.jsonSchemaType(fieldTypeName)
|
||||||
prop.Type = &mapped
|
prop.Type = &mapped
|
||||||
prop.Format = b.jsonSchemaFormat(fieldType.String())
|
prop.Format = b.jsonSchemaFormat(fieldTypeName)
|
||||||
return jsonName, modelDescription, prop
|
return jsonName, modelDescription, prop
|
||||||
}
|
}
|
||||||
modelType := fieldType.String()
|
modelType := b.keyFrom(fieldType)
|
||||||
prop.Ref = &modelType
|
prop.Ref = &modelType
|
||||||
|
|
||||||
if fieldType.Name() == "" { // override type of anonymous structs
|
if fieldType.Name() == "" { // override type of anonymous structs
|
||||||
|
@ -272,7 +284,7 @@ func (b modelBuilder) buildStructTypeProperty(field reflect.StructField, jsonNam
|
||||||
}
|
}
|
||||||
// simple struct
|
// simple struct
|
||||||
b.addModel(fieldType, "")
|
b.addModel(fieldType, "")
|
||||||
var pType = fieldType.String()
|
var pType = b.keyFrom(fieldType)
|
||||||
prop.Ref = &pType
|
prop.Ref = &pType
|
||||||
return jsonName, prop
|
return jsonName, prop
|
||||||
}
|
}
|
||||||
|
@ -336,10 +348,11 @@ func (b modelBuilder) buildPointerTypeProperty(field reflect.StructField, jsonNa
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// non-array, pointer type
|
// non-array, pointer type
|
||||||
var pType = b.jsonSchemaType(fieldType.String()[1:]) // no star, include pkg path
|
fieldTypeName := b.keyFrom(fieldType.Elem())
|
||||||
if b.isPrimitiveType(fieldType.String()[1:]) {
|
var pType = b.jsonSchemaType(fieldTypeName) // no star, include pkg path
|
||||||
|
if b.isPrimitiveType(fieldTypeName) {
|
||||||
prop.Type = &pType
|
prop.Type = &pType
|
||||||
prop.Format = b.jsonSchemaFormat(fieldType.String()[1:])
|
prop.Format = b.jsonSchemaFormat(fieldTypeName)
|
||||||
return jsonName, prop
|
return jsonName, prop
|
||||||
}
|
}
|
||||||
prop.Ref = &pType
|
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 {
|
func (b modelBuilder) getElementTypeName(modelName, jsonName string, t reflect.Type) string {
|
||||||
if t.Kind() == reflect.Ptr {
|
if t.Kind() == reflect.Ptr {
|
||||||
return t.String()[1:]
|
t = t.Elem()
|
||||||
}
|
}
|
||||||
if t.Name() == "" {
|
if t.Name() == "" {
|
||||||
return modelName + "." + jsonName
|
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 {
|
func (b modelBuilder) keyFrom(st reflect.Type) string {
|
||||||
key := st.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
|
if len(st.Name()) == 0 { // unnamed type
|
||||||
// Swagger UI has special meaning for [
|
// Swagger UI has special meaning for [
|
||||||
key = strings.Replace(key, "[]", "||", -1)
|
key = strings.Replace(key, "[]", "||", -1)
|
||||||
|
|
|
@ -33,6 +33,21 @@ func (prop *ModelProperty) setMaximum(field reflect.StructField) {
|
||||||
|
|
||||||
func (prop *ModelProperty) setType(field reflect.StructField) {
|
func (prop *ModelProperty) setType(field reflect.StructField) {
|
||||||
if tag := field.Tag.Get("type"); tag != "" {
|
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
|
prop.Type = &tag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -277,7 +277,7 @@ func composeResponseMessages(route restful.Route, decl *ApiDeclaration, config *
|
||||||
}
|
}
|
||||||
// sort by code
|
// sort by code
|
||||||
codes := sort.IntSlice{}
|
codes := sort.IntSlice{}
|
||||||
for code, _ := range route.ResponseErrors {
|
for code := range route.ResponseErrors {
|
||||||
codes = append(codes, code)
|
codes = append(codes, code)
|
||||||
}
|
}
|
||||||
codes.Sort()
|
codes.Sort()
|
||||||
|
|
Loading…
Reference in New Issue