From 6df648d018ef4e30ecd26bf5f6018f19babe29e9 Mon Sep 17 00:00:00 2001 From: "Ruddarraju, Uday Kumar Raju" Date: Mon, 11 Apr 2016 19:51:45 -0700 Subject: [PATCH] Updating go-restful dependency to fix thirdparty --- Godeps/Godeps.json | 4 +- .../github.com/emicklei/go-restful/CHANGES.md | 4 ++ .../emicklei/go-restful/compress.go | 13 +++++ .../emicklei/go-restful/cors_filter.go | 6 ++- .../emicklei/go-restful/entity_accessors.go | 20 ++++++-- .../google_app_engine/datastore/main.go | 6 +-- .../google_app_engine/restful-user-service.go | 4 +- .../examples/restful-CORS-filter.go | 1 + .../examples/restful-no-cache-filter.go | 31 +++++++++++ .../github.com/emicklei/go-restful/mime.go | 45 ++++++++++++++++ .../github.com/emicklei/go-restful/request.go | 2 +- .../emicklei/go-restful/response.go | 51 +++++++++++-------- .../go-restful/swagger/model_builder.go | 31 +++++++---- .../emicklei/go-restful/web_service.go | 7 ++- 14 files changed, 180 insertions(+), 45 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/emicklei/go-restful/examples/restful-no-cache-filter.go create mode 100644 Godeps/_workspace/src/github.com/emicklei/go-restful/mime.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 603c01cd1fa..d51bd75db3c 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -492,8 +492,8 @@ }, { "ImportPath": "github.com/emicklei/go-restful", - "Comment": "v1.2", - "Rev": "777bb3f19bcafe2575ffb2a3e46af92509ae9594" + "Comment": "v1.2-34-g496d495", + "Rev": "496d495156da218b9912f03dfa7df7f80fbd8cc3" }, { "ImportPath": "github.com/evanphx/json-patch", diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/CHANGES.md b/Godeps/_workspace/src/github.com/emicklei/go-restful/CHANGES.md index 45bd2012930..070bca7cdc4 100644 --- a/Godeps/_workspace/src/github.com/emicklei/go-restful/CHANGES.md +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/CHANGES.md @@ -1,5 +1,9 @@ Change history of go-restful = +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 + 2015-09-27 - rename new WriteStatusAnd... to WriteHeaderAnd... for consistency diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/compress.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/compress.go index 66f3603e4e2..220b37712f5 100644 --- a/Godeps/_workspace/src/github.com/emicklei/go-restful/compress.go +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/compress.go @@ -5,10 +5,12 @@ package restful // that can be found in the LICENSE file. import ( + "bufio" "compress/gzip" "compress/zlib" "errors" "io" + "net" "net/http" "strings" ) @@ -69,6 +71,17 @@ func (c *CompressingResponseWriter) isCompressorClosed() bool { return nil == c.compressor } +// Hijack implements the Hijacker interface +// This is especially useful when combining Container.EnabledContentEncoding +// in combination with websockets (for instance gorilla/websocket) +func (c *CompressingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + hijacker, ok := c.writer.(http.Hijacker) + if !ok { + return nil, nil, errors.New("ResponseWriter doesn't support Hijacker interface") + } + return hijacker.Hijack() +} + // WantsCompressedResponse reads the Accept-Encoding header to see if and which encoding is requested. func wantsCompressedResponse(httpRequest *http.Request) (bool, string) { header := httpRequest.Header.Get(HEADER_AcceptEncoding) diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/cors_filter.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/cors_filter.go index cd9e7fd291f..cb7fc1934f2 100644 --- a/Godeps/_workspace/src/github.com/emicklei/go-restful/cors_filter.go +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/cors_filter.go @@ -74,7 +74,11 @@ func (c CrossOriginResourceSharing) doActualRequest(req *Request, resp *Response func (c *CrossOriginResourceSharing) doPreflightRequest(req *Request, resp *Response) { if len(c.AllowedMethods) == 0 { - c.AllowedMethods = c.Container.computeAllowedMethods(req) + if c.Container == nil { + c.AllowedMethods = DefaultContainer.computeAllowedMethods(req) + } else { + c.AllowedMethods = c.Container.computeAllowedMethods(req) + } } acrm := req.Request.Header.Get(HEADER_AccessControlRequestMethod) diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/entity_accessors.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/entity_accessors.go index e3ab79d9b12..6ecf6c7f897 100644 --- a/Godeps/_workspace/src/github.com/emicklei/go-restful/entity_accessors.go +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/entity_accessors.go @@ -36,8 +36,8 @@ type entityReaderWriters struct { } func init() { - RegisterEntityAccessor(MIME_JSON, entityJSONAccess{ContentType: MIME_JSON}) - RegisterEntityAccessor(MIME_XML, entityXMLAccess{ContentType: MIME_XML}) + RegisterEntityAccessor(MIME_JSON, NewEntityAccessorJSON(MIME_JSON)) + RegisterEntityAccessor(MIME_XML, NewEntityAccessorXML(MIME_XML)) } // RegisterEntityAccessor add/overrides the ReaderWriter for encoding content with this MIME type. @@ -47,8 +47,20 @@ func RegisterEntityAccessor(mime string, erw EntityReaderWriter) { entityAccessRegistry.accessors[mime] = erw } -// AccessorAt returns the registered ReaderWriter for this MIME type. -func (r *entityReaderWriters) AccessorAt(mime string) (EntityReaderWriter, bool) { +// NewEntityAccessorJSON returns a new EntityReaderWriter for accessing JSON content. +// This package is already initialized with such an accessor using the MIME_JSON contentType. +func NewEntityAccessorJSON(contentType string) EntityReaderWriter { + return entityJSONAccess{ContentType: contentType} +} + +// NewEntityAccessorXML returns a new EntityReaderWriter for accessing XML content. +// This package is already initialized with such an accessor using the MIME_XML contentType. +func NewEntityAccessorXML(contentType string) EntityReaderWriter { + return entityXMLAccess{ContentType: contentType} +} + +// accessorAt returns the registered ReaderWriter for this MIME type. +func (r *entityReaderWriters) accessorAt(mime string) (EntityReaderWriter, bool) { r.protection.RLock() defer r.protection.RUnlock() er, ok := r.accessors[mime] diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/google_app_engine/datastore/main.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/google_app_engine/datastore/main.go index 9f9c78d1fa6..ca290818098 100644 --- a/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/google_app_engine/datastore/main.go +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/google_app_engine/datastore/main.go @@ -3,9 +3,9 @@ package main import ( "github.com/emicklei/go-restful" "github.com/emicklei/go-restful/swagger" - "google.golang.com/appengine" - "google.golang.com/appengine/datastore" - "google.golang.com/appengine/user" + "google.golang.org/appengine" + "google.golang.org/appengine/datastore" + "google.golang.org/appengine/user" "net/http" "time" ) diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/google_app_engine/restful-user-service.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/google_app_engine/restful-user-service.go index 0e883018151..3f38fd6b2f7 100644 --- a/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/google_app_engine/restful-user-service.go +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/google_app_engine/restful-user-service.go @@ -3,8 +3,8 @@ package main import ( "github.com/emicklei/go-restful" "github.com/emicklei/go-restful/swagger" - "google.golang.com/appengine" - "google.golang.com/appengine/memcache" + "google.golang.org/appengine" + "google.golang.org/appengine/memcache" "net/http" ) diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/restful-CORS-filter.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/restful-CORS-filter.go index 346aa1b3751..6419d253817 100644 --- a/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/restful-CORS-filter.go +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/restful-CORS-filter.go @@ -54,6 +54,7 @@ func main() { cors := restful.CrossOriginResourceSharing{ ExposeHeaders: []string{"X-My-Header"}, AllowedHeaders: []string{"Content-Type", "Accept"}, + AllowedMethods: []string{"GET", "POST"}, CookiesAllowed: false, Container: wsContainer} wsContainer.Filter(cors.Filter) diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/restful-no-cache-filter.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/restful-no-cache-filter.go new file mode 100644 index 00000000000..04fae8dce59 --- /dev/null +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/examples/restful-no-cache-filter.go @@ -0,0 +1,31 @@ +package main + +import ( + "io" + "net/http" + + "github.com/emicklei/go-restful" +) + +func NoBrowserCacheFilter(req *restful.Request, resp *restful.Response, chain *restful.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) +} + +// This example shows how to use a WebService filter that passed the Http headers to disable browser cacheing. +// +// GET http://localhost:8080/hello + +func main() { + ws := new(restful.WebService) + ws.Filter(NoBrowserCacheFilter) + ws.Route(ws.GET("/hello").To(hello)) + restful.Add(ws) + http.ListenAndServe(":8080", nil) +} + +func hello(req *restful.Request, resp *restful.Response) { + io.WriteString(resp, "world") +} diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/mime.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/mime.go new file mode 100644 index 00000000000..d7ea2b61579 --- /dev/null +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/mime.go @@ -0,0 +1,45 @@ +package restful + +import ( + "strconv" + "strings" +) + +type mime struct { + media string + quality float64 +} + +// insertMime adds a mime to a list and keeps it sorted by quality. +func insertMime(l []mime, e mime) []mime { + for i, each := range l { + // if current mime has lower quality then insert before + if e.quality > each.quality { + left := append([]mime{}, l[0:i]...) + return append(append(left, e), l[i:]...) + } + } + return append(l, e) +} + +// sortedMimes returns a list of mime sorted (desc) by its specified quality. +func sortedMimes(accept string) (sorted []mime) { + for _, each := range strings.Split(accept, ",") { + typeAndQuality := strings.Split(strings.Trim(each, " "), ";") + if len(typeAndQuality) == 1 { + sorted = insertMime(sorted, mime{typeAndQuality[0], 1.0}) + } else { + // take factor + parts := strings.Split(typeAndQuality[1], "=") + if len(parts) == 2 { + f, err := strconv.ParseFloat(parts[1], 64) + if err != nil { + traceLogger.Printf("unable to parse quality in %s, %v", each, err) + } else { + sorted = insertMime(sorted, mime{typeAndQuality[0], f}) + } + } + } + } + return +} diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/request.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/request.go index 988adc9848f..3e4234697d6 100644 --- a/Godeps/_workspace/src/github.com/emicklei/go-restful/request.go +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/request.go @@ -108,7 +108,7 @@ func (r *Request) ReadEntity(entityPointer interface{}) (err error) { } // lookup the EntityReader - entityReader, ok := entityAccessRegistry.AccessorAt(contentType) + entityReader, ok := entityAccessRegistry.accessorAt(contentType) if !ok { return NewError(http.StatusBadRequest, "Unable to unmarshal content of type:"+contentType) } diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/response.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/response.go index 3798f18c838..696c67eb70c 100644 --- a/Godeps/_workspace/src/github.com/emicklei/go-restful/response.go +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/response.go @@ -7,7 +7,6 @@ package restful import ( "errors" "net/http" - "strings" ) // DEPRECATED, use DefaultResponseContentType(mime) @@ -68,38 +67,39 @@ func (r *Response) SetRequestAccepts(mime string) { // can write according to what the request wants (Accept) and what the Route can produce or what the restful defaults say. // If called before WriteEntity and WriteHeader then a false return value can be used to write a 406: Not Acceptable. func (r *Response) EntityWriter() (EntityReaderWriter, bool) { - for _, qualifiedMime := range strings.Split(r.requestAccept, ",") { - mime := strings.Trim(strings.Split(qualifiedMime, ";")[0], " ") - if 0 == len(mime) || mime == "*/*" { - for _, each := range r.routeProduces { - if MIME_JSON == each { - return entityAccessRegistry.AccessorAt(MIME_JSON) - } - if MIME_XML == each { - return entityAccessRegistry.AccessorAt(MIME_XML) + sorted := sortedMimes(r.requestAccept) + for _, eachAccept := range sorted { + for _, eachProduce := range r.routeProduces { + if eachProduce == eachAccept.media { + if w, ok := entityAccessRegistry.accessorAt(eachAccept.media); ok { + return w, true } } - } else { // mime is not blank; see if we have a match in Produces + } + if eachAccept.media == "*/*" { for _, each := range r.routeProduces { - if mime == each { - if MIME_JSON == each { - return entityAccessRegistry.AccessorAt(MIME_JSON) - } - if MIME_XML == each { - return entityAccessRegistry.AccessorAt(MIME_XML) - } + if w, ok := entityAccessRegistry.accessorAt(each); ok { + return w, true } } } } - writer, ok := entityAccessRegistry.AccessorAt(r.requestAccept) + // if requestAccept is empty + writer, ok := entityAccessRegistry.accessorAt(r.requestAccept) if !ok { // if not registered then fallback to the defaults (if set) if DefaultResponseMimeType == MIME_JSON { - return entityAccessRegistry.AccessorAt(MIME_JSON) + return entityAccessRegistry.accessorAt(MIME_JSON) } if DefaultResponseMimeType == MIME_XML { - return entityAccessRegistry.AccessorAt(MIME_XML) + return entityAccessRegistry.accessorAt(MIME_XML) + } + // Fallback to whatever the route says it can produce. + // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + for _, each := range r.routeProduces { + if w, ok := entityAccessRegistry.accessorAt(each); ok { + return w, true + } } if trace { traceLogger.Printf("no registered EntityReaderWriter found for %s", r.requestAccept) @@ -184,6 +184,15 @@ func (r *Response) WriteErrorString(httpStatus int, errorReason string) error { return nil } +// Flush implements http.Flusher interface, which sends any buffered data to the client. +func (r *Response) Flush() { + if f, ok := r.ResponseWriter.(http.Flusher); ok { + f.Flush() + } else if trace { + traceLogger.Printf("ResponseWriter %v doesn't support Flush", r) + } +} + // WriteHeader is overridden to remember the Status Code that has been written. // Changes to the Header of the response have no effect after this. func (r *Response) WriteHeader(httpStatus int) { diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/model_builder.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/model_builder.go index 3fbb20be26d..fcc2976cb96 100644 --- a/Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/model_builder.go +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/swagger/model_builder.go @@ -178,8 +178,8 @@ func (b modelBuilder) buildProperty(field reflect.StructField, model *Model, mod return jsonName, modelDescription, prop case fieldKind == reflect.Map: // if it's a map, it's unstructured, and swagger 1.2 can't handle it - anyt := "any" - prop.Type = &anyt + objectType := "object" + prop.Type = &objectType return jsonName, modelDescription, prop } @@ -277,9 +277,10 @@ func (b modelBuilder) buildArrayTypeProperty(field reflect.StructField, jsonName fieldType := field.Type var pType = "array" prop.Type = &pType + isPrimitive := b.isPrimitiveType(fieldType.Elem().Name()) elemTypeName := b.getElementTypeName(modelName, jsonName, fieldType.Elem()) prop.Items = new(Item) - if b.isPrimitiveType(elemTypeName) { + if isPrimitive { mapped := b.jsonSchemaType(elemTypeName) prop.Items.Type = &mapped } else { @@ -289,7 +290,9 @@ func (b modelBuilder) buildArrayTypeProperty(field reflect.StructField, jsonName if fieldType.Elem().Kind() == reflect.Ptr { fieldType = fieldType.Elem() } - b.addModel(fieldType.Elem(), elemTypeName) + if !isPrimitive { + b.addModel(fieldType.Elem(), elemTypeName) + } return jsonName, prop } @@ -305,10 +308,18 @@ func (b modelBuilder) buildPointerTypeProperty(field reflect.StructField, jsonNa if fieldType.Elem().Kind() == reflect.Slice || fieldType.Elem().Kind() == reflect.Array { var pType = "array" prop.Type = &pType + isPrimitive := b.isPrimitiveType(fieldType.Elem().Elem().Name()) elemName := b.getElementTypeName(modelName, jsonName, fieldType.Elem().Elem()) - prop.Items = &Item{Ref: &elemName} - // add|overwrite model for element type - b.addModel(fieldType.Elem().Elem(), elemName) + if isPrimitive { + primName := b.jsonSchemaType(elemName) + prop.Items = &Item{Ref: &primName} + } else { + prop.Items = &Item{Ref: &elemName} + } + if !isPrimitive { + // add|overwrite model for element type + b.addModel(fieldType.Elem().Elem(), elemName) + } } else { // non-array, pointer type var pType = b.jsonSchemaType(fieldType.String()[1:]) // no star, include pkg path @@ -335,9 +346,6 @@ func (b modelBuilder) getElementTypeName(modelName, jsonName string, t reflect.T if t.Name() == "" { return modelName + "." + jsonName } - if b.isPrimitiveType(t.Name()) { - return b.jsonSchemaType(t.Name()) - } return b.keyFrom(t) } @@ -352,6 +360,9 @@ func (b modelBuilder) keyFrom(st reflect.Type) string { // see also https://golang.org/ref/spec#Numeric_types func (b modelBuilder) isPrimitiveType(modelName string) bool { + if len(modelName) == 0 { + return false + } return strings.Contains("uint uint8 uint16 uint32 uint64 int int8 int16 int32 int64 float32 float64 bool string byte rune time.Time", modelName) } diff --git a/Godeps/_workspace/src/github.com/emicklei/go-restful/web_service.go b/Godeps/_workspace/src/github.com/emicklei/go-restful/web_service.go index e89be70097c..70708e4bd0e 100644 --- a/Godeps/_workspace/src/github.com/emicklei/go-restful/web_service.go +++ b/Godeps/_workspace/src/github.com/emicklei/go-restful/web_service.go @@ -159,11 +159,16 @@ func (w *WebService) RemoveRoute(path, method string) error { } w.routesLock.Lock() defer w.routesLock.Unlock() + newRoutes := make([]Route, (len(w.routes) - 1)) + current := 0 for ix := range w.routes { if w.routes[ix].Method == method && w.routes[ix].Path == path { - w.routes = append(w.routes[:ix], w.routes[ix+1:]...) + continue } + newRoutes[current] = w.routes[ix] + current = current + 1 } + w.routes = newRoutes return nil }