forked from mirror/gitea
6b33152b7d
Replace #16455 Close #21803 Mixing different Gitea contexts together causes some problems: 1. Unable to respond proper content when error occurs, eg: Web should respond HTML while API should respond JSON 2. Unclear dependency, eg: it's unclear when Context is used in APIContext, which fields should be initialized, which methods are necessary. To make things clear, this PR introduces a Base context, it only provides basic Req/Resp/Data features. This PR mainly moves code. There are still many legacy problems and TODOs in code, leave unrelated changes to future PRs.
78 lines
2.5 KiB
Go
78 lines
2.5 KiB
Go
// Copyright 2020 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package context
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"code.gitea.io/gitea/modules/graceful"
|
|
"code.gitea.io/gitea/modules/process"
|
|
)
|
|
|
|
// PrivateContext represents a context for private routes
|
|
type PrivateContext struct {
|
|
*Base
|
|
Override context.Context
|
|
|
|
Repo *Repository
|
|
}
|
|
|
|
// Deadline is part of the interface for context.Context and we pass this to the request context
|
|
func (ctx *PrivateContext) Deadline() (deadline time.Time, ok bool) {
|
|
if ctx.Override != nil {
|
|
return ctx.Override.Deadline()
|
|
}
|
|
return ctx.Base.Deadline()
|
|
}
|
|
|
|
// Done is part of the interface for context.Context and we pass this to the request context
|
|
func (ctx *PrivateContext) Done() <-chan struct{} {
|
|
if ctx.Override != nil {
|
|
return ctx.Override.Done()
|
|
}
|
|
return ctx.Base.Done()
|
|
}
|
|
|
|
// Err is part of the interface for context.Context and we pass this to the request context
|
|
func (ctx *PrivateContext) Err() error {
|
|
if ctx.Override != nil {
|
|
return ctx.Override.Err()
|
|
}
|
|
return ctx.Base.Err()
|
|
}
|
|
|
|
var privateContextKey interface{} = "default_private_context"
|
|
|
|
// GetPrivateContext returns a context for Private routes
|
|
func GetPrivateContext(req *http.Request) *PrivateContext {
|
|
return req.Context().Value(privateContextKey).(*PrivateContext)
|
|
}
|
|
|
|
// PrivateContexter returns apicontext as middleware
|
|
func PrivateContexter() func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
base, baseCleanUp := NewBaseContext(w, req)
|
|
ctx := &PrivateContext{Base: base}
|
|
defer baseCleanUp()
|
|
ctx.Base.AppendContextValue(privateContextKey, ctx)
|
|
|
|
next.ServeHTTP(ctx.Resp, ctx.Req)
|
|
})
|
|
}
|
|
}
|
|
|
|
// OverrideContext overrides the underlying request context for Done() etc.
|
|
// This function should be used when there is a need for work to continue even if the request has been cancelled.
|
|
// Primarily this affects hook/post-receive and hook/proc-receive both of which need to continue working even if
|
|
// the underlying request has timed out from the ssh/http push
|
|
func OverrideContext(ctx *PrivateContext) (cancel context.CancelFunc) {
|
|
// 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
|
|
ctx.Override, _, cancel = process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), fmt.Sprintf("PrivateContext: %s", ctx.Req.RequestURI), process.RequestProcessType, true)
|
|
return cancel
|
|
}
|