code.gitea.io/gitea@v1.19.3/modules/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 ) 15 16 // PrivateContext represents a context for private routes 17 type PrivateContext struct { 18 *Context 19 Override context.Context 20 } 21 22 // Deadline is part of the interface for context.Context and we pass this to the request context 23 func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) { 24 if ctx.Override != nil { 25 return ctx.Override.Deadline() 26 } 27 return ctx.Req.Context().Deadline() 28 } 29 30 // Done is part of the interface for context.Context and we pass this to the request context 31 func (ctx *PrivateContext) Done() <-chan struct{} { 32 if ctx.Override != nil { 33 return ctx.Override.Done() 34 } 35 return ctx.Req.Context().Done() 36 } 37 38 // Err is part of the interface for context.Context and we pass this to the request context 39 func (ctx *PrivateContext) Err() error { 40 if ctx.Override != nil { 41 return ctx.Override.Err() 42 } 43 return ctx.Req.Context().Err() 44 } 45 46 var privateContextKey interface{} = "default_private_context" 47 48 // WithPrivateContext set up private context in request 49 func WithPrivateContext(req *http.Request, ctx *PrivateContext) *http.Request { 50 return req.WithContext(context.WithValue(req.Context(), privateContextKey, ctx)) 51 } 52 53 // GetPrivateContext returns a context for Private routes 54 func GetPrivateContext(req *http.Request) *PrivateContext { 55 return req.Context().Value(privateContextKey).(*PrivateContext) 56 } 57 58 // PrivateContexter returns apicontext as middleware 59 func PrivateContexter() func(http.Handler) http.Handler { 60 return func(next http.Handler) http.Handler { 61 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 62 ctx := &PrivateContext{ 63 Context: &Context{ 64 Resp: NewResponse(w), 65 Data: map[string]interface{}{}, 66 }, 67 } 68 defer ctx.Close() 69 70 ctx.Req = WithPrivateContext(req, ctx) 71 ctx.Data["Context"] = ctx 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 }