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  }