diff options
Diffstat (limited to 'services/context/private.go')
-rw-r--r-- | services/context/private.go | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/services/context/private.go b/services/context/private.go new file mode 100644 index 0000000..8b41949 --- /dev/null +++ b/services/context/private.go @@ -0,0 +1,85 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package context + +import ( + "context" + "fmt" + "net/http" + "time" + + "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/web" + web_types "code.gitea.io/gitea/modules/web/types" +) + +// PrivateContext represents a context for private routes +type PrivateContext struct { + *Base + Override context.Context + + Repo *Repository +} + +func init() { + web.RegisterResponseStatusProvider[*PrivateContext](func(req *http.Request) web_types.ResponseStatusProvider { + return req.Context().Value(privateContextKey).(*PrivateContext) + }) +} + +// Deadline is part of the interface for context.Context and we pass this to the request context +func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) { + if ctx.Override != nil { + return ctx.Override.Deadline() + } + return ctx.Base.Deadline() +} + +// Done is part of the interface for context.Context and we pass this to the request context +func (ctx *PrivateContext) Done() <-chan struct{} { + if ctx.Override != nil { + return ctx.Override.Done() + } + return ctx.Base.Done() +} + +// Err is part of the interface for context.Context and we pass this to the request context +func (ctx *PrivateContext) Err() error { + if ctx.Override != nil { + return ctx.Override.Err() + } + return ctx.Base.Err() +} + +var privateContextKey any = "default_private_context" + +// GetPrivateContext returns a context for Private routes +func GetPrivateContext(req *http.Request) *PrivateContext { + return req.Context().Value(privateContextKey).(*PrivateContext) +} + +// PrivateContexter returns apicontext as middleware +func PrivateContexter() func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + base, baseCleanUp := NewBaseContext(w, req) + ctx := &PrivateContext{Base: base} + defer baseCleanUp() + ctx.Base.AppendContextValue(privateContextKey, ctx) + + next.ServeHTTP(ctx.Resp, ctx.Req) + }) + } +} + +// OverrideContext overrides the underlying request context for Done() etc. +// This function should be used when there is a need for work to continue even if the request has been cancelled. +// Primarily this affects hook/post-receive and hook/proc-receive both of which need to continue working even if +// the underlying request has timed out from the ssh/http push +func OverrideContext(ctx *PrivateContext) (cancel context.CancelFunc) { + // We now need to override the request context as the base for our work because even if the request is cancelled we have to continue this work + ctx.Override, _, cancel = process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), fmt.Sprintf("PrivateContext: %s", ctx.Req.RequestURI), process.RequestProcessType, true) + return cancel +} |