package util import ( "context" "mime" "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" "go.uber.org/zap/zapcore" ) // Header Keys const ( // ContextKey is used as key to set/get context. ContextKey = "context" // ContentTypeJSON : json ContentTypeJSON = "application/json" // ContentTypeOctetStream: octet stream ContentTypeOctetStream = "application/octet-stream" // HeaderTraceID is header name for trace id. HeaderTraceID = "x-fc-trace-id" HeaderContentType = "content-Type" HeaderContentLength = "content-Length" // HeaderClientIP is the real IP of the remote client HeaderClientIP = "clientIP" ) // ContextKeyType defining the context key type for the middleware type ContextKeyType string const ( // ServiceLogFields shared key service log fields ServiceLogFields ContextKeyType = "ServiceLogFields" // HeaderRequestID is used as key to set/get request id. HeaderRequestID ContextKeyType = "x-fc-request-id" ) // RESTful API paths const ( RootPath = "/api" EnvironmentPath = "/envs" ApplicationPath = "/apps" WorkloadDefinitionPath = "/workloads" ScopeDefinitionPath = "/scopes" TraitDefinitionPath = "/traits" CapabilityPath = "/capabilities" CapabilityCenterPath = "/capability-centers" VersionPath = "/version" Definition = "/definitions" ) // NoRoute is a handler which is invoked when there is no route matches. func NoRoute() gin.HandlerFunc { return func(c *gin.Context) { SetErrorAndAbort(c, PathNotSupported, c.Request.Method, c.Request.URL.Path) } } // generateRequestID :Get request id func generateRequestID() string { id, _ := uuid.NewV4() return id.String() } // SetRequestID ... func SetRequestID() gin.HandlerFunc { return func(c *gin.Context) { requestID := "" traceID := "" if traceID = c.Request.Header.Get(HeaderTraceID); traceID != "" { requestID = traceID } else if requestID = c.Request.Header.Get(string(HeaderRequestID)); requestID != "" { traceID = requestID } else { requestID = generateRequestID() traceID = requestID } c.Set(string(HeaderRequestID), requestID) c.Set(HeaderClientIP, c.ClientIP()) c.Set(HeaderTraceID, traceID) } } // SetContext :Set context metadata for request // Before get request func SetContext() gin.HandlerFunc { return func(c *gin.Context) { reqID := c.MustGet(string(HeaderRequestID)).(string) ctx, cancel := context.WithCancel(c.Request.Context()) fields := make(map[string]zapcore.Field) mctx := context.WithValue(ctx, ServiceLogFields, fields) fctx := context.WithValue(mctx, HeaderRequestID, reqID) c.Set(ContextKey, fctx) c.Next() cancel() } } // GetContext get the context from the gin context func GetContext(c *gin.Context) context.Context { return c.MustGet(ContextKey).(context.Context) } // ValidateHeaders validates the common headers. // // It reports one problem at a time. func ValidateHeaders() gin.HandlerFunc { return func(c *gin.Context) { // It's ok to not specify Content-Type header, but it should be correct if it's specified. contentType := c.Request.Header.Get(HeaderContentType) if len(contentType) != 0 { mType, _, err := mime.ParseMediaType(contentType) if err != nil { SetErrorAndAbort(c, UnsupportedMediaType) return } switch mType { case ContentTypeJSON, ContentTypeOctetStream: // Passes. default: SetErrorAndAbort(c, UnsupportedMediaType) return } } } }