// Copyright 2014 Manu Martinez-Almeida. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package gin import ( "encoding/xml" "net/http" "os" "path" "reflect" "runtime" "strconv" "strings" ) // BindKey indicates a default bind key. const BindKey = "_gin-gonic/gin/bindkey" // Bind is a helper function for given interface object and returns a Gin middleware. func Bind(val interface{}) HandlerFunc { value := reflect.ValueOf(val) if value.Kind() == reflect.Ptr { panic(`Bind struct can not be a pointer. Example: Use: gin.Bind(Struct{}) instead of gin.Bind(&Struct{}) `) } typ := value.Type() return func(c *Context) { obj := reflect.New(typ).Interface() if c.Bind(obj) == nil { c.Set(BindKey, obj) } } } // WrapF is a helper function for wrapping http.HandlerFunc and returns a Gin middleware. func WrapF(f http.HandlerFunc) HandlerFunc { return func(c *Context) { f(c.Writer, c.Request) } } // WrapH is a helper function for wrapping http.Handler and returns a Gin middleware. func WrapH(h http.Handler) HandlerFunc { return func(c *Context) { h.ServeHTTP(c.Writer, c.Request) } } // H is a shortcut for map[string]interface{} type H map[string]interface{} // MarshalXML allows type H to be used with xml.Marshal. func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error { start.Name = xml.Name{ Space: "", Local: "map", } if err := e.EncodeToken(start); err != nil { return err } for key, value := range h { elem := xml.StartElement{ Name: xml.Name{Space: "", Local: key}, Attr: []xml.Attr{}, } if err := e.EncodeElement(value, elem); err != nil { return err } } return e.EncodeToken(xml.EndElement{Name: start.Name}) } func assert1(guard bool, text string) { if !guard { panic(text) } } func filterFlags(content string) string { for i, char := range content { if char == ' ' || char == ';' { return content[:i] } } return content } func chooseData(custom, wildcard interface{}) interface{} { if custom == nil { if wildcard == nil { panic("negotiation config is invalid") } return wildcard } return custom } func parseAccept(acceptHeader string) []string { parts := strings.Split(acceptHeader, ",") out := make([]string, 0, len(parts)) for _, part := range parts { if part = strings.TrimSpace(strings.Split(part, ";")[0]); part != "" { out = append(out, part) } } return out } func lastChar(str string) uint8 { if str == "" { panic("The length of the string can't be 0") } return str[len(str)-1] } func nameOfFunction(f interface{}) string { return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() } func joinPaths(absolutePath, relativePath string) string { if relativePath == "" { return absolutePath } finalPath := path.Join(absolutePath, relativePath) appendSlash := lastChar(relativePath) == '/' && lastChar(finalPath) != '/' if appendSlash { return finalPath + "/" } return finalPath } func resolveAddress(addr []string) string { switch len(addr) { case 0: if port := os.Getenv("PORT"); port != "" { if isValidPORTEnvVar(port) { debugPrint("Environment variable PORT=\"%s\"", port) return ":" + port } } debugPrint("Environment variable PORT is undefined or invalid. Using port :8080 by default") return ":8080" case 1: return addr[0] default: panic("too many parameters") } } // Determine the PORT environment variable whether is valid。 // If the PORT can be parsed to uint(0-65535),return true。 func isValidPORTEnvVar(portString string) bool { _, err := strconv.ParseUint(portString, 10, 16) return err == nil }