code.gitea.io/gitea@v1.22.3/services/context/private.go (about) 1 // Copyright 2020 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package context 5 6 import ( 7 "context" 8 "fmt" 9 "net/http" 10 "time" 11 12 "code.gitea.io/gitea/modules/graceful" 13 "code.gitea.io/gitea/modules/process" 14 "code.gitea.io/gitea/modules/web" 15 web_types "code.gitea.io/gitea/modules/web/types" 16 ) 17 18 // PrivateContext represents a context for private routes 19 type PrivateContext struct { 20 *Base 21 Override context.Context 22 23 Repo *Repository 24 } 25 26 func init() { 27 web.RegisterResponseStatusProvider[*PrivateContext](func(req *http.Request) web_types.ResponseStatusProvider { 28 return req.Context().Value(privateContextKey).(*PrivateContext) 29 }) 30 } 31 32 // Deadline is part of the interface for context.Context and we pass this to the request context 33 func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) { 34 if ctx.Override != nil { 35 return ctx.Override.Deadline() 36 } 37 return ctx.Base.Deadline() 38 } 39 40 // Done is part of the interface for context.Context and we pass this to the request context 41 func (ctx *PrivateContext) Done() <-chan struct{} { 42 if ctx.Override != nil { 43 return ctx.Override.Done() 44 } 45 return ctx.Base.Done() 46 } 47 48 // Err is part of the interface for context.Context and we pass this to the request context 49 func (ctx *PrivateContext) Err() error { 50 if ctx.Override != nil { 51 return ctx.Override.Err() 52 } 53 return ctx.Base.Err() 54 } 55 56 var privateContextKey any = "default_private_context" 57 58 // GetPrivateContext returns a context for Private routes 59 func GetPrivateContext(req *http.Request) *PrivateContext { 60 return req.Context().Value(privateContextKey).(*PrivateContext) 61 } 62 63 // PrivateContexter returns apicontext as middleware 64 func PrivateContexter() func(http.Handler) http.Handler { 65 return func(next http.Handler) http.Handler { 66 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 67 base, baseCleanUp := NewBaseContext(w, req) 68 ctx := &PrivateContext{Base: base} 69 defer baseCleanUp() 70 ctx.Base.AppendContextValue(privateContextKey, ctx) 71 72 next.ServeHTTP(ctx.Resp, ctx.Req) 73 }) 74 } 75 } 76 77 // OverrideContext overrides the underlying request context for Done() etc. 78 // This function should be used when there is a need for work to continue even if the request has been cancelled. 79 // Primarily this affects hook/post-receive and hook/proc-receive both of which need to continue working even if 80 // the underlying request has timed out from the ssh/http push 81 func OverrideContext(ctx *PrivateContext) (cancel context.CancelFunc) { 82 // 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 83 ctx.Override, _, cancel = process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), fmt.Sprintf("PrivateContext: %s", ctx.Req.RequestURI), process.RequestProcessType, true) 84 return cancel 85 }