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.8KB

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