From 1d8474ee1feb2ae744beb6d240eb6212469c71ee Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sat, 24 Oct 2026 16:27:56 +0800 Subject: [PATCH] refactor: username sub route (#39967) Remove the workaround for chi router, do as much as possible in middlewares --------- Co-authored-by: silverwind Co-authored-by: Giteabot --- models/user/user.go | 2 +- routers/web/feed/convert.go | 15 +++--- routers/web/feed/profile.go | 14 ++---- routers/web/goget.go | 8 +--- routers/web/home.go | 5 ++ routers/web/org/home.go | 10 +--- routers/web/user/heatmap.go | 7 --- routers/web/user/home.go | 83 +++++++++++++++++----------------- routers/web/user/profile.go | 25 +--------- routers/web/web.go | 29 ++++++++---- services/context/user.go | 12 +++++ tests/integration/user_test.go | 6 ++- tests/integration/view_test.go | 4 +- 13 files changed, 103 insertions(+), 117 deletions(-) diff --git a/models/user/user.go b/models/user/user.go index 7c4404d376d..6da7cb68c53 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -660,7 +660,7 @@ var ( } // These names are reserved for user accounts: user's keys, user's rss feed, user's avatar, etc. - // DO NOT add any new stuff! The paths with these names are processed by `/{username}` handler (UsernameSubRoute) manually. + // HINT: OWNER-NAME-RESERVED-EXT: DO NOT add any new stuff! The paths with these names are processed by UsernamePreRoute handler manually. reservedUserPatterns = []string{"*.keys", "*.gpg", "*.rss", "*.atom", "*.png"} ) diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go index ccdd250a3b2..5fce911c126 100644 --- a/routers/web/feed/convert.go +++ b/routers/web/feed/convert.go @@ -260,18 +260,21 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio return items, err } +const ( + ExtNameRss = ".rss" + ExtNameAtom = ".atom" + ContentTypeRssXml = "application/rss+xml" + ContentTypeAtomXml = "application/atom+xml" +) + // GetFeedType return if it is a feed request and altered name and feed type. func GetFeedType(name string, req *http.Request) (showFeed bool, feedType string) { - if strings.HasSuffix(name, ".rss") || - strings.Contains(req.Header.Get("Accept"), "application/rss+xml") { + if strings.HasSuffix(name, ExtNameRss) || strings.Contains(req.Header.Get("Accept"), ContentTypeRssXml) { return true, "rss" } - - if strings.HasSuffix(name, ".atom") || - strings.Contains(req.Header.Get("Accept"), "application/atom+xml") { + if strings.HasSuffix(name, ExtNameAtom) || strings.Contains(req.Header.Get("Accept"), ContentTypeAtomXml) { return true, "atom" } - return false, "" } diff --git a/routers/web/feed/profile.go b/routers/web/feed/profile.go index 14320890931..201649ab2d6 100644 --- a/routers/web/feed/profile.go +++ b/routers/web/feed/profile.go @@ -9,7 +9,6 @@ import ( activities_model "gitea.dev/models/activities" "gitea.dev/models/organization" "gitea.dev/models/renderhelper" - user_model "gitea.dev/models/user" "gitea.dev/modules/markup/markdown" "gitea.dev/modules/setting" "gitea.dev/services/context" @@ -30,16 +29,13 @@ func ShowUserFeedAtom(ctx *context.Context) { // showUserFeed show user activity as RSS / Atom feed func showUserFeed(ctx *context.Context, formatType string) { - isOrganisation := ctx.ContextUser.IsOrganization() - if !setting.Other.EnableFeed || - isOrganisation && !organization.HasOrgOrUserVisible(ctx, ctx.ContextUser, ctx.Doer) || - !isOrganisation && !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) { + if !setting.Other.EnableFeed { ctx.NotFound(nil) return } includePrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID) - if ctx.IsSigned && isOrganisation && !includePrivate { + if ctx.IsSigned && ctx.ContextUser.IsOrganization() && !includePrivate { // When feed is requested by a member of the organization, // include the private repo's the member has access to. isOrgMember, err := organization.IsOrganizationMember(ctx, ctx.ContextUser.ID, ctx.Doer.ID) @@ -54,7 +50,7 @@ func showUserFeed(ctx *context.Context, formatType string) { RequestedUser: ctx.ContextUser, Actor: ctx.Doer, IncludePrivate: includePrivate, - OnlyPerformedBy: !isOrganisation, + OnlyPerformedBy: !ctx.ContextUser.IsOrganization(), IncludeDeleted: false, Date: ctx.FormString("date"), }) @@ -90,12 +86,12 @@ func showUserFeed(ctx *context.Context, formatType string) { // writeFeed write a feeds.Feed as atom or rss to ctx.Resp func writeFeed(ctx *context.Context, feed *feeds.Feed, formatType string) { if formatType == "atom" { - ctx.Resp.Header().Set("Content-Type", "application/atom+xml;charset=utf-8") + ctx.Resp.Header().Set("Content-Type", ContentTypeAtomXml+"; charset=utf-8") if err := feed.WriteAtom(ctx.Resp); err != nil { ctx.ServerError("Render Atom failed", err) } } else { - ctx.Resp.Header().Set("Content-Type", "application/rss+xml;charset=utf-8") + ctx.Resp.Header().Set("Content-Type", ContentTypeRssXml+"; charset=utf-8") if err := feed.WriteRss(ctx.Resp); err != nil { ctx.ServerError("Render RSS failed", err) } diff --git a/routers/web/goget.go b/routers/web/goget.go index f80134fc647..9a3a61591ee 100644 --- a/routers/web/goget.go +++ b/routers/web/goget.go @@ -96,18 +96,14 @@ func goGetDefaultBranch(ctx *context.Context, repo *repo_model.Repository) strin if len(repo.DefaultBranch) == 0 { return def } - if err := repo.LoadOwner(ctx); err != nil || repo.Owner == nil { - return def - } // a token that was not granted repository read scope must not learn repository details, even when the // account behind it could read the repo through the web UI if !goGetTokenCanReadRepo(ctx) { return def } - // the caller must be able to read the code and see the owner: a limited/private owner hides its repos - // from anonymous/non-member callers even when the repo itself is public + // the caller must be able to read the code perm, err := access_model.GetDoerRepoPermission(ctx, repo, ctx.Doer) - if err != nil || !perm.CanRead(unit.TypeCode) || !user_model.IsUserVisibleToViewer(ctx, repo.Owner, ctx.Doer) { + if err != nil || !perm.CanRead(unit.TypeCode) { return def } return repo.DefaultBranch diff --git a/routers/web/home.go b/routers/web/home.go index c0756294ba9..fcdb2c27bc6 100644 --- a/routers/web/home.go +++ b/routers/web/home.go @@ -17,6 +17,7 @@ import ( "gitea.dev/modules/sitemap" "gitea.dev/modules/structs" "gitea.dev/modules/templates" + "gitea.dev/routers/web/feed" "gitea.dev/routers/web/user" "gitea.dev/services/context" ) @@ -24,6 +25,10 @@ import ( const tplHome templates.TplName = "home" func Home(ctx *context.Context) { + if _, feedType := feed.GetFeedType(ctx.Req.URL.Path, ctx.Req); feedType != "" { + ctx.Resp.WriteHeader(http.StatusUnsupportedMediaType) + return + } if ctx.IsSigned { user.Dashboard(ctx) return diff --git a/routers/web/org/home.go b/routers/web/org/home.go index dfb7da079fd..d9150655b6a 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -5,7 +5,6 @@ package org import ( "net/http" - "strings" "gitea.dev/models/db" "gitea.dev/models/organization" @@ -25,14 +24,7 @@ const tplOrgHome templates.TplName = "org/home" // Home show organization home page func Home(ctx *context.Context) { - uname := ctx.PathParam("username") - - if strings.HasSuffix(uname, ".keys") || strings.HasSuffix(uname, ".gpg") { - ctx.NotFound(nil) - return - } - - ctx.SetPathParam("org", uname) + ctx.SetPathParam("org", ctx.PathParam("username")) context.OrgAssignment(context.OrgAssignmentOptions{})(ctx) if ctx.Written() { return diff --git a/routers/web/user/heatmap.go b/routers/web/user/heatmap.go index 475e48ff580..a9e7ac86ccf 100644 --- a/routers/web/user/heatmap.go +++ b/routers/web/user/heatmap.go @@ -8,7 +8,6 @@ import ( "net/url" activities_model "gitea.dev/models/activities" - user_model "gitea.dev/models/user" "gitea.dev/modules/setting" "gitea.dev/services/context" ) @@ -52,12 +51,6 @@ func DashboardHeatmap(ctx *context.Context) { ctx.NotFound(nil) return } - if ctx.Org.Organization == nil && !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) { - // this end point is mounted on different routes, so we need to - // check if the user is visible to the viewer when there is no organization context (no visibility check) - ctx.NotFound(nil) - return - } var data []*activities_model.UserHeatmapData var err error if ctx.Org.Organization == nil { diff --git a/routers/web/user/home.go b/routers/web/user/home.go index addb9caec9a..02f215aa09e 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -6,8 +6,8 @@ package user import ( "bytes" - "fmt" "net/http" + "path" "regexp" "slices" "sort" @@ -43,6 +43,7 @@ import ( "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/armor" + "github.com/go-chi/chi/v5" "xorm.io/builder" ) @@ -702,52 +703,50 @@ func ShowGPGKeys(ctx *context.Context) { ctx.PlainTextBytes(http.StatusOK, buf.Bytes()) } -func UsernameSubRoute(ctx *context.Context) { - // WORKAROUND to support usernames with "." in it - // https://github.com/go-chi/chi/issues/781 - username := ctx.PathParam("username") - reloadParam := func(suffix string) (success bool) { - ctx.SetPathParam("username", strings.TrimSuffix(username, suffix)) - context.UserAssignmentWeb()(ctx) - if ctx.Written() { - return false +// UsernamePreRoute rewrites the route path if the username has a suffix, so that the correct handler can be called. +func UsernamePreRoute(next http.Handler) http.Handler { + // HINT: OWNER-NAME-RESERVED-EXT: use the reserved extensions to check and rewrite requests + suffixes := container.SetOf(".png", ".keys", ".gpg", feed.ExtNameRss, feed.ExtNameAtom) + rewriteRoutePath := func(rctx *chi.Context, r *http.Request) (ownerPath, rewrittenExt string) { + if rctx.RouteMethod != "HEAD" && rctx.RouteMethod != "GET" { + return "", "" + } + // if there is no slash in the path, then it is possible to be a username or a username with a suffix + possibleUsernameWithSuffix := rctx.RoutePath != "" && strings.IndexByte(rctx.RoutePath[1:], '/') == -1 + if !possibleUsernameWithSuffix { + return "", "" } - // check view permissions - if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) { - ctx.NotFound(fmt.Errorf("%s", ctx.ContextUser.Name)) - return false + // HINT: USERNAME-AVATAR-APPLE-TOUCH-ICON: skip rewriting the path if it is an apple touch icon request + isAppleTouchIcon := rctx.RoutePath == "/apple-touch-icon.png" || rctx.RoutePath == "/apple-touch-icon-precomposed.png" + if isAppleTouchIcon { + return "", "" } - return true + + // try to extract the suffix from the path, if it is a valid suffix, then rewrite the path to "/-/ownername.png/{username}" + ext := path.Ext(rctx.RoutePath) + if suffixes.Contains(ext) { + return rctx.RoutePath[:len(rctx.RoutePath)-len(ext)], ext + } + // also try to rewrite "/username" to "/-/ownername.rss/{username}" if the Accept header is for RSS or Atom + if strings.Contains(r.Header.Get("Accept"), feed.ContentTypeRssXml) { + return rctx.RoutePath, feed.ExtNameRss + } else if strings.Contains(r.Header.Get("Accept"), feed.ContentTypeAtomXml) { + return rctx.RoutePath, feed.ExtNameAtom + } + return "", "" } - switch { - case strings.HasSuffix(username, ".png"): - if reloadParam(".png") { - AvatarByUsernameSize(ctx) + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + rctx := chi.RouteContext(r.Context()) + if ownerPath, rewrittenExt := rewriteRoutePath(rctx, r); ownerPath != "/" && rewrittenExt != "" { + // Owner path can be something like "/" (site home) or "/explore" (endpoint of reserved username) + // It's safe to pass the owner path to the handler as is and just let the handler respond 4xx. + // Because the server doesn't respond avatar, keys or feeds for these endpoints. + rctx.RoutePath = "/-/ownername" + rewrittenExt + ownerPath } - case strings.HasSuffix(username, ".keys"): - if reloadParam(".keys") { - ShowSSHKeys(ctx) - } - case strings.HasSuffix(username, ".gpg"): - if reloadParam(".gpg") { - ShowGPGKeys(ctx) - } - case strings.HasSuffix(username, ".rss"): - if reloadParam(".rss") { - feed.ShowUserFeedRSS(ctx) - } - case strings.HasSuffix(username, ".atom"): - if reloadParam(".atom") { - feed.ShowUserFeedAtom(ctx) - } - default: - context.UserAssignmentWeb()(ctx) - if !ctx.Written() { - ctx.Data["EnableFeed"] = setting.Other.EnableFeed - OwnerProfile(ctx) - } - } + next.ServeHTTP(w, r) + }) } func getUserIssueStats(ctx *context.Context, ctxUser *user_model.User, filterMode int, opts *issue_indexer.SearchOptions) (ret *issues_model.IssueStats, err error) { diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 2f232c24710..53ce18d773f 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -7,7 +7,6 @@ package user import ( "fmt" "net/http" - "strings" activities_model "gitea.dev/models/activities" "gitea.dev/models/db" @@ -21,7 +20,6 @@ import ( "gitea.dev/modules/optional" "gitea.dev/modules/setting" "gitea.dev/modules/templates" - "gitea.dev/routers/web/feed" "gitea.dev/routers/web/org" shared_user "gitea.dev/routers/web/shared/user" "gitea.dev/services/context" @@ -35,15 +33,7 @@ const ( // OwnerProfile render profile page for a user or a organization (aka, repo owner) func OwnerProfile(ctx *context.Context) { - if strings.Contains(ctx.Req.Header.Get("Accept"), "application/rss+xml") { - feed.ShowUserFeedRSS(ctx) - return - } - if strings.Contains(ctx.Req.Header.Get("Accept"), "application/atom+xml") { - feed.ShowUserFeedAtom(ctx) - return - } - + ctx.Data["EnableFeed"] = setting.Other.EnableFeed if ctx.ContextUser.IsOrganization() { org.Home(ctx) } else { @@ -52,12 +42,6 @@ func OwnerProfile(ctx *context.Context) { } func userProfile(ctx *context.Context) { - // check view permissions - if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) { - ctx.NotFound(fmt.Errorf("%s", ctx.ContextUser.Name)) - return - } - ctx.Data["Title"] = ctx.ContextUser.DisplayName() ctx.Data["PageIsUserProfile"] = true @@ -322,13 +306,6 @@ func prepareUserProfileTabData(ctx *context.Context, profileDbRepo *repo_model.R // ActionUserFollow is for follow/unfollow user request func ActionUserFollow(ctx *context.Context) { - isOrg := ctx.ContextUser.IsOrganization() - if isOrg && !organization.HasOrgOrUserVisible(ctx, ctx.ContextUser, ctx.Doer) || - !isOrg && !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) { - ctx.NotFound(nil) - return - } - var err error switch ctx.FormString("action") { case "follow": diff --git a/routers/web/web.go b/routers/web/web.go index 0fa4c8b7a9e..a28e35eef81 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -258,15 +258,18 @@ func Routes() *web.Router { // GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route routes.BeforeRouting(chi_middleware.GetHead) + routes.BeforeRouting(user.UsernamePreRoute) routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler routes.Methods("GET, HEAD", "/assets/site-manifest.json", misc.SiteManifest) routes.Methods("GET, HEAD, OPTIONS", "/assets/*", routing.MarkLogLevelTrace, public.AssetsCors(), public.FileHandlerFunc()) routes.Methods("GET, HEAD", "/avatars/*", avatarStorageHandler(setting.Avatar.Storage, "avatars", storage.Avatars)) routes.Methods("GET, HEAD", "/repo-avatars/*", avatarStorageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars)) + routes.Methods("GET, HEAD", "/favicon.ico", misc.StaticRedirect("/assets/img/favicon.png")) + + // HINT: USERNAME-AVATAR-APPLE-TOUCH-ICON: these two paths conflict with "/{username}.png" routes.Methods("GET, HEAD", "/apple-touch-icon.png", misc.StaticRedirect("/assets/img/apple-touch-icon.png")) routes.Methods("GET, HEAD", "/apple-touch-icon-precomposed.png", misc.StaticRedirect("/assets/img/apple-touch-icon.png")) - routes.Methods("GET, HEAD", "/favicon.ico", misc.StaticRedirect("/assets/img/favicon.png")) var mid []any @@ -906,13 +909,19 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { }, adminReq, ctxDataSet(reqctx.ContextData{"EnableOAuth2": setting.OAuth2.Enabled, "EnablePackages": setting.Packages.Enabled})) // ***** END: Admin ***** - m.Group("", func() { - // it handles "username.rss" in the handler, so allow basic auth as other rss/atom routes - m.Get("/{username}", webAuth.AllowBasic, user.UsernameSubRoute) - m.Methods("GET, OPTIONS", "/attachments/{uuid}", optionsCorsHandler(), webAuth.AllowBasic, webAuth.AllowOAuth2, repo.GetAttachment) - }, optSignIn) + m.Methods("GET, OPTIONS", "/attachments/{uuid}", optionsCorsHandler(), webAuth.AllowBasic, webAuth.AllowOAuth2, optSignIn, repo.GetAttachment) - m.Post("/{username}", reqSignIn, context.UserAssignmentWeb(), user.ActionUserFollow) + m.Group("", func() { + // "UsernamePreRoute" is used to rewrite username with a suffix like "/username.png" to "/-/ownername.png/username" + m.Get("/-/ownername.png/{username}", user.AvatarByUsernameSize) + m.Get("/-/ownername.keys/{username}", user.ShowSSHKeys) + m.Get("/-/ownername.gpg/{username}", user.ShowGPGKeys) + m.Get("/-/ownername.rss/{username}", feed.ShowUserFeedRSS) + m.Get("/-/ownername.atom/{username}", feed.ShowUserFeedAtom) + m.Get("/{username}", user.OwnerProfile) + }, webAuth.AllowBasic, optSignIn, context.UserAssignmentWeb(), context.ReqContextUserVisibleToDoer()) + + m.Post("/{username}", reqSignIn, context.UserAssignmentWeb(), context.ReqContextUserVisibleToDoer(), user.ActionUserFollow) reqRepoAdmin := context.RequireRepoAdmin() reqRepoCodeWriter := context.RequireUnitWriter(unit.TypeCode) @@ -981,8 +990,8 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Group("/{org}", func() { m.Get("/dashboard", user.Dashboard) m.Get("/dashboard/{team}", user.Dashboard) - m.Get("/dashboard/-/heatmap", user.DashboardHeatmap) - m.Get("/dashboard/-/heatmap/{team}", user.DashboardHeatmap) + m.Get("/dashboard/-/heatmap", context.ReqContextUserVisibleToDoer(), user.DashboardHeatmap) + m.Get("/dashboard/-/heatmap/{team}", context.ReqContextUserVisibleToDoer(), user.DashboardHeatmap) m.Get("/issues", user.Issues) m.Get("/issues/{team}", user.Issues) m.Get("/pulls", user.Pulls) @@ -1132,7 +1141,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Get("/mentions-in-owner", reqAnyRepoUnitAccess(unit.TypeProjects, perm.AccessModeWrite, true), org.GetMentionsInOwner) m.Get("/repositories", org.Repositories) - m.Get("/heatmap", user.DashboardHeatmap) + m.Get("/heatmap", context.ReqContextUserVisibleToDoer(), user.DashboardHeatmap) m.Group("/projects", func() { m.Group("", func() { diff --git a/services/context/user.go b/services/context/user.go index 576a778bb48..06fc2671fd8 100644 --- a/services/context/user.go +++ b/services/context/user.go @@ -8,10 +8,22 @@ import ( "net/http" "strings" + "gitea.dev/models/organization" user_model "gitea.dev/models/user" "gitea.dev/modules/session" ) +func ReqContextUserVisibleToDoer() func(ctx *Context) { + return func(ctx *Context) { + isOrg := ctx.ContextUser.IsOrganization() + if isOrg && !organization.HasOrgOrUserVisible(ctx, ctx.ContextUser, ctx.Doer) || + !isOrg && !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) { + ctx.NotFound(nil) + return + } + } +} + // UserAssignmentWeb returns a middleware to handle context-user assignment for web routes func UserAssignmentWeb() func(ctx *Context) { return func(ctx *Context) { diff --git a/tests/integration/user_test.go b/tests/integration/user_test.go index 76bc85adcc1..1e8a79767dd 100644 --- a/tests/integration/user_test.go +++ b/tests/integration/user_test.go @@ -134,6 +134,7 @@ func testViewLimitedAndPrivateUserAndRename(t *testing.T) { req = NewRequest(t, "GET", "/"+user31.Name) MakeRequest(t, req, http.StatusNotFound) MakeRequest(t, NewRequest(t, "GET", "/"+user31.Name).SetHeader("Accept", "application/rss+xml"), http.StatusNotFound) + MakeRequest(t, NewRequest(t, "GET", "/"+user31.Name+".keys"), http.StatusNotFound) strangerSession.MakeRequest(t, NewRequest(t, "POST", "/"+user31.Name+"?action=follow"), http.StatusNotFound) oldName = user31.Name @@ -237,6 +238,7 @@ func testRenameReservedUsername(t *testing.T) { func testExportUserGPGKeys(t *testing.T) { testExportUserGPGKeys := func(t *testing.T, user, expected string) { + t.Helper() session := loginUser(t, user) t.Logf("Testing username %s export gpg keys", user) req := NewRequest(t, "GET", "/"+user+".gpg") @@ -324,7 +326,7 @@ func testGetUserRss(t *testing.T) { user34 := "the_34-user.with.all.allowedChars" req := NewRequestf(t, "GET", "/%s.rss", user34) resp := MakeRequest(t, req, http.StatusOK) - if assert.Equal(t, "application/rss+xml;charset=utf-8", resp.Header().Get("Content-Type")) { + if assert.Equal(t, "application/rss+xml; charset=utf-8", resp.Header().Get("Content-Type")) { rssDoc := NewHTMLParser(t, resp.Body).Find("channel") title, _ := rssDoc.ChildrenFiltered("title").Html() assert.Equal(t, "Feed of "the_1-user.with.all.allowedChars"", title) @@ -339,6 +341,8 @@ func testGetUserRss(t *testing.T) { req = NewRequestf(t, "GET", "/non-existent-user.rss") session.MakeRequest(t, req, http.StatusNotFound) + MakeRequest(t, NewRequest(t, "GET", "/").SetHeader("Accept", "application/rss+xml"), http.StatusUnsupportedMediaType) + defer test.MockVariableValue(&setting.Other.EnableFeed, false)() MakeRequest(t, NewRequestf(t, "GET", "/%s.rss", user34), http.StatusNotFound) MakeRequest(t, NewRequestf(t, "GET", "/%s", user34).SetHeader("Accept", "application/rss+xml"), http.StatusNotFound) diff --git a/tests/integration/view_test.go b/tests/integration/view_test.go index 7c5a2525ebc..30f5400c266 100644 --- a/tests/integration/view_test.go +++ b/tests/integration/view_test.go @@ -126,6 +126,6 @@ func testViewPageCurrentURL(t *testing.T) { currentURL, _ = ctx.Data["CurrentURL"].(string) }) defer web.RouteMockReset() - MakeRequest(t, NewRequest(t, "GET", "/any-page?k=v"), http.StatusNotFound) - assert.Equal(t, "/subpath/any-page?k=v", currentURL) + MakeRequest(t, NewRequest(t, "GET", "/user2?k=v"), http.StatusOK) + assert.Equal(t, "/subpath/user2?k=v", currentURL) }