From edc30e6d36b51f73d2db31e6fbc55f86e8ca451f Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Sat, 05 Apr 2025 23:18:30 +0800 Subject: [PATCH] web: Separate HTTP error pages into its own package --- http_error_page.go | 47 ----------------------------------------------- http_handle_group_index.go | 29 +++++++++++++++-------------- http_handle_index.go | 3 ++- http_handle_login.go | 9 +++++---- http_handle_repo_commit.go | 7 ++++--- http_handle_repo_contrib_index.go | 7 ++++--- http_handle_repo_contrib_one.go | 19 ++++++++++--------- http_handle_repo_index.go | 5 +++-- http_handle_repo_log.go | 5 +++-- http_handle_repo_raw.go | 7 ++++--- http_handle_repo_tree.go | 7 ++++--- http_handle_users.go | 4 +++- http_server.go | 37 +++++++++++++++++++------------------ internal/web/error_pages.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/http_error_page.go b/http_error_page.go deleted file mode 100644 index 0cce72e82577782a70f7c173cdf98a255755daa1..0000000000000000000000000000000000000000 --- a/http_error_page.go +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -// SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu - -package forge - -import ( - "net/http" -) - -func errorPage404(w http.ResponseWriter, params map[string]any) { - w.WriteHeader(http.StatusNotFound) - _ = templates.ExecuteTemplate(w, "404", params) -} - -func errorPage400(w http.ResponseWriter, params map[string]any, msg string) { - w.WriteHeader(http.StatusBadRequest) - params["complete_error_msg"] = msg - _ = templates.ExecuteTemplate(w, "400", params) -} - -func errorPage400Colon(w http.ResponseWriter, params map[string]any) { - w.WriteHeader(http.StatusBadRequest) - _ = templates.ExecuteTemplate(w, "400_colon", params) -} - -func errorPage403(w http.ResponseWriter, params map[string]any, msg string) { - w.WriteHeader(http.StatusForbidden) - params["complete_error_msg"] = msg - _ = templates.ExecuteTemplate(w, "403", params) -} - -func errorPage451(w http.ResponseWriter, params map[string]any, msg string) { - w.WriteHeader(http.StatusUnavailableForLegalReasons) - params["complete_error_msg"] = msg - _ = templates.ExecuteTemplate(w, "451", params) -} - -func errorPage500(w http.ResponseWriter, params map[string]any, msg string) { - w.WriteHeader(http.StatusInternalServerError) - params["complete_error_msg"] = msg - _ = templates.ExecuteTemplate(w, "500", params) -} - -func errorPage501(w http.ResponseWriter, params map[string]any) { - w.WriteHeader(http.StatusNotImplemented) - _ = templates.ExecuteTemplate(w, "501", params) -} diff --git a/http_handle_group_index.go b/http_handle_group_index.go index a607ba26e57666a85b8ebcbc1a175131d765c59c..63bb164d918984761dbe3574f5be7b66e54363c4 100644 --- a/http_handle_group_index.go +++ b/http_handle_group_index.go @@ -13,6 +13,7 @@ "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" "go.lindenii.runxiyu.org/forge/internal/misc" + "go.lindenii.runxiyu.org/forge/internal/web" ) // httpHandleGroupIndex provides index pages for groups, which includes a list @@ -61,10 +62,10 @@ pgtype.FlatArray[string](groupPath), ).Scan(&groupID, &groupDesc) if errors.Is(err, pgx.ErrNoRows) { - errorPage404(writer, params) + web.ErrorPage404(templates, writer, params) return } else if err != nil { - errorPage500(writer, params, "Error getting group: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting group: "+err.Error()) return } @@ -77,14 +78,14 @@ WHERE user_id = $1 AND group_id = $2 `, params["user_id"].(int), groupID).Scan(&count) if err != nil { - errorPage500(writer, params, "Error checking access: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error checking access: "+err.Error()) return } directAccess := (count > 0) if request.Method == http.MethodPost { if !directAccess { - errorPage403(writer, params, "You do not have direct access to this group") + web.ErrorPage403(templates, writer, params, "You do not have direct access to this group") return } @@ -92,7 +93,7 @@ repoName := request.FormValue("repo_name") repoDesc := request.FormValue("repo_desc") contribReq := request.FormValue("repo_contrib") if repoName == "" { - errorPage400(writer, params, "Repo name is required") + web.ErrorPage400(templates, writer, params, "Repo name is required") return } @@ -108,7 +109,7 @@ groupID, contribReq, ).Scan(&newRepoID) if err != nil { - errorPage500(writer, params, "Error creating repo: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error creating repo: "+err.Error()) return } @@ -123,12 +124,12 @@ filePath, newRepoID, ) if err != nil { - errorPage500(writer, params, "Error updating repo path: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error updating repo path: "+err.Error()) return } if err = s.gitInit(filePath); err != nil { - errorPage500(writer, params, "Error initializing repo: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error initializing repo: "+err.Error()) return } @@ -144,7 +145,7 @@ FROM repos WHERE group_id = $1 `, groupID) if err != nil { - errorPage500(writer, params, "Error getting repos: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting repos: "+err.Error()) return } defer rows.Close() @@ -152,13 +153,13 @@ for rows.Next() { var name, description string if err = rows.Scan(&name, &description); err != nil { - errorPage500(writer, params, "Error getting repos: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting repos: "+err.Error()) return } repos = append(repos, nameDesc{name, description}) } if err = rows.Err(); err != nil { - errorPage500(writer, params, "Error getting repos: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting repos: "+err.Error()) return } @@ -169,7 +170,7 @@ FROM groups WHERE parent_group = $1 `, groupID) if err != nil { - errorPage500(writer, params, "Error getting subgroups: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting subgroups: "+err.Error()) return } defer rows.Close() @@ -177,13 +178,13 @@ for rows.Next() { var name, description string if err = rows.Scan(&name, &description); err != nil { - errorPage500(writer, params, "Error getting subgroups: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting subgroups: "+err.Error()) return } subgroups = append(subgroups, nameDesc{name, description}) } if err = rows.Err(); err != nil { - errorPage500(writer, params, "Error getting subgroups: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting subgroups: "+err.Error()) return } diff --git a/http_handle_index.go b/http_handle_index.go index a519a5a7099e1de29de74181e508261e498b8497..a1ecfe4db09ebfe3e341274718bf260aa5535c54 100644 --- a/http_handle_index.go +++ b/http_handle_index.go @@ -8,6 +8,7 @@ "net/http" "runtime" "github.com/dustin/go-humanize" + "go.lindenii.runxiyu.org/forge/internal/web" ) // httpHandleIndex provides the main index page which includes a list of groups @@ -18,7 +19,7 @@ var groups []nameDesc groups, err = s.queryNameDesc(request.Context(), "SELECT name, COALESCE(description, '') FROM groups WHERE parent_group IS NULL") if err != nil { - errorPage500(writer, params, "Error querying groups: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error querying groups: "+err.Error()) return } params["groups"] = groups diff --git a/http_handle_login.go b/http_handle_login.go index e6267190e65f0aece20b5d9c9cd53cc620b4501c..dfb74c8b0cd12c5c38a0b35ce2dfb2db865a5c97 100644 --- a/http_handle_login.go +++ b/http_handle_login.go @@ -13,6 +13,7 @@ "time" "github.com/alexedwards/argon2id" "github.com/jackc/pgx/v5" + "go.lindenii.runxiyu.org/forge/internal/web" ) // httpHandleLogin provides the login page for local users. @@ -45,7 +46,7 @@ params["login_error"] = "Unknown username" renderTemplate(writer, "login", params) return } - errorPage500(writer, params, "Error querying user information: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error querying user information: "+err.Error()) return } if passwordHash == "" { @@ -55,7 +56,7 @@ return } if passwordMatches, err = argon2id.ComparePasswordAndHash(password, passwordHash); err != nil { - errorPage500(writer, params, "Error comparing password and hash: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error comparing password and hash: "+err.Error()) return } @@ -66,7 +67,7 @@ return } if cookieValue, err = randomUrlsafeStr(16); err != nil { - errorPage500(writer, params, "Error getting random string: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting random string: "+err.Error()) return } @@ -87,7 +88,7 @@ http.SetCookie(writer, &cookie) _, err = s.database.Exec(request.Context(), "INSERT INTO sessions (user_id, session_id) VALUES ($1, $2)", userID, cookieValue) if err != nil { - errorPage500(writer, params, "Error inserting session: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error inserting session: "+err.Error()) return } diff --git a/http_handle_repo_commit.go b/http_handle_repo_commit.go index 1042affa76e15b7e69dbf8c4698451f300754ca8..c348dca590b3e0bcbcf16a9b4c82f33195f0806b 100644 --- a/http_handle_repo_commit.go +++ b/http_handle_repo_commit.go @@ -14,6 +14,7 @@ "github.com/go-git/go-git/v5/plumbing/filemode" "github.com/go-git/go-git/v5/plumbing/format/diff" "github.com/go-git/go-git/v5/plumbing/object" "go.lindenii.runxiyu.org/forge/internal/misc" + "go.lindenii.runxiyu.org/forge/internal/web" ) // usableFilePatch is a [diff.FilePatch] that is structured in a way more @@ -46,13 +47,13 @@ commitIDStrSpecNoSuffix = strings.TrimSuffix(commitIDStrSpec, ".patch") commitID = plumbing.NewHash(commitIDStrSpecNoSuffix) if commitObj, err = repo.CommitObject(commitID); err != nil { - errorPage500(writer, params, "Error getting commit object: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting commit object: "+err.Error()) return } if commitIDStrSpecNoSuffix != commitIDStrSpec { var patchStr string if patchStr, err = fmtCommitPatch(commitObj); err != nil { - errorPage500(writer, params, "Error formatting patch: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error formatting patch: "+err.Error()) return } fmt.Fprintln(writer, patchStr) @@ -70,7 +71,7 @@ params["commit_id"] = commitIDStr parentCommitHash, patch, err = commitToPatch(commitObj) if err != nil { - errorPage500(writer, params, "Error getting patch from commit: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting patch from commit: "+err.Error()) return } params["parent_commit_hash"] = parentCommitHash.String() diff --git a/http_handle_repo_contrib_index.go b/http_handle_repo_contrib_index.go index a4b1eacabcf00b7ddbd4013f381dc81cad5bd184..b83dfcb11832738a6a82e13ff5773c5607973f92 100644 --- a/http_handle_repo_contrib_index.go +++ b/http_handle_repo_contrib_index.go @@ -7,6 +7,7 @@ import ( "net/http" "github.com/jackc/pgx/v5" + "go.lindenii.runxiyu.org/forge/internal/web" ) // idTitleStatus describes properties of a merge request that needs to be @@ -27,7 +28,7 @@ if rows, err = s.database.Query(request.Context(), "SELECT repo_local_id, COALESCE(title, 'Untitled'), status FROM merge_requests WHERE repo_id = $1", params["repo_id"], ); err != nil { - errorPage500(writer, params, "Error querying merge requests: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error querying merge requests: "+err.Error()) return } defer rows.Close() @@ -36,13 +37,13 @@ for rows.Next() { var mrID int var mrTitle, mrStatus string if err = rows.Scan(&mrID, &mrTitle, &mrStatus); err != nil { - errorPage500(writer, params, "Error scanning merge request: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error scanning merge request: "+err.Error()) return } result = append(result, idTitleStatus{mrID, mrTitle, mrStatus}) } if err = rows.Err(); err != nil { - errorPage500(writer, params, "Error ranging over merge requests: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error ranging over merge requests: "+err.Error()) return } params["merge_requests"] = result diff --git a/http_handle_repo_contrib_one.go b/http_handle_repo_contrib_one.go index 55af74c759bbe9355637bcf4e4c1eef0e6e99f25..dac58d0afa1b6f1967367a9b4a431375f3b3daca 100644 --- a/http_handle_repo_contrib_one.go +++ b/http_handle_repo_contrib_one.go @@ -10,6 +10,7 @@ "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" + "go.lindenii.runxiyu.org/forge/internal/web" ) // httpHandleRepoContribOne provides an interface to each merge request of a @@ -28,7 +29,7 @@ mrIDStr = params["mr_id"].(string) mrIDInt64, err := strconv.ParseInt(mrIDStr, 10, strconv.IntSize) if err != nil { - errorPage400(writer, params, "Merge request ID not an integer") + web.ErrorPage400(templates, writer, params, "Merge request ID not an integer") return } mrIDInt = int(mrIDInt64) @@ -37,18 +38,18 @@ if err = s.database.QueryRow(request.Context(), "SELECT COALESCE(title, ''), status, source_ref, COALESCE(destination_branch, '') FROM merge_requests WHERE repo_id = $1 AND repo_local_id = $2", params["repo_id"], mrIDInt, ).Scan(&title, &status, &srcRefStr, &dstBranchStr); err != nil { - errorPage500(writer, params, "Error querying merge request: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error querying merge request: "+err.Error()) return } repo = params["repo"].(*git.Repository) if srcRefHash, err = getRefHash(repo, "branch", srcRefStr); err != nil { - errorPage500(writer, params, "Error getting source ref hash: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting source ref hash: "+err.Error()) return } if srcCommit, err = repo.CommitObject(srcRefHash); err != nil { - errorPage500(writer, params, "Error getting source commit: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting source commit: "+err.Error()) return } params["source_commit"] = srcCommit @@ -60,23 +61,23 @@ } else { dstBranchHash, err = getRefHash(repo, "branch", dstBranchStr) } if err != nil { - errorPage500(writer, params, "Error getting destination branch hash: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting destination branch hash: "+err.Error()) return } if dstCommit, err = repo.CommitObject(dstBranchHash); err != nil { - errorPage500(writer, params, "Error getting destination commit: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting destination commit: "+err.Error()) return } params["destination_commit"] = dstCommit if mergeBases, err = srcCommit.MergeBase(dstCommit); err != nil { - errorPage500(writer, params, "Error getting merge base: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting merge base: "+err.Error()) return } if len(mergeBases) < 1 { - errorPage500(writer, params, "No merge base found for this merge request; these two branches do not share any common history") + web.ErrorPage500(templates, writer, params, "No merge base found for this merge request; these two branches do not share any common history") // TODO return } @@ -86,7 +87,7 @@ params["merge_base"] = mergeBaseCommit patch, err := mergeBaseCommit.Patch(srcCommit) if err != nil { - errorPage500(writer, params, "Error getting patch: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting patch: "+err.Error()) return } params["file_patches"] = makeUsableFilePatches(patch) diff --git a/http_handle_repo_index.go b/http_handle_repo_index.go index d28311b8e3a4e544703b209e97f6bf9178422afb..567f329a4422df633f103be75a28484acafd6fb0 100644 --- a/http_handle_repo_index.go +++ b/http_handle_repo_index.go @@ -8,6 +8,7 @@ "net/http" "go.lindenii.runxiyu.org/forge/internal/git2c" "go.lindenii.runxiyu.org/forge/internal/render" + "go.lindenii.runxiyu.org/forge/internal/web" ) type commitDisplay struct { @@ -27,14 +28,14 @@ _, repoPath, _, _, _, _, _ := s.getRepoInfo(req.Context(), groupPath, repoName, "") // TODO: Don't use getRepoInfo client, err := git2c.NewClient(s.config.Git.Socket) if err != nil { - errorPage500(w, params, err.Error()) + web.ErrorPage500(templates, w, params, err.Error()) return } defer client.Close() commits, readme, err := client.Cmd1(repoPath) if err != nil { - errorPage500(w, params, err.Error()) + web.ErrorPage500(templates, w, params, err.Error()) return } diff --git a/http_handle_repo_log.go b/http_handle_repo_log.go index b104491e3273589a4a1817a09162d6c76482dd8b..14fe84c9ee80fc1b9d93270ad9b8e0a3dd8b33fe 100644 --- a/http_handle_repo_log.go +++ b/http_handle_repo_log.go @@ -8,6 +8,7 @@ "net/http" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" + "go.lindenii.runxiyu.org/forge/internal/web" ) // httpHandleRepoLog provides a page with a complete Git log. @@ -22,14 +23,14 @@ repo = params["repo"].(*git.Repository) if refHash, err = getRefHash(repo, params["ref_type"].(string), params["ref_name"].(string)); err != nil { - errorPage500(writer, params, "Error getting ref hash: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting ref hash: "+err.Error()) return } logOptions := git.LogOptions{From: refHash} //exhaustruct:ignore commitIter, err := repo.Log(&logOptions) if err != nil { - errorPage500(writer, params, "Error getting recent commits: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting recent commits: "+err.Error()) return } params["commits"], params["commits_err"] = commitIterSeqErr(commitIter) diff --git a/http_handle_repo_raw.go b/http_handle_repo_raw.go index 0407574e5e4d7dad8e6c81725e5e8697c3fe9cb4..c7f5653c53b3d8af7f08fc3a7137365b9e1a106a 100644 --- a/http_handle_repo_raw.go +++ b/http_handle_repo_raw.go @@ -11,6 +11,7 @@ "strings" "go.lindenii.runxiyu.org/forge/internal/git2c" "go.lindenii.runxiyu.org/forge/internal/misc" + "go.lindenii.runxiyu.org/forge/internal/web" ) // httpHandleRepoRaw serves raw files, or directory listings that point to raw @@ -26,14 +27,14 @@ _, repoPath, _, _, _, _, _ := s.getRepoInfo(request.Context(), groupPath, repoName, "") client, err := git2c.NewClient(s.config.Git.Socket) if err != nil { - errorPage500(writer, params, err.Error()) + web.ErrorPage500(templates, writer, params, err.Error()) return } defer client.Close() files, content, err := client.Cmd2(repoPath, pathSpec) if err != nil { - errorPage500(writer, params, err.Error()) + web.ErrorPage500(templates, writer, params, err.Error()) return } @@ -50,6 +51,6 @@ } writer.Header().Set("Content-Type", "application/octet-stream") fmt.Fprint(writer, content) default: - errorPage500(writer, params, "Unknown error fetching repo raw data") + web.ErrorPage500(templates, writer, params, "Unknown error fetching repo raw data") } } diff --git a/http_handle_repo_tree.go b/http_handle_repo_tree.go index 7667435ce5ffdd0abe94eb3f67257e0e864cbbfa..b855fe454b65cbb77a3950f461697f44c5eaefe0 100644 --- a/http_handle_repo_tree.go +++ b/http_handle_repo_tree.go @@ -10,6 +10,7 @@ "strings" "go.lindenii.runxiyu.org/forge/internal/git2c" "go.lindenii.runxiyu.org/forge/internal/render" + "go.lindenii.runxiyu.org/forge/internal/web" ) // httpHandleRepoTree provides a friendly, syntax-highlighted view of @@ -27,14 +28,14 @@ _, repoPath, _, _, _, _, _ := s.getRepoInfo(request.Context(), groupPath, repoName, "") client, err := git2c.NewClient(s.config.Git.Socket) if err != nil { - errorPage500(writer, params, err.Error()) + web.ErrorPage500(templates, writer, params, err.Error()) return } defer client.Close() files, content, err := client.Cmd2(repoPath, pathSpec) if err != nil { - errorPage500(writer, params, err.Error()) + web.ErrorPage500(templates, writer, params, err.Error()) return } @@ -49,6 +50,6 @@ rendered := render.Highlight(pathSpec, content) params["file_contents"] = rendered renderTemplate(writer, "repo_tree_file", params) default: - errorPage500(writer, params, "Unknown object type, something is seriously wrong") + web.ErrorPage500(templates, writer, params, "Unknown object type, something is seriously wrong") } } diff --git a/http_handle_users.go b/http_handle_users.go index d3796247f444eca05433ec9e25993bf94337f8ad..ce6c0457d784d731aab8f987a61388409d3b641b 100644 --- a/http_handle_users.go +++ b/http_handle_users.go @@ -5,9 +5,11 @@ package forge import ( "net/http" + + "go.lindenii.runxiyu.org/forge/internal/web" ) // httpHandleUsers is a useless stub. func httpHandleUsers(writer http.ResponseWriter, _ *http.Request, params map[string]any) { - errorPage501(writer, params) + web.ErrorPage501(templates, writer, params) } diff --git a/http_server.go b/http_server.go index f5f63283ff74fee938a604ee263ca84b273ac5b2..b2c93b94fb8dd9e6b1a36cf47ea2580166ff9f47 100644 --- a/http_server.go +++ b/http_server.go @@ -13,6 +13,7 @@ "strings" "github.com/jackc/pgx/v5" "go.lindenii.runxiyu.org/forge/internal/misc" + "go.lindenii.runxiyu.org/forge/internal/web" ) // ServeHTTP handles all incoming HTTP requests and routes them to the correct @@ -39,7 +40,7 @@ var sepIndex int params := make(map[string]any) if segments, _, err = misc.ParseReqURI(request.RequestURI); err != nil { - errorPage400(writer, params, "Error parsing request URI: "+err.Error()) + web.ErrorPage400(templates, writer, params, "Error parsing request URI: "+err.Error()) return } dirMode := false @@ -55,7 +56,7 @@ var userID int // 0 for none userID, params["username"], err = s.getUserFromRequest(request) params["user_id"] = userID if err != nil && !errors.Is(err, http.ErrNoCookie) && !errors.Is(err, pgx.ErrNoRows) { - errorPage500(writer, params, "Error getting user info from request: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error getting user info from request: "+err.Error()) return } @@ -67,7 +68,7 @@ } for _, v := range segments { if strings.Contains(v, ":") { - errorPage400Colon(writer, params) + web.ErrorPage400Colon(templates, writer, params) return } } @@ -79,7 +80,7 @@ } if segments[0] == "-" { if len(segments) < 2 { - errorPage404(writer, params) + web.ErrorPage404(templates, writer, params) return } else if len(segments) == 2 && misc.RedirectDir(writer, request) { return @@ -104,7 +105,7 @@ case "users": httpHandleUsers(writer, request, params) return default: - errorPage404(writer, params) + web.ErrorPage404(templates, writer, params) return } } @@ -137,10 +138,10 @@ return } s.httpHandleGroupIndex(writer, request, params) case len(segments) == sepIndex+1: - errorPage404(writer, params) + web.ErrorPage404(templates, writer, params) return case len(segments) == sepIndex+2: - errorPage404(writer, params) + web.ErrorPage404(templates, writer, params) return default: moduleType = segments[sepIndex+1] @@ -153,12 +154,12 @@ if len(segments) > sepIndex+3 { switch segments[sepIndex+3] { case "info": if err = s.httpHandleRepoInfo(writer, request, params); err != nil { - errorPage500(writer, params, err.Error()) + web.ErrorPage500(templates, writer, params, err.Error()) } return case "git-upload-pack": if err = s.httpHandleUploadPack(writer, request, params); err != nil { - errorPage500(writer, params, err.Error()) + web.ErrorPage500(templates, writer, params, err.Error()) } return } @@ -168,13 +169,13 @@ if params["ref_type"], params["ref_name"], err = misc.GetParamRefTypeName(request); err != nil { if errors.Is(err, misc.ErrNoRefSpec) { params["ref_type"] = "" } else { - errorPage400(writer, params, "Error querying ref type: "+err.Error()) + web.ErrorPage400(templates, writer, params, "Error querying ref type: "+err.Error()) return } } if params["repo"], params["repo_description"], params["repo_id"], _, err = s.openRepo(request.Context(), groupPath, moduleName); err != nil { - errorPage500(writer, params, "Error opening repo: "+err.Error()) + web.ErrorPage500(templates, writer, params, "Error opening repo: "+err.Error()) return } @@ -199,7 +200,7 @@ repoFeature := segments[sepIndex+3] switch repoFeature { case "tree": if misc.AnyContain(segments[sepIndex+4:], "/") { - errorPage400(writer, params, "Repo tree paths may not contain slashes in any segments") + web.ErrorPage400(templates, writer, params, "Repo tree paths may not contain slashes in any segments") return } if dirMode { @@ -219,7 +220,7 @@ s.httpHandleRepoBranches(writer, request, params) return case "raw": if misc.AnyContain(segments[sepIndex+4:], "/") { - errorPage400(writer, params, "Repo tree paths may not contain slashes in any segments") + web.ErrorPage400(templates, writer, params, "Repo tree paths may not contain slashes in any segments") return } if dirMode { @@ -233,7 +234,7 @@ } s.httpHandleRepoRaw(writer, request, params) case "log": if len(segments) > sepIndex+4 { - errorPage400(writer, params, "Too many parameters") + web.ErrorPage400(templates, writer, params, "Too many parameters") return } if misc.RedirectDir(writer, request) { @@ -242,7 +243,7 @@ } httpHandleRepoLog(writer, request, params) case "commit": if len(segments) != sepIndex+5 { - errorPage400(writer, params, "Incorrect number of parameters") + web.ErrorPage400(templates, writer, params, "Incorrect number of parameters") return } if misc.RedirectNoDir(writer, request) { @@ -261,14 +262,14 @@ case sepIndex + 5: params["mr_id"] = segments[sepIndex+4] s.httpHandleRepoContribOne(writer, request, params) default: - errorPage400(writer, params, "Too many parameters") + web.ErrorPage400(templates, writer, params, "Too many parameters") } default: - errorPage404(writer, params) + web.ErrorPage404(templates, writer, params) return } default: - errorPage404(writer, params) + web.ErrorPage404(templates, writer, params) return } } diff --git a/internal/web/error_pages.go b/internal/web/error_pages.go new file mode 100644 index 0000000000000000000000000000000000000000..200e9d371c0391f6fdc53784c509b1e4f2eb3b77 --- /dev/null +++ b/internal/web/error_pages.go @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-only +// SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu + +package web + +import ( + "html/template" + "net/http" +) + +func ErrorPage404(templates *template.Template, w http.ResponseWriter, params map[string]any) { + w.WriteHeader(http.StatusNotFound) + _ = templates.ExecuteTemplate(w, "404", params) +} + +func ErrorPage400(templates *template.Template, w http.ResponseWriter, params map[string]any, msg string) { + w.WriteHeader(http.StatusBadRequest) + params["complete_error_msg"] = msg + _ = templates.ExecuteTemplate(w, "400", params) +} + +func ErrorPage400Colon(templates *template.Template, w http.ResponseWriter, params map[string]any) { + w.WriteHeader(http.StatusBadRequest) + _ = templates.ExecuteTemplate(w, "400_colon", params) +} + +func ErrorPage403(templates *template.Template, w http.ResponseWriter, params map[string]any, msg string) { + w.WriteHeader(http.StatusForbidden) + params["complete_error_msg"] = msg + _ = templates.ExecuteTemplate(w, "403", params) +} + +func ErrorPage451(templates *template.Template, w http.ResponseWriter, params map[string]any, msg string) { + w.WriteHeader(http.StatusUnavailableForLegalReasons) + params["complete_error_msg"] = msg + _ = templates.ExecuteTemplate(w, "451", params) +} + +func ErrorPage500(templates *template.Template, w http.ResponseWriter, params map[string]any, msg string) { + w.WriteHeader(http.StatusInternalServerError) + params["complete_error_msg"] = msg + _ = templates.ExecuteTemplate(w, "500", params) +} + +func ErrorPage501(templates *template.Template, w http.ResponseWriter, params map[string]any) { + w.WriteHeader(http.StatusNotImplemented) + _ = templates.ExecuteTemplate(w, "501", params) +} -- 2.48.1