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  }