You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

private.go 2.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package context
  5. import (
  6. "context"
  7. "fmt"
  8. "net/http"
  9. "time"
  10. "code.gitea.io/gitea/modules/graceful"
  11. "code.gitea.io/gitea/modules/process"
  12. )
  13. // PrivateContext represents a context for private routes
  14. type PrivateContext struct {
  15. *Context
  16. Override context.Context
  17. }
  18. // Deadline is part of the interface for context.Context and we pass this to the request context
  19. func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) {
  20. if ctx.Override != nil {
  21. return ctx.Override.Deadline()
  22. }
  23. return ctx.Req.Context().Deadline()
  24. }
  25. // Done is part of the interface for context.Context and we pass this to the request context
  26. func (ctx *PrivateContext) Done() <-chan struct{} {
  27. if ctx.Override != nil {
  28. return ctx.Override.Done()
  29. }
  30. return ctx.Req.Context().Done()
  31. }
  32. // Err is part of the interface for context.Context and we pass this to the request context
  33. func (ctx *PrivateContext) Err() error {
  34. if ctx.Override != nil {
  35. return ctx.Override.Err()
  36. }
  37. return ctx.Req.Context().Err()
  38. }
  39. var privateContextKey interface{} = "default_private_context"
  40. // WithPrivateContext set up private context in request
  41. func WithPrivateContext(req *http.Request, ctx *PrivateContext) *http.Request {
  42. return req.WithContext(context.WithValue(req.Context(), privateContextKey, ctx))
  43. }
  44. // GetPrivateContext returns a context for Private routes
  45. func GetPrivateContext(req *http.Request) *PrivateContext {
  46. return req.Context().Value(privateContextKey).(*PrivateContext)
  47. }
  48. // PrivateContexter returns apicontext as middleware
  49. func PrivateContexter() func(http.Handler) http.Handler {
  50. return func(next http.Handler) http.Handler {
  51. return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  52. ctx := &PrivateContext{
  53. Context: &Context{
  54. Resp: NewResponse(w),
  55. Data: map[string]interface{}{},
  56. },
  57. }
  58. defer ctx.Close()
  59. ctx.Req = WithPrivateContext(req, ctx)
  60. ctx.Data["Context"] = ctx
  61. next.ServeHTTP(ctx.Resp, ctx.Req)
  62. })
  63. }
  64. }
  65. // OverrideContext overrides the underlying request context for Done() etc.
  66. // This function should be used when there is a need for work to continue even if the request has been cancelled.
  67. // Primarily this affects hook/post-receive and hook/proc-receive both of which need to continue working even if
  68. // the underlying request has timed out from the ssh/http push
  69. func OverrideContext(ctx *PrivateContext) (cancel context.CancelFunc) {
  70. // 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
  71. ctx.Override, _, cancel = process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), fmt.Sprintf("PrivateContext: %s", ctx.Req.RequestURI), process.RequestProcessType, true)
  72. return cancel
  73. }