diff options
Diffstat (limited to 'vendor/github.com/99designs/gqlgen/handler')
3 files changed, 65 insertions, 22 deletions
diff --git a/vendor/github.com/99designs/gqlgen/handler/graphql.go b/vendor/github.com/99designs/gqlgen/handler/graphql.go index 7c5f70cf..92a0471c 100644 --- a/vendor/github.com/99designs/gqlgen/handler/graphql.go +++ b/vendor/github.com/99designs/gqlgen/handler/graphql.go @@ -34,6 +34,7 @@ type Config struct { requestHook graphql.RequestMiddleware tracer graphql.Tracer complexityLimit int + complexityLimitFunc graphql.ComplexityLimitFunc disableIntrospection bool connectionKeepAlivePingInterval time.Duration } @@ -60,11 +61,9 @@ func (c *Config) newRequestContext(es graphql.ExecutableSchema, doc *ast.QueryDo if hook := c.tracer; hook != nil { reqCtx.Tracer = hook - } else { - reqCtx.Tracer = &graphql.NopTracer{} } - if c.complexityLimit > 0 { + if c.complexityLimit > 0 || c.complexityLimitFunc != nil { reqCtx.ComplexityLimit = c.complexityLimit operationComplexity := complexity.Calculate(es, op, variables) reqCtx.OperationComplexity = operationComplexity @@ -112,6 +111,15 @@ func ComplexityLimit(limit int) Option { } } +// ComplexityLimitFunc allows you to define a function to dynamically set the maximum query complexity that is allowed +// to be executed. +// If a query is submitted that exceeds the limit, a 422 status code will be returned. +func ComplexityLimitFunc(complexityLimitFunc graphql.ComplexityLimitFunc) Option { + return func(cfg *Config) { + cfg.complexityLimitFunc = complexityLimitFunc + } +} + // ResolverMiddleware allows you to define a function that will be called around every resolver, // useful for logging. func ResolverMiddleware(middleware graphql.FieldMiddleware) Option { @@ -243,19 +251,23 @@ func CacheSize(size int) Option { } } -const DefaultCacheSize = 1000 - -// WebsocketKeepAliveDuration allows you to reconfigure the keepAlive behavior. -// By default, keep-alive is disabled. +// WebsocketKeepAliveDuration allows you to reconfigure the keepalive behavior. +// By default, keepalive is enabled with a DefaultConnectionKeepAlivePingInterval +// duration. Set handler.connectionKeepAlivePingInterval = 0 to disable keepalive +// altogether. func WebsocketKeepAliveDuration(duration time.Duration) Option { return func(cfg *Config) { cfg.connectionKeepAlivePingInterval = duration } } +const DefaultCacheSize = 1000 +const DefaultConnectionKeepAlivePingInterval = 25 * time.Second + func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc { cfg := &Config{ - cacheSize: DefaultCacheSize, + cacheSize: DefaultCacheSize, + connectionKeepAlivePingInterval: DefaultConnectionKeepAlivePingInterval, upgrader: websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, @@ -269,7 +281,7 @@ func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc var cache *lru.Cache if cfg.cacheSize > 0 { var err error - cache, err = lru.New(DefaultCacheSize) + cache, err = lru.New(cfg.cacheSize) if err != nil { // An error is only returned for non-positive cache size // and we already checked for that. @@ -305,10 +317,11 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } if strings.Contains(r.Header.Get("Upgrade"), "websocket") { - connectWs(gh.exec, w, r, gh.cfg) + connectWs(gh.exec, w, r, gh.cfg, gh.cache) return } + w.Header().Set("Content-Type", "application/json") var reqParams params switch r.Method { case http.MethodGet: @@ -330,7 +343,6 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusMethodNotAllowed) return } - w.Header().Set("Content-Type", "application/json") ctx := r.Context() @@ -379,6 +391,10 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } }() + if gh.cfg.complexityLimitFunc != nil { + reqCtx.ComplexityLimit = gh.cfg.complexityLimitFunc(ctx) + } + if reqCtx.ComplexityLimit > 0 && reqCtx.OperationComplexity > reqCtx.ComplexityLimit { sendErrorf(w, http.StatusUnprocessableEntity, "operation has complexity %d, which exceeds the limit of %d", reqCtx.OperationComplexity, reqCtx.ComplexityLimit) return diff --git a/vendor/github.com/99designs/gqlgen/handler/playground.go b/vendor/github.com/99designs/gqlgen/handler/playground.go index f1687def..0e1ca768 100644 --- a/vendor/github.com/99designs/gqlgen/handler/playground.go +++ b/vendor/github.com/99designs/gqlgen/handler/playground.go @@ -11,9 +11,12 @@ var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html> <meta charset=utf-8/> <meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui"> <link rel="shortcut icon" href="https://graphcool-playground.netlify.com/favicon.png"> - <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/css/index.css"/> - <link rel="shortcut icon" href="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/favicon.png"/> - <script src="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/js/middleware.js"></script> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/css/index.css" + integrity="{{ .cssSRI }}" crossorigin="anonymous"/> + <link rel="shortcut icon" href="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/favicon.png" + integrity="{{ .faviconSRI }}" crossorigin="anonymous"/> + <script src="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/js/middleware.js" + integrity="{{ .jsSRI }}" crossorigin="anonymous"></script> <title>{{.title}}</title> </head> <body> @@ -42,10 +45,14 @@ var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html> func Playground(title string, endpoint string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/html") err := page.Execute(w, map[string]string{ - "title": title, - "endpoint": endpoint, - "version": "1.7.8", + "title": title, + "endpoint": endpoint, + "version": "1.7.20", + "cssSRI": "sha256-cS9Vc2OBt9eUf4sykRWukeFYaInL29+myBmFDSa7F/U=", + "faviconSRI": "sha256-GhTyE+McTU79R4+pRO6ih+4TfsTOrpPwD8ReKFzb3PM=", + "jsSRI": "sha256-4QG1Uza2GgGdlBL3RCBCGtGeZB6bDbsw8OltCMGeJsA=", }) if err != nil { panic(err) diff --git a/vendor/github.com/99designs/gqlgen/handler/websocket.go b/vendor/github.com/99designs/gqlgen/handler/websocket.go index 09800c17..58f38e5d 100644 --- a/vendor/github.com/99designs/gqlgen/handler/websocket.go +++ b/vendor/github.com/99designs/gqlgen/handler/websocket.go @@ -12,6 +12,7 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/gorilla/websocket" + "github.com/hashicorp/golang-lru" "github.com/vektah/gqlparser" "github.com/vektah/gqlparser/ast" "github.com/vektah/gqlparser/gqlerror" @@ -44,12 +45,13 @@ type wsConnection struct { active map[string]context.CancelFunc mu sync.Mutex cfg *Config + cache *lru.Cache keepAliveTicker *time.Ticker initPayload InitPayload } -func connectWs(exec graphql.ExecutableSchema, w http.ResponseWriter, r *http.Request, cfg *Config) { +func connectWs(exec graphql.ExecutableSchema, w http.ResponseWriter, r *http.Request, cfg *Config, cache *lru.Cache) { ws, err := cfg.upgrader.Upgrade(w, r, http.Header{ "Sec-Websocket-Protocol": []string{"graphql-ws"}, }) @@ -65,6 +67,7 @@ func connectWs(exec graphql.ExecutableSchema, w http.ResponseWriter, r *http.Req conn: ws, ctx: r.Context(), cfg: cfg, + cache: cache, } if !conn.init() { @@ -176,10 +179,27 @@ func (c *wsConnection) subscribe(message *operationMessage) bool { return false } - doc, qErr := gqlparser.LoadQuery(c.exec.Schema(), reqParams.Query) - if qErr != nil { - c.sendError(message.ID, qErr...) - return true + var ( + doc *ast.QueryDocument + cacheHit bool + ) + if c.cache != nil { + val, ok := c.cache.Get(reqParams.Query) + if ok { + doc = val.(*ast.QueryDocument) + cacheHit = true + } + } + if !cacheHit { + var qErr gqlerror.List + doc, qErr = gqlparser.LoadQuery(c.exec.Schema(), reqParams.Query) + if qErr != nil { + c.sendError(message.ID, qErr...) + return true + } + if c.cache != nil { + c.cache.Add(reqParams.Query, doc) + } } op := doc.Operations.ForName(reqParams.OperationName) |