diff --git a/cmd/web.go b/cmd/web.go index da6c987ff..3a46b9091 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -191,7 +191,7 @@ func runWeb(ctx *cli.Context) error { } // Set up Chi routes - c := routers.NormalRoutes(graceful.GetManager().HammerContext()) + c := routers.NormalRoutes() err := listen(c, true) <-graceful.GetManager().Done() log.Info("PID: %d Gitea Web Finished", os.Getpid()) diff --git a/modules/context/api.go b/modules/context/api.go index 092ad73f3..3c4d02041 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -20,6 +20,8 @@ import ( "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/web" + web_types "code.gitea.io/gitea/modules/web/types" "gitea.com/go-chi/cache" ) @@ -41,6 +43,12 @@ type APIContext struct { Package *Package } +func init() { + web.RegisterResponseStatusProvider[*APIContext](func(req *http.Request) web_types.ResponseStatusProvider { + return req.Context().Value(apiContextKey).(*APIContext) + }) +} + // Currently, we have the following common fields in error response: // * message: the message for end users (it shouldn't be used for error type detection) // if we need to indicate some errors, we should introduce some new fields like ErrorCode or ErrorType diff --git a/modules/context/base.go b/modules/context/base.go index c8238050f..45f33feb0 100644 --- a/modules/context/base.go +++ b/modules/context/base.go @@ -96,7 +96,11 @@ func (b *Base) SetTotalCountHeader(total int64) { // Written returns true if there are something sent to web browser func (b *Base) Written() bool { - return b.Resp.Status() > 0 + return b.Resp.WrittenStatus() != 0 +} + +func (b *Base) WrittenStatus() int { + return b.Resp.WrittenStatus() } // Status writes status code diff --git a/modules/context/context.go b/modules/context/context.go index 9e351432c..93d448fca 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -21,7 +21,9 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" + web_types "code.gitea.io/gitea/modules/web/types" "gitea.com/go-chi/cache" "gitea.com/go-chi/session" @@ -58,6 +60,12 @@ type Context struct { Package *Package } +func init() { + web.RegisterResponseStatusProvider[*Context](func(req *http.Request) web_types.ResponseStatusProvider { + return req.Context().Value(WebContextKey).(*Context) + }) +} + // TrHTMLEscapeArgs runs ".Locale.Tr()" but pre-escapes all arguments with html.EscapeString. // This is useful if the locale message is intended to only produce HTML content. func (ctx *Context) TrHTMLEscapeArgs(msg string, args ...string) string { diff --git a/modules/context/private.go b/modules/context/private.go index 41ca8a470..2e9b31140 100644 --- a/modules/context/private.go +++ b/modules/context/private.go @@ -11,6 +11,8 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/web" + web_types "code.gitea.io/gitea/modules/web/types" ) // PrivateContext represents a context for private routes @@ -21,6 +23,12 @@ type PrivateContext struct { Repo *Repository } +func init() { + web.RegisterResponseStatusProvider[*PrivateContext](func(req *http.Request) web_types.ResponseStatusProvider { + return req.Context().Value(privateContextKey).(*PrivateContext) + }) +} + // 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 { diff --git a/modules/context/response.go b/modules/context/response.go index 8708d77da..2f271f211 100644 --- a/modules/context/response.go +++ b/modules/context/response.go @@ -5,15 +5,20 @@ package context import ( "net/http" + + web_types "code.gitea.io/gitea/modules/web/types" ) // ResponseWriter represents a response writer for HTTP type ResponseWriter interface { http.ResponseWriter http.Flusher - Status() int + web_types.ResponseStatusProvider + Before(func(ResponseWriter)) - Size() int // used by access logger template + + Status() int // used by access logger template + Size() int // used by access logger template } var _ ResponseWriter = &Response{} @@ -46,6 +51,10 @@ func (r *Response) Write(bs []byte) (int, error) { return size, nil } +func (r *Response) Status() int { + return r.status +} + func (r *Response) Size() int { return r.written } @@ -71,8 +80,8 @@ func (r *Response) Flush() { } } -// Status returned status code written -func (r *Response) Status() int { +// WrittenStatus returned status code written +func (r *Response) WrittenStatus() int { return r.status } diff --git a/modules/test/context_tests.go b/modules/test/context_tests.go index 349c7e3e8..cf8af32fc 100644 --- a/modules/test/context_tests.go +++ b/modules/test/context_tests.go @@ -9,6 +9,7 @@ import ( "net/http" "net/http/httptest" "net/url" + "strings" "testing" access_model "code.gitea.io/gitea/models/perm/access" @@ -25,19 +26,26 @@ import ( "github.com/stretchr/testify/assert" ) -// MockContext mock context for unit tests -// TODO: move this function to other packages, because it depends on "models" package -func MockContext(t *testing.T, path string) *context.Context { - resp := httptest.NewRecorder() +func mockRequest(t *testing.T, reqPath string) *http.Request { + method, path, found := strings.Cut(reqPath, " ") + if !found { + method = "GET" + path = reqPath + } requestURL, err := url.Parse(path) assert.NoError(t, err) - req := &http.Request{ - URL: requestURL, - Form: url.Values{}, - } + req := &http.Request{Method: method, URL: requestURL, Form: url.Values{}} + req = req.WithContext(middleware.WithContextData(req.Context())) + return req +} +// MockContext mock context for unit tests +// TODO: move this function to other packages, because it depends on "models" package +func MockContext(t *testing.T, reqPath string) (*context.Context, *httptest.ResponseRecorder) { + resp := httptest.NewRecorder() + req := mockRequest(t, reqPath) base, baseCleanUp := context.NewBaseContext(resp, req) - base.Data = middleware.ContextData{} + base.Data = middleware.GetContextData(req.Context()) base.Locale = &translation.MockLocale{} ctx := &context.Context{ Base: base, @@ -48,29 +56,23 @@ func MockContext(t *testing.T, path string) *context.Context { chiCtx := chi.NewRouteContext() ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) - return ctx + return ctx, resp } // MockAPIContext mock context for unit tests // TODO: move this function to other packages, because it depends on "models" package -func MockAPIContext(t *testing.T, path string) *context.APIContext { +func MockAPIContext(t *testing.T, reqPath string) (*context.APIContext, *httptest.ResponseRecorder) { resp := httptest.NewRecorder() - requestURL, err := url.Parse(path) - assert.NoError(t, err) - req := &http.Request{ - URL: requestURL, - Form: url.Values{}, - } - + req := mockRequest(t, reqPath) base, baseCleanUp := context.NewBaseContext(resp, req) - base.Data = middleware.ContextData{} + base.Data = middleware.GetContextData(req.Context()) base.Locale = &translation.MockLocale{} ctx := &context.APIContext{Base: base} _ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later chiCtx := chi.NewRouteContext() ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) - return ctx + return ctx, resp } // LoadRepo load a repo into a test context. diff --git a/modules/web/handler.go b/modules/web/handler.go index c8aebd905..26b742801 100644 --- a/modules/web/handler.go +++ b/modules/web/handler.go @@ -9,25 +9,15 @@ import ( "net/http" "reflect" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/web/routing" + "code.gitea.io/gitea/modules/web/types" ) -// ResponseStatusProvider is an interface to check whether the response has been written by the handler -type ResponseStatusProvider interface { - Written() bool -} +var responseStatusProviders = map[reflect.Type]func(req *http.Request) types.ResponseStatusProvider{} -// TODO: decouple this from the context package, let the context package register these providers -var argTypeProvider = map[reflect.Type]func(req *http.Request) ResponseStatusProvider{ - reflect.TypeOf(&context.APIContext{}): func(req *http.Request) ResponseStatusProvider { return context.GetAPIContext(req) }, - reflect.TypeOf(&context.Context{}): func(req *http.Request) ResponseStatusProvider { return context.GetWebContext(req) }, - reflect.TypeOf(&context.PrivateContext{}): func(req *http.Request) ResponseStatusProvider { return context.GetPrivateContext(req) }, -} - -func RegisterHandleTypeProvider[T any](fn func(req *http.Request) ResponseStatusProvider) { - argTypeProvider[reflect.TypeOf((*T)(nil)).Elem()] = fn +func RegisterResponseStatusProvider[T any](fn func(req *http.Request) types.ResponseStatusProvider) { + responseStatusProviders[reflect.TypeOf((*T)(nil)).Elem()] = fn } // responseWriter is a wrapper of http.ResponseWriter, to check whether the response has been written @@ -36,10 +26,10 @@ type responseWriter struct { status int } -var _ ResponseStatusProvider = (*responseWriter)(nil) +var _ types.ResponseStatusProvider = (*responseWriter)(nil) -func (r *responseWriter) Written() bool { - return r.status > 0 +func (r *responseWriter) WrittenStatus() int { + return r.status } func (r *responseWriter) Header() http.Header { @@ -68,7 +58,7 @@ var ( func preCheckHandler(fn reflect.Value, argsIn []reflect.Value) { hasStatusProvider := false for _, argIn := range argsIn { - if _, hasStatusProvider = argIn.Interface().(ResponseStatusProvider); hasStatusProvider { + if _, hasStatusProvider = argIn.Interface().(types.ResponseStatusProvider); hasStatusProvider { break } } @@ -101,7 +91,7 @@ func prepareHandleArgsIn(resp http.ResponseWriter, req *http.Request, fn reflect case httpReqType: argsIn[i] = reflect.ValueOf(req) default: - if argFn, ok := argTypeProvider[argTyp]; ok { + if argFn, ok := responseStatusProviders[argTyp]; ok { if isPreCheck { argsIn[i] = reflect.ValueOf(&responseWriter{}) } else { @@ -129,8 +119,8 @@ func handleResponse(fn reflect.Value, ret []reflect.Value) goctx.CancelFunc { func hasResponseBeenWritten(argsIn []reflect.Value) bool { for _, argIn := range argsIn { - if statusProvider, ok := argIn.Interface().(ResponseStatusProvider); ok { - if statusProvider.Written() { + if statusProvider, ok := argIn.Interface().(types.ResponseStatusProvider); ok { + if statusProvider.WrittenStatus() != 0 { return true } } @@ -161,7 +151,7 @@ func toHandlerProvider(handler any) func(next http.Handler) http.Handler { return http.HandlerFunc(func(respOrig http.ResponseWriter, req *http.Request) { // wrap the response writer to check whether the response has been written resp := respOrig - if _, ok := resp.(ResponseStatusProvider); !ok { + if _, ok := resp.(types.ResponseStatusProvider); !ok { resp = &responseWriter{respWriter: resp} } diff --git a/modules/web/middleware/data.go b/modules/web/middleware/data.go index c1f0516d7..9497dc02e 100644 --- a/modules/web/middleware/data.go +++ b/modules/web/middleware/data.go @@ -17,7 +17,7 @@ type ContextDataStore interface { type ContextData map[string]any -func (ds ContextData) GetData() map[string]any { +func (ds ContextData) GetData() ContextData { return ds } diff --git a/modules/web/route.go b/modules/web/route.go index d801f1025..db511aeb1 100644 --- a/modules/web/route.go +++ b/modules/web/route.go @@ -7,31 +7,31 @@ import ( "net/http" "strings" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/web/middleware" "gitea.com/go-chi/binding" - chi "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5" ) -// Bind binding an obj to a handler -func Bind[T any](_ T) any { - return func(ctx *context.Context) { +// Bind binding an obj to a handler's context data +func Bind[T any](_ T) http.HandlerFunc { + return func(resp http.ResponseWriter, req *http.Request) { theObj := new(T) // create a new form obj for every request but not use obj directly - binding.Bind(ctx.Req, theObj) - SetForm(ctx, theObj) - middleware.AssignForm(theObj, ctx.Data) + data := middleware.GetContextData(req.Context()) + binding.Bind(req, theObj) + SetForm(data, theObj) + middleware.AssignForm(theObj, data) } } // SetForm set the form object -func SetForm(data middleware.ContextDataStore, obj interface{}) { - data.GetData()["__form"] = obj +func SetForm(dataStore middleware.ContextDataStore, obj interface{}) { + dataStore.GetData()["__form"] = obj } // GetForm returns the validate form information -func GetForm(data middleware.ContextDataStore) interface{} { - return data.GetData()["__form"] +func GetForm(dataStore middleware.ContextDataStore) interface{} { + return dataStore.GetData()["__form"] } // Route defines a route based on chi's router diff --git a/modules/web/routing/logger.go b/modules/web/routing/logger.go index b58065aa7..6a4dae66f 100644 --- a/modules/web/routing/logger.go +++ b/modules/web/routing/logger.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/web/types" ) // NewLoggerHandler is a handler that will log routing to the router log taking account of @@ -86,8 +86,8 @@ func logPrinter(logger log.Logger) func(trigger Event, record *requestRecord) { } var status int - if v, ok := record.responseWriter.(context.ResponseWriter); ok { - status = v.Status() + if v, ok := record.responseWriter.(types.ResponseStatusProvider); ok { + status = v.WrittenStatus() } logf := log.Info if strings.HasPrefix(req.RequestURI, "/assets/") { diff --git a/modules/web/types/response.go b/modules/web/types/response.go new file mode 100644 index 000000000..834f4912f --- /dev/null +++ b/modules/web/types/response.go @@ -0,0 +1,10 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package types + +// ResponseStatusProvider is an interface to get the written status in the response +// Many packages need this interface, so put it in the separate package to avoid import cycle +type ResponseStatusProvider interface { + WrittenStatus() int +} diff --git a/routers/api/actions/actions.go b/routers/api/actions/actions.go index bdcac4120..a418b3a1c 100644 --- a/routers/api/actions/actions.go +++ b/routers/api/actions/actions.go @@ -4,7 +4,6 @@ package actions import ( - "context" "net/http" "code.gitea.io/gitea/modules/web" @@ -12,7 +11,7 @@ import ( "code.gitea.io/gitea/routers/api/actions/runner" ) -func Routes(_ context.Context, prefix string) *web.Route { +func Routes(prefix string) *web.Route { m := web.NewRoute() path, handler := ping.NewPingServiceHandler() diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go index 4b10cd7ad..060f7bc3d 100644 --- a/routers/api/actions/artifacts.go +++ b/routers/api/actions/artifacts.go @@ -82,6 +82,7 @@ import ( "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + web_types "code.gitea.io/gitea/modules/web/types" ) const ( @@ -102,7 +103,7 @@ type ArtifactContext struct { } func init() { - web.RegisterHandleTypeProvider[*ArtifactContext](func(req *http.Request) web.ResponseStatusProvider { + web.RegisterResponseStatusProvider[*ArtifactContext](func(req *http.Request) web_types.ResponseStatusProvider { return req.Context().Value(artifactContextKey).(*ArtifactContext) }) } diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 4f0f637fa..fa7f66f3a 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -4,7 +4,6 @@ package packages import ( - gocontext "context" "net/http" "regexp" "strings" @@ -96,7 +95,7 @@ func verifyAuth(r *web.Route, authMethods []auth.Method) { // CommonRoutes provide endpoints for most package managers (except containers - see below) // These are mounted on `/api/packages` (not `/api/v1/packages`) -func CommonRoutes(ctx gocontext.Context) *web.Route { +func CommonRoutes() *web.Route { r := web.NewRoute() r.Use(context.PackageContexter()) @@ -590,7 +589,7 @@ func CommonRoutes(ctx gocontext.Context) *web.Route { // ContainerRoutes provides endpoints that implement the OCI API to serve containers // These have to be mounted on `/v2/...` to comply with the OCI spec: // https://github.com/opencontainers/distribution-spec/blob/main/spec.md -func ContainerRoutes(ctx gocontext.Context) *web.Route { +func ContainerRoutes() *web.Route { r := web.NewRoute() r.Use(context.PackageContexter()) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 37361a8b9..be66cc524 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -64,7 +64,6 @@ package v1 import ( - gocontext "context" "fmt" "net/http" "strings" @@ -705,7 +704,7 @@ func buildAuthGroup() *auth.Group { } // Routes registers all v1 APIs routes to web application. -func Routes(ctx gocontext.Context) *web.Route { +func Routes() *web.Route { m := web.NewRoute() m.Use(securityHeaders()) @@ -722,13 +721,8 @@ func Routes(ctx gocontext.Context) *web.Route { } m.Use(context.APIContexter()) - group := buildAuthGroup() - if err := group.Init(ctx); err != nil { - log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err) - } - // Get user from session if logged in. - m.Use(auth.APIAuth(group)) + m.Use(auth.APIAuth(buildAuthGroup())) m.Use(auth.VerifyAuthWithOptionsAPI(&auth.VerifyOptions{ SignInRequired: setting.Service.RequireSignInView, diff --git a/routers/api/v1/misc/markup_test.go b/routers/api/v1/misc/markup_test.go index fdf540fd6..bab06b3e6 100644 --- a/routers/api/v1/misc/markup_test.go +++ b/routers/api/v1/misc/markup_test.go @@ -7,18 +7,14 @@ import ( go_context "context" "io" "net/http" - "net/http/httptest" - "net/url" "strings" "testing" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/web" - "code.gitea.io/gitea/modules/web/middleware" "github.com/stretchr/testify/assert" ) @@ -29,34 +25,16 @@ const ( AppSubURL = AppURL + Repo + "/" ) -func createAPIContext(req *http.Request) (*context.APIContext, *httptest.ResponseRecorder) { - resp := httptest.NewRecorder() - base, baseCleanUp := context.NewBaseContext(resp, req) - base.Data = middleware.ContextData{} - c := &context.APIContext{Base: base} - _ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later - - return c, resp -} - func testRenderMarkup(t *testing.T, mode, filePath, text, responseBody string, responseCode int) { setting.AppURL = AppURL - options := api.MarkupOption{ Mode: mode, - Text: "", + Text: text, Context: Repo, Wiki: true, FilePath: filePath, } - requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markup")) - req := &http.Request{ - Method: "POST", - URL: requrl, - } - ctx, resp := createAPIContext(req) - - options.Text = text + ctx, resp := test.MockAPIContext(t, "POST /api/v1/markup") web.SetForm(ctx, &options) Markup(ctx) assert.Equal(t, responseBody, resp.Body.String()) @@ -66,21 +44,13 @@ func testRenderMarkup(t *testing.T, mode, filePath, text, responseBody string, r func testRenderMarkdown(t *testing.T, mode, text, responseBody string, responseCode int) { setting.AppURL = AppURL - options := api.MarkdownOption{ Mode: mode, - Text: "", + Text: text, Context: Repo, Wiki: true, } - requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) - req := &http.Request{ - Method: "POST", - URL: requrl, - } - ctx, resp := createAPIContext(req) - - options.Text = text + ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") web.SetForm(ctx, &options) Markdown(ctx) assert.Equal(t, responseBody, resp.Body.String()) @@ -187,19 +157,12 @@ var simpleCases = []string{ func TestAPI_RenderSimple(t *testing.T) { setting.AppURL = AppURL - options := api.MarkdownOption{ Mode: "markdown", Text: "", Context: Repo, } - requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) - req := &http.Request{ - Method: "POST", - URL: requrl, - } - ctx, resp := createAPIContext(req) - + ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") for i := 0; i < len(simpleCases); i += 2 { options.Text = simpleCases[i] web.SetForm(ctx, &options) @@ -211,14 +174,7 @@ func TestAPI_RenderSimple(t *testing.T) { func TestAPI_RenderRaw(t *testing.T) { setting.AppURL = AppURL - - requrl, _ := url.Parse(util.URLJoin(AppURL, "api", "v1", "markdown")) - req := &http.Request{ - Method: "POST", - URL: requrl, - } - ctx, resp := createAPIContext(req) - + ctx, resp := test.MockAPIContext(t, "POST /api/v1/markdown") for i := 0; i < len(simpleCases); i += 2 { ctx.Req.Body = io.NopCloser(strings.NewReader(simpleCases[i])) MarkdownRaw(ctx) diff --git a/routers/api/v1/repo/hook_test.go b/routers/api/v1/repo/hook_test.go index 56658b45d..b43a22cd5 100644 --- a/routers/api/v1/repo/hook_test.go +++ b/routers/api/v1/repo/hook_test.go @@ -17,7 +17,7 @@ import ( func TestTestHook(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockAPIContext(t, "user2/repo1/wiki/_pages") + ctx, _ := test.MockAPIContext(t, "user2/repo1/wiki/_pages") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) diff --git a/routers/api/v1/repo/repo_test.go b/routers/api/v1/repo/repo_test.go index e1bdea5c8..7593a87c2 100644 --- a/routers/api/v1/repo/repo_test.go +++ b/routers/api/v1/repo/repo_test.go @@ -19,7 +19,7 @@ import ( func TestRepoEdit(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockAPIContext(t, "user2/repo1") + ctx, _ := test.MockAPIContext(t, "user2/repo1") test.LoadRepo(t, ctx, 1) test.LoadUser(t, ctx, 2) ctx.Repo.Owner = ctx.Doer @@ -65,7 +65,7 @@ func TestRepoEdit(t *testing.T) { func TestRepoEditNameChange(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockAPIContext(t, "user2/repo1") + ctx, _ := test.MockAPIContext(t, "user2/repo1") test.LoadRepo(t, ctx, 1) test.LoadUser(t, ctx, 2) ctx.Repo.Owner = ctx.Doer diff --git a/routers/init.go b/routers/init.go index 725e5c52b..54e8d2b8b 100644 --- a/routers/init.go +++ b/routers/init.go @@ -174,27 +174,27 @@ func GlobalInitInstalled(ctx context.Context) { } // NormalRoutes represents non install routes -func NormalRoutes(ctx context.Context) *web.Route { +func NormalRoutes() *web.Route { _ = templates.HTMLRenderer() r := web.NewRoute() r.Use(common.ProtocolMiddlewares()...) - r.Mount("/", web_routers.Routes(ctx)) - r.Mount("/api/v1", apiv1.Routes(ctx)) + r.Mount("/", web_routers.Routes()) + r.Mount("/api/v1", apiv1.Routes()) r.Mount("/api/internal", private.Routes()) r.Post("/-/fetch-redirect", common.FetchRedirectDelegate) if setting.Packages.Enabled { // This implements package support for most package managers - r.Mount("/api/packages", packages_router.CommonRoutes(ctx)) + r.Mount("/api/packages", packages_router.CommonRoutes()) // This implements the OCI API (Note this is not preceded by /api but is instead /v2) - r.Mount("/v2", packages_router.ContainerRoutes(ctx)) + r.Mount("/v2", packages_router.ContainerRoutes()) } if setting.Actions.Enabled { prefix := "/api/actions" - r.Mount(prefix, actions_router.Routes(ctx, prefix)) + r.Mount(prefix, actions_router.Routes(prefix)) // TODO: Pipeline api used for runner internal communication with gitea server. but only artifact is used for now. // In Github, it uses ACTIONS_RUNTIME_URL=https://pipelines.actions.githubusercontent.com/fLgcSHkPGySXeIFrg8W8OBSfeg3b5Fls1A1CwX566g8PayEGlg/ diff --git a/routers/web/admin/users_test.go b/routers/web/admin/users_test.go index ed58a54ee..19d6d7294 100644 --- a/routers/web/admin/users_test.go +++ b/routers/web/admin/users_test.go @@ -19,7 +19,7 @@ import ( func TestNewUserPost_MustChangePassword(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "admin/users/new") + ctx, _ := test.MockContext(t, "admin/users/new") u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, @@ -56,7 +56,7 @@ func TestNewUserPost_MustChangePassword(t *testing.T) { func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "admin/users/new") + ctx, _ := test.MockContext(t, "admin/users/new") u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, @@ -93,7 +93,7 @@ func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { func TestNewUserPost_InvalidEmail(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "admin/users/new") + ctx, _ := test.MockContext(t, "admin/users/new") u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, @@ -123,7 +123,7 @@ func TestNewUserPost_InvalidEmail(t *testing.T) { func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "admin/users/new") + ctx, _ := test.MockContext(t, "admin/users/new") u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, @@ -161,7 +161,7 @@ func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) { func TestNewUserPost_VisibilityPrivate(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "admin/users/new") + ctx, _ := test.MockContext(t, "admin/users/new") u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, diff --git a/routers/web/org/projects_test.go b/routers/web/org/projects_test.go index 3450fa8e7..08a97b7d2 100644 --- a/routers/web/org/projects_test.go +++ b/routers/web/org/projects_test.go @@ -15,7 +15,7 @@ import ( func TestCheckProjectBoardChangePermissions(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/-/projects/4/4") + ctx, _ := test.MockContext(t, "user2/-/projects/4/4") test.LoadUser(t, ctx, 2) ctx.ContextUser = ctx.Doer // user2 ctx.SetParams(":id", "4") diff --git a/routers/web/repo/editor_test.go b/routers/web/repo/editor_test.go index 1e53aac9b..52dded68b 100644 --- a/routers/web/repo/editor_test.go +++ b/routers/web/repo/editor_test.go @@ -41,7 +41,7 @@ func TestCleanUploadName(t *testing.T) { func TestGetUniquePatchBranchName(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -56,7 +56,7 @@ func TestGetUniquePatchBranchName(t *testing.T) { func TestGetClosestParentWithFiles(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) diff --git a/routers/web/repo/issue_label_test.go b/routers/web/repo/issue_label_test.go index c24fe898b..4c9a35943 100644 --- a/routers/web/repo/issue_label_test.go +++ b/routers/web/repo/issue_label_test.go @@ -32,7 +32,7 @@ func int64SliceToCommaSeparated(a []int64) string { func TestInitializeLabels(t *testing.T) { unittest.PrepareTestEnv(t) assert.NoError(t, repository.LoadRepoConfig()) - ctx := test.MockContext(t, "user2/repo1/labels/initialize") + ctx, _ := test.MockContext(t, "user2/repo1/labels/initialize") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 2) web.SetForm(ctx, &forms.InitializeLabelsForm{TemplateName: "Default"}) @@ -57,7 +57,7 @@ func TestRetrieveLabels(t *testing.T) { {1, "leastissues", []int64{2, 1}}, {2, "", []int64{}}, } { - ctx := test.MockContext(t, "user/repo/issues") + ctx, _ := test.MockContext(t, "user/repo/issues") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, testCase.RepoID) ctx.Req.Form.Set("sort", testCase.Sort) @@ -75,7 +75,7 @@ func TestRetrieveLabels(t *testing.T) { func TestNewLabel(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/labels/edit") + ctx, _ := test.MockContext(t, "user2/repo1/labels/edit") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) web.SetForm(ctx, &forms.CreateLabelForm{ @@ -93,7 +93,7 @@ func TestNewLabel(t *testing.T) { func TestUpdateLabel(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/labels/edit") + ctx, _ := test.MockContext(t, "user2/repo1/labels/edit") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) web.SetForm(ctx, &forms.CreateLabelForm{ @@ -113,7 +113,7 @@ func TestUpdateLabel(t *testing.T) { func TestDeleteLabel(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/labels/delete") + ctx, _ := test.MockContext(t, "user2/repo1/labels/delete") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) ctx.Req.Form.Set("id", "2") @@ -126,7 +126,7 @@ func TestDeleteLabel(t *testing.T) { func TestUpdateIssueLabel_Clear(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) ctx.Req.Form.Set("issue_ids", "1,3") @@ -151,7 +151,7 @@ func TestUpdateIssueLabel_Toggle(t *testing.T) { {"toggle", []int64{1, 2}, 2, true}, } { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) ctx.Req.Form.Set("issue_ids", int64SliceToCommaSeparated(testCase.IssueIDs)) diff --git a/routers/web/repo/projects_test.go b/routers/web/repo/projects_test.go index c712902ea..e2797772a 100644 --- a/routers/web/repo/projects_test.go +++ b/routers/web/repo/projects_test.go @@ -14,7 +14,7 @@ import ( func TestCheckProjectBoardChangePermissions(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/projects/1/2") + ctx, _ := test.MockContext(t, "user2/repo1/projects/1/2") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) ctx.SetParams(":id", "1") diff --git a/routers/web/repo/release_test.go b/routers/web/repo/release_test.go index 9ec1b4d34..07e349811 100644 --- a/routers/web/repo/release_test.go +++ b/routers/web/repo/release_test.go @@ -47,7 +47,7 @@ func TestNewReleasePost(t *testing.T) { } { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/releases/new") + ctx, _ := test.MockContext(t, "user2/repo1/releases/new") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) test.LoadGitRepo(t, ctx) @@ -67,7 +67,7 @@ func TestNewReleasePost(t *testing.T) { func TestNewReleasesList(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo-release/releases") + ctx, _ := test.MockContext(t, "user2/repo-release/releases") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 57) test.LoadGitRepo(t, ctx) diff --git a/routers/web/repo/settings_test.go b/routers/web/repo/settings_test.go index 3bb202505..a33e92c82 100644 --- a/routers/web/repo/settings_test.go +++ b/routers/web/repo/settings_test.go @@ -42,7 +42,7 @@ func TestAddReadOnlyDeployKey(t *testing.T) { } unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/settings/keys") + ctx, _ := test.MockContext(t, "user2/repo1/settings/keys") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 2) @@ -71,7 +71,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/settings/keys") + ctx, _ := test.MockContext(t, "user2/repo1/settings/keys") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 2) @@ -94,7 +94,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) { func TestCollaborationPost(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadUser(t, ctx, 4) test.LoadRepo(t, ctx, 1) @@ -129,7 +129,7 @@ func TestCollaborationPost(t *testing.T) { func TestCollaborationPost_InactiveUser(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadUser(t, ctx, 9) test.LoadRepo(t, ctx, 1) @@ -152,7 +152,7 @@ func TestCollaborationPost_InactiveUser(t *testing.T) { func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadUser(t, ctx, 4) test.LoadRepo(t, ctx, 1) @@ -193,7 +193,7 @@ func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) { func TestCollaborationPost_NonExistentUser(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/issues/labels") + ctx, _ := test.MockContext(t, "user2/repo1/issues/labels") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) @@ -215,7 +215,7 @@ func TestCollaborationPost_NonExistentUser(t *testing.T) { func TestAddTeamPost(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "org26/repo43") + ctx, _ := test.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team11") @@ -255,7 +255,7 @@ func TestAddTeamPost(t *testing.T) { func TestAddTeamPost_NotAllowed(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "org26/repo43") + ctx, _ := test.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team11") @@ -295,7 +295,7 @@ func TestAddTeamPost_NotAllowed(t *testing.T) { func TestAddTeamPost_AddTeamTwice(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "org26/repo43") + ctx, _ := test.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team11") @@ -336,7 +336,7 @@ func TestAddTeamPost_AddTeamTwice(t *testing.T) { func TestAddTeamPost_NonExistentTeam(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "org26/repo43") + ctx, _ := test.MockContext(t, "org26/repo43") ctx.Req.Form.Set("team", "team-non-existent") @@ -369,7 +369,7 @@ func TestAddTeamPost_NonExistentTeam(t *testing.T) { func TestDeleteTeam(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "org3/team1/repo3") + ctx, _ := test.MockContext(t, "org3/team1/repo3") ctx.Req.Form.Set("id", "2") diff --git a/routers/web/repo/wiki_test.go b/routers/web/repo/wiki_test.go index e51820a52..d85879d1e 100644 --- a/routers/web/repo/wiki_test.go +++ b/routers/web/repo/wiki_test.go @@ -78,7 +78,7 @@ func assertPagesMetas(t *testing.T, expectedNames []string, metas interface{}) { func TestWiki(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/?action=_pages") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_pages") ctx.SetParams("*", "Home") test.LoadRepo(t, ctx, 1) Wiki(ctx) @@ -90,7 +90,7 @@ func TestWiki(t *testing.T) { func TestWikiPages(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/?action=_pages") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_pages") test.LoadRepo(t, ctx, 1) WikiPages(ctx) assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) @@ -100,7 +100,7 @@ func TestWikiPages(t *testing.T) { func TestNewWiki(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) NewWiki(ctx) @@ -115,7 +115,7 @@ func TestNewWikiPost(t *testing.T) { } { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) web.SetForm(ctx, &forms.NewWikiForm{ @@ -133,7 +133,7 @@ func TestNewWikiPost(t *testing.T) { func TestNewWikiPost_ReservedName(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/?action=_new") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/?action=_new") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) web.SetForm(ctx, &forms.NewWikiForm{ @@ -150,7 +150,7 @@ func TestNewWikiPost_ReservedName(t *testing.T) { func TestEditWiki(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_edit") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_edit") ctx.SetParams("*", "Home") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) @@ -166,7 +166,7 @@ func TestEditWikiPost(t *testing.T) { "New/", } { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_new") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_new") ctx.SetParams("*", "Home") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) @@ -188,7 +188,7 @@ func TestEditWikiPost(t *testing.T) { func TestDeleteWikiPagePost(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/Home?action=_delete") + ctx, _ := test.MockContext(t, "user2/repo1/wiki/Home?action=_delete") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) DeleteWikiPagePost(ctx) @@ -207,7 +207,7 @@ func TestWikiRaw(t *testing.T) { } { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1/wiki/raw/"+url.PathEscape(filepath)) + ctx, _ := test.MockContext(t, "user2/repo1/wiki/raw/"+url.PathEscape(filepath)) ctx.SetParams("*", filepath) test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) diff --git a/routers/web/user/home_test.go b/routers/web/user/home_test.go index 534b0b262..3a06a38c2 100644 --- a/routers/web/user/home_test.go +++ b/routers/web/user/home_test.go @@ -20,7 +20,7 @@ func TestArchivedIssues(t *testing.T) { setting.UI.IssuePagingNum = 1 assert.NoError(t, unittest.LoadFixtures()) - ctx := test.MockContext(t, "issues") + ctx, _ := test.MockContext(t, "issues") test.LoadUser(t, ctx, 30) ctx.Req.Form.Set("state", "open") @@ -53,7 +53,7 @@ func TestIssues(t *testing.T) { setting.UI.IssuePagingNum = 1 assert.NoError(t, unittest.LoadFixtures()) - ctx := test.MockContext(t, "issues") + ctx, _ := test.MockContext(t, "issues") test.LoadUser(t, ctx, 2) ctx.Req.Form.Set("state", "closed") Issues(ctx) @@ -69,7 +69,7 @@ func TestPulls(t *testing.T) { setting.UI.IssuePagingNum = 20 assert.NoError(t, unittest.LoadFixtures()) - ctx := test.MockContext(t, "pulls") + ctx, _ := test.MockContext(t, "pulls") test.LoadUser(t, ctx, 2) ctx.Req.Form.Set("state", "open") Pulls(ctx) @@ -82,7 +82,7 @@ func TestMilestones(t *testing.T) { setting.UI.IssuePagingNum = 1 assert.NoError(t, unittest.LoadFixtures()) - ctx := test.MockContext(t, "milestones") + ctx, _ := test.MockContext(t, "milestones") test.LoadUser(t, ctx, 2) ctx.SetParams("sort", "issues") ctx.Req.Form.Set("state", "closed") @@ -101,7 +101,7 @@ func TestMilestonesForSpecificRepo(t *testing.T) { setting.UI.IssuePagingNum = 1 assert.NoError(t, unittest.LoadFixtures()) - ctx := test.MockContext(t, "milestones") + ctx, _ := test.MockContext(t, "milestones") test.LoadUser(t, ctx, 2) ctx.SetParams("sort", "issues") ctx.SetParams("repo", "1") diff --git a/routers/web/user/setting/account_test.go b/routers/web/user/setting/account_test.go index 569d59772..ba840db28 100644 --- a/routers/web/user/setting/account_test.go +++ b/routers/web/user/setting/account_test.go @@ -83,7 +83,7 @@ func TestChangePassword(t *testing.T) { t.Run(req.OldPassword+"__"+req.NewPassword, func(t *testing.T) { unittest.PrepareTestEnv(t) setting.PasswordComplexity = req.PasswordComplexity - ctx := test.MockContext(t, "user/settings/security") + ctx, _ := test.MockContext(t, "user/settings/security") test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) diff --git a/routers/web/web.go b/routers/web/web.go index 8683ef221..fae935a50 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -104,7 +104,7 @@ func ctxDataSet(args ...any) func(ctx *context.Context) { } // Routes returns all web routes -func Routes(ctx gocontext.Context) *web.Route { +func Routes() *web.Route { routes := web.NewRoute() routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler @@ -146,13 +146,8 @@ func Routes(ctx gocontext.Context) *web.Route { mid = append(mid, common.Sessioner(), context.Contexter()) - group := buildAuthGroup() - if err := group.Init(ctx); err != nil { - log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err) - } - // Get user from session if logged in. - mid = append(mid, auth_service.Auth(group)) + mid = append(mid, auth_service.Auth(buildAuthGroup())) // GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route mid = append(mid, middleware.GetHead) diff --git a/services/auth/group.go b/services/auth/group.go index 0a0330b3a..a1ff65f20 100644 --- a/services/auth/group.go +++ b/services/auth/group.go @@ -4,7 +4,6 @@ package auth import ( - "context" "net/http" "reflect" "strings" @@ -14,9 +13,7 @@ import ( // Ensure the struct implements the interface. var ( - _ Method = &Group{} - _ Initializable = &Group{} - _ Freeable = &Group{} + _ Method = &Group{} ) // Group implements the Auth interface with serval Auth. @@ -49,35 +46,6 @@ func (b *Group) Name() string { return strings.Join(names, ",") } -// Init does nothing as the Basic implementation does not need to allocate any resources -func (b *Group) Init(ctx context.Context) error { - for _, method := range b.methods { - initializable, ok := method.(Initializable) - if !ok { - continue - } - - if err := initializable.Init(ctx); err != nil { - return err - } - } - return nil -} - -// Free does nothing as the Basic implementation does not have to release any resources -func (b *Group) Free() error { - for _, method := range b.methods { - freeable, ok := method.(Freeable) - if !ok { - continue - } - if err := freeable.Free(); err != nil { - return err - } - } - return nil -} - // Verify extracts and validates func (b *Group) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { // Try to sign in with each of the enabled plugins diff --git a/services/auth/interface.go b/services/auth/interface.go index c4a8a20d0..508291fa4 100644 --- a/services/auth/interface.go +++ b/services/auth/interface.go @@ -29,26 +29,11 @@ type Method interface { Verify(http *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) } -// Initializable represents a structure that requires initialization -// It usually should only be called once before anything else is called -type Initializable interface { - // Init should be called exactly once before using any of the other methods, - // in order to allow the plugin to allocate necessary resources - Init(ctx context.Context) error -} - // Named represents a named thing type Named interface { Name() string } -// Freeable represents a structure that is required to be freed -type Freeable interface { - // Free should be called exactly once before application closes, in order to - // give chance to the plugin to free any allocated resources - Free() error -} - // PasswordAuthenticator represents a source of authentication type PasswordAuthenticator interface { Authenticate(user *user_model.User, login, password string) (*user_model.User, error) diff --git a/services/auth/sspi_windows.go b/services/auth/sspi_windows.go index d49497e19..c16281079 100644 --- a/services/auth/sspi_windows.go +++ b/services/auth/sspi_windows.go @@ -4,10 +4,10 @@ package auth import ( - "context" "errors" "net/http" "strings" + "sync" "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/avatars" @@ -32,13 +32,12 @@ var ( // sspiAuth is a global instance of the websspi authentication package, // which is used to avoid acquiring the server credential handle on // every request - sspiAuth *websspi.Authenticator + sspiAuth *websspi.Authenticator + sspiAuthOnce sync.Once // Ensure the struct implements the interface. - _ Method = &SSPI{} - _ Named = &SSPI{} - _ Initializable = &SSPI{} - _ Freeable = &SSPI{} + _ Method = &SSPI{} + _ Named = &SSPI{} ) // SSPI implements the SingleSignOn interface and authenticates requests @@ -47,32 +46,25 @@ var ( // Returns nil if authentication fails. type SSPI struct{} -// Init creates a new global websspi.Authenticator object -func (s *SSPI) Init(ctx context.Context) error { - config := websspi.NewConfig() - var err error - sspiAuth, err = websspi.New(config) - if err != nil { - return err - } - return nil -} - // Name represents the name of auth method func (s *SSPI) Name() string { return "sspi" } -// Free releases resources used by the global websspi.Authenticator object -func (s *SSPI) Free() error { - return sspiAuth.Free() -} - // Verify uses SSPI (Windows implementation of SPNEGO) to authenticate the request. // If authentication is successful, returns the corresponding user object. // If negotiation should continue or authentication fails, immediately returns a 401 HTTP // response code, as required by the SPNEGO protocol. func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { + var errInit error + sspiAuthOnce.Do(func() { + config := websspi.NewConfig() + sspiAuth, errInit = websspi.New(config) + }) + if errInit != nil { + return nil, errInit + } + if !s.shouldAuthenticate(req) { return nil, nil } diff --git a/services/repository/archiver/archiver_test.go b/services/repository/archiver/archiver_test.go index 3cd6e8135..4b6fb7446 100644 --- a/services/repository/archiver/archiver_test.go +++ b/services/repository/archiver/archiver_test.go @@ -24,7 +24,7 @@ func TestMain(m *testing.M) { func TestArchive_Basic(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - ctx := test.MockContext(t, "user27/repo49") + ctx, _ := test.MockContext(t, "user27/repo49") firstCommit, secondCommit := "51f84af23134", "aacbdfe9e1c4" test.LoadRepo(t, ctx, 49) diff --git a/services/repository/files/content_test.go b/services/repository/files/content_test.go index a43b71cf3..8ff96822c 100644 --- a/services/repository/files/content_test.go +++ b/services/repository/files/content_test.go @@ -54,7 +54,7 @@ func getExpectedReadmeContentsResponse() *api.ContentsResponse { func TestGetContents(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -82,7 +82,7 @@ func TestGetContents(t *testing.T) { func TestGetContentsOrListForDir(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -117,7 +117,7 @@ func TestGetContentsOrListForDir(t *testing.T) { func TestGetContentsOrListForFile(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -145,7 +145,7 @@ func TestGetContentsOrListForFile(t *testing.T) { func TestGetContentsErrors(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -176,7 +176,7 @@ func TestGetContentsErrors(t *testing.T) { func TestGetContentsOrListErrors(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -207,7 +207,7 @@ func TestGetContentsOrListErrors(t *testing.T) { func TestGetContentsOrListOfEmptyRepos(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user30/empty") + ctx, _ := test.MockContext(t, "user30/empty") ctx.SetParams(":id", "52") test.LoadRepo(t, ctx, 52) test.LoadUser(t, ctx, 30) @@ -225,7 +225,7 @@ func TestGetContentsOrListOfEmptyRepos(t *testing.T) { func TestGetBlobBySHA(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) test.LoadUser(t, ctx, 2) diff --git a/services/repository/files/diff_test.go b/services/repository/files/diff_test.go index 621816e97..0346e0e9e 100644 --- a/services/repository/files/diff_test.go +++ b/services/repository/files/diff_test.go @@ -17,7 +17,7 @@ import ( func TestGetDiffPreview(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -139,7 +139,7 @@ func TestGetDiffPreview(t *testing.T) { func TestGetDiffPreviewErrors(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) diff --git a/services/repository/files/file_test.go b/services/repository/files/file_test.go index e1c7d5d7f..d14a04943 100644 --- a/services/repository/files/file_test.go +++ b/services/repository/files/file_test.go @@ -98,7 +98,7 @@ func getExpectedFileResponse() *api.FileResponse { func TestGetFileResponseFromCommit(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) diff --git a/services/repository/files/tree_test.go b/services/repository/files/tree_test.go index a500dbdb2..51a2190e8 100644 --- a/services/repository/files/tree_test.go +++ b/services/repository/files/tree_test.go @@ -15,7 +15,7 @@ import ( func TestGetTreeBySHA(t *testing.T) { unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) test.LoadUser(t, ctx, 2) diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index fbcb0e7da..c4b0b6219 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -38,7 +38,7 @@ func TestMain(m *testing.M) { defer cancel() tests.InitTest(false) - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() os.Unsetenv("GIT_AUTHOR_NAME") os.Unsetenv("GIT_AUTHOR_EMAIL") diff --git a/tests/integration/api_activitypub_person_test.go b/tests/integration/api_activitypub_person_test.go index 301cfba17..a1ce80270 100644 --- a/tests/integration/api_activitypub_person_test.go +++ b/tests/integration/api_activitypub_person_test.go @@ -22,10 +22,10 @@ import ( func TestActivityPubPerson(t *testing.T) { setting.Federation.Enabled = true - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() defer func() { setting.Federation.Enabled = false - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() }() onGiteaRun(t, func(*testing.T, *url.URL) { @@ -60,10 +60,10 @@ func TestActivityPubPerson(t *testing.T) { func TestActivityPubMissingPerson(t *testing.T) { setting.Federation.Enabled = true - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() defer func() { setting.Federation.Enabled = false - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() }() onGiteaRun(t, func(*testing.T, *url.URL) { @@ -75,10 +75,10 @@ func TestActivityPubMissingPerson(t *testing.T) { func TestActivityPubPersonInbox(t *testing.T) { setting.Federation.Enabled = true - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() defer func() { setting.Federation.Enabled = false - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() }() srv := httptest.NewServer(c) diff --git a/tests/integration/api_nodeinfo_test.go b/tests/integration/api_nodeinfo_test.go index bc2f11a7f..158a86609 100644 --- a/tests/integration/api_nodeinfo_test.go +++ b/tests/integration/api_nodeinfo_test.go @@ -4,7 +4,6 @@ package integration import ( - "context" "net/http" "net/url" "testing" @@ -18,10 +17,10 @@ import ( func TestNodeinfo(t *testing.T) { setting.Federation.Enabled = true - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() defer func() { setting.Federation.Enabled = false - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() }() onGiteaRun(t, func(*testing.T, *url.URL) { diff --git a/tests/integration/create_no_session_test.go b/tests/integration/create_no_session_test.go index 9a96ed61f..535d0d495 100644 --- a/tests/integration/create_no_session_test.go +++ b/tests/integration/create_no_session_test.go @@ -4,7 +4,6 @@ package integration import ( - "context" "net/http" "net/http/httptest" "os" @@ -57,7 +56,7 @@ func TestSessionFileCreation(t *testing.T) { oldSessionConfig := setting.SessionConfig.ProviderConfig defer func() { setting.SessionConfig.ProviderConfig = oldSessionConfig - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() }() var config session.Options @@ -76,7 +75,7 @@ func TestSessionFileCreation(t *testing.T) { setting.SessionConfig.ProviderConfig = string(newConfigBytes) - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() t.Run("NoSessionOnViewIssue", func(t *testing.T) { defer tests.PrintCurrentTest(t)() diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index 27918a9cc..2318ab9bb 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -87,7 +87,7 @@ func TestMain(m *testing.M) { defer cancel() tests.InitTest(true) - c = routers.NormalRoutes(context.TODO()) + c = routers.NormalRoutes() // integration test settings... if setting.CfgProvider != nil { diff --git a/tests/integration/repofiles_change_test.go b/tests/integration/repofiles_change_test.go index a257b95a8..c273d3818 100644 --- a/tests/integration/repofiles_change_test.go +++ b/tests/integration/repofiles_change_test.go @@ -244,7 +244,7 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA func TestChangeRepoFilesForCreate(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -281,7 +281,7 @@ func TestChangeRepoFilesForCreate(t *testing.T) { func TestChangeRepoFilesForUpdate(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -315,7 +315,7 @@ func TestChangeRepoFilesForUpdate(t *testing.T) { func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -366,7 +366,7 @@ func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) { func TestChangeRepoFilesWithoutBranchNames(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -402,7 +402,7 @@ func TestChangeRepoFilesForDelete(t *testing.T) { func testDeleteRepoFiles(t *testing.T, u *url.URL) { // setup unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -441,7 +441,7 @@ func TestChangeRepoFilesForDeleteWithoutBranchNames(t *testing.T) { func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { // setup unittest.PrepareTestEnv(t) - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx) @@ -471,7 +471,7 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) { func TestChangeRepoFilesErrors(t *testing.T) { // setup onGiteaRun(t, func(t *testing.T, u *url.URL) { - ctx := test.MockContext(t, "user2/repo1") + ctx, _ := test.MockContext(t, "user2/repo1") ctx.SetParams(":id", "1") test.LoadRepo(t, ctx, 1) test.LoadRepoCommit(t, ctx)