From 54a19febc0c7c49caa014254cabab571abad60ab Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Sat, 05 Apr 2025 19:45:17 +0800 Subject: [PATCH] misc: Move url.go into the misc package --- http_handle_group_index.go | 3 ++- http_handle_repo_raw.go | 3 ++- http_server.go | 29 +++++++++++++++-------------- lmtp_server.go | 3 ++- remote_url.go | 6 ++++-- ssh_utils.go | 3 ++- url.go => misc/url.go | 42 +++++++++++++++++++++--------------------- diff --git a/http_handle_group_index.go b/http_handle_group_index.go index 67cffd82eba58e1ccd5bedb76b45e1052fbfe345..568a38e76e61569171e03723f265afd73d5b21f6 100644 --- a/http_handle_group_index.go +++ b/http_handle_group_index.go @@ -11,6 +11,7 @@ "strconv" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" + "go.lindenii.runxiyu.org/forge/misc" ) // httpHandleGroupIndex provides index pages for groups, which includes a list @@ -130,7 +131,7 @@ errorPage500(writer, params, "Error initializing repo: "+err.Error()) return } - redirectUnconditionally(writer, request) + misc.RedirectUnconditionally(writer, request) return } diff --git a/http_handle_repo_raw.go b/http_handle_repo_raw.go index ea2925c897f67f11f67648897ab921bc67e0ed5c..3a4e152fbb9af4a6dd2c7d2762af394fa7d15c61 100644 --- a/http_handle_repo_raw.go +++ b/http_handle_repo_raw.go @@ -10,6 +10,7 @@ "net/http" "strings" "go.lindenii.runxiyu.org/forge/git2c" + "go.lindenii.runxiyu.org/forge/misc" ) // httpHandleRepoRaw serves raw files, or directory listings that point to raw @@ -43,7 +44,7 @@ params["readme_filename"] = "README.md" params["readme"] = template.HTML("

README rendering here is WIP again

") // TODO renderTemplate(writer, "repo_raw_dir", params) case content != "": - if redirectNoDir(writer, request) { + if misc.RedirectNoDir(writer, request) { return } writer.Header().Set("Content-Type", "application/octet-stream") diff --git a/http_server.go b/http_server.go index 5d45d00df0e5e31a70a99464c632d41ab3a278b0..3f8e36cc2d9dec50674c927ba77c2f0c7fb0f1d6 100644 --- a/http_server.go +++ b/http_server.go @@ -12,6 +12,7 @@ "strconv" "strings" "github.com/jackc/pgx/v5" + "go.lindenii.runxiyu.org/forge/misc" ) type forgeHTTPRouter struct{} @@ -39,7 +40,7 @@ var err error var sepIndex int params := make(map[string]any) - if segments, _, err = parseReqURI(request.RequestURI); err != nil { + if segments, _, err = misc.ParseReqURI(request.RequestURI); err != nil { errorPage400(writer, params, "Error parsing request URI: "+err.Error()) return } @@ -82,7 +83,7 @@ if segments[0] == "-" { if len(segments) < 2 { errorPage404(writer, params) return - } else if len(segments) == 2 && redirectDir(writer, request) { + } else if len(segments) == 2 && misc.RedirectDir(writer, request) { return } @@ -133,7 +134,7 @@ params["group_path"] = groupPath switch { case sepIndex == -1: - if redirectDir(writer, request) { + if misc.RedirectDir(writer, request) { return } httpHandleGroupIndex(writer, request, params) @@ -165,8 +166,8 @@ return } } - if params["ref_type"], params["ref_name"], err = getParamRefTypeName(request); err != nil { - if errors.Is(err, errNoRefSpec) { + 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()) @@ -189,7 +190,7 @@ params["http_clone_url"] = genHTTPRemoteURL(groupPath, moduleName) params["ssh_clone_url"] = genSSHRemoteURL(groupPath, moduleName) if len(segments) == sepIndex+3 { - if redirectDir(writer, request) { + if misc.RedirectDir(writer, request) { return } httpHandleRepoIndex(writer, request, params) @@ -199,7 +200,7 @@ repoFeature := segments[sepIndex+3] switch repoFeature { case "tree": - if anyContain(segments[sepIndex+4:], "/") { + if misc.AnyContain(segments[sepIndex+4:], "/") { errorPage400(writer, params, "Repo tree paths may not contain slashes in any segments") return } @@ -208,18 +209,18 @@ params["rest"] = strings.Join(segments[sepIndex+4:], "/") + "/" } else { params["rest"] = strings.Join(segments[sepIndex+4:], "/") } - if len(segments) < sepIndex+5 && redirectDir(writer, request) { + if len(segments) < sepIndex+5 && misc.RedirectDir(writer, request) { return } httpHandleRepoTree(writer, request, params) case "branches": - if redirectDir(writer, request) { + if misc.RedirectDir(writer, request) { return } httpHandleRepoBranches(writer, request, params) return case "raw": - if anyContain(segments[sepIndex+4:], "/") { + if misc.AnyContain(segments[sepIndex+4:], "/") { errorPage400(writer, params, "Repo tree paths may not contain slashes in any segments") return } @@ -228,7 +229,7 @@ params["rest"] = strings.Join(segments[sepIndex+4:], "/") + "/" } else { params["rest"] = strings.Join(segments[sepIndex+4:], "/") } - if len(segments) < sepIndex+5 && redirectDir(writer, request) { + if len(segments) < sepIndex+5 && misc.RedirectDir(writer, request) { return } httpHandleRepoRaw(writer, request, params) @@ -237,7 +238,7 @@ if len(segments) > sepIndex+4 { errorPage400(writer, params, "Too many parameters") return } - if redirectDir(writer, request) { + if misc.RedirectDir(writer, request) { return } httpHandleRepoLog(writer, request, params) @@ -246,13 +247,13 @@ if len(segments) != sepIndex+5 { errorPage400(writer, params, "Incorrect number of parameters") return } - if redirectNoDir(writer, request) { + if misc.RedirectNoDir(writer, request) { return } params["commit_id"] = segments[sepIndex+4] httpHandleRepoCommit(writer, request, params) case "contrib": - if redirectDir(writer, request) { + if misc.RedirectDir(writer, request) { return } switch len(segments) { diff --git a/lmtp_server.go b/lmtp_server.go index cdfcffbb6a7214a82797f872248e4ab6f94bae5c..fc3d92d5e51fcb8c98dcf5328dd1bc7c59113e59 100644 --- a/lmtp_server.go +++ b/lmtp_server.go @@ -17,6 +17,7 @@ "time" "github.com/emersion/go-message" "github.com/emersion/go-smtp" + "go.lindenii.runxiyu.org/forge/misc" ) type lmtpHandler struct{} @@ -136,7 +137,7 @@ continue } localPart := to[:len(to)-len("@"+config.LMTP.Domain)] var segments []string - segments, err = pathToSegments(localPart) + segments, err = misc.PathToSegments(localPart) if err != nil { // TODO: Should the entire email fail or should we just // notify them out of band? diff --git a/remote_url.go b/remote_url.go index 5c980f5d5cadec1e1aa8bec2adae24abe7d85146..f227dbf5ce953b1110bdbf6ba6b3219e1c960483 100644 --- a/remote_url.go +++ b/remote_url.go @@ -6,6 +6,8 @@ import ( "net/url" "strings" + + "go.lindenii.runxiyu.org/forge/misc" ) // We don't use path.Join because it collapses multiple slashes into one. @@ -13,11 +15,11 @@ // genSSHRemoteURL generates SSH remote URLs from a given group path and repo // name. func genSSHRemoteURL(groupPath []string, repoName string) string { - return strings.TrimSuffix(config.SSH.Root, "/") + "/" + segmentsToURL(groupPath) + "/-/repos/" + url.PathEscape(repoName) + return strings.TrimSuffix(config.SSH.Root, "/") + "/" + misc.SegmentsToURL(groupPath) + "/-/repos/" + url.PathEscape(repoName) } // genHTTPRemoteURL generates HTTP remote URLs from a given group path and repo // name. func genHTTPRemoteURL(groupPath []string, repoName string) string { - return strings.TrimSuffix(config.HTTP.Root, "/") + "/" + segmentsToURL(groupPath) + "/-/repos/" + url.PathEscape(repoName) + return strings.TrimSuffix(config.HTTP.Root, "/") + "/" + misc.SegmentsToURL(groupPath) + "/-/repos/" + url.PathEscape(repoName) } diff --git a/ssh_utils.go b/ssh_utils.go index 476fc313a5d10ce0be314542f501bad473f5bf66..c906ab3514bcb5477ecd295765498e5203ee161d 100644 --- a/ssh_utils.go +++ b/ssh_utils.go @@ -11,6 +11,7 @@ "io" "net/url" "go.lindenii.runxiyu.org/forge/ansiec" + "go.lindenii.runxiyu.org/forge/misc" ) var errIllegalSSHRepoPath = errors.New("illegal SSH repo path") @@ -22,7 +23,7 @@ var segments []string var sepIndex int var moduleType, moduleName string - segments, err = pathToSegments(sshPath) + segments, err = misc.PathToSegments(sshPath) if err != nil { return } diff --git a/url.go b/misc/url.go rename from url.go rename to misc/url.go index ad5c8bb51c69b4962d216a93792c3bc2dac0199f..b77d8ce0a667fdc97cf1f84b02d038a9b77e74f0 100644 --- a/url.go +++ b/misc/url.go @@ -1,7 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-only // SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu -package main +package misc import ( "errors" @@ -11,13 +11,13 @@ "strings" ) var ( - errDupRefSpec = errors.New("duplicate ref spec") - errNoRefSpec = errors.New("no ref spec") + ErrDupRefSpec = errors.New("duplicate ref spec") + ErrNoRefSpec = errors.New("no ref spec") ) // getParamRefTypeName looks at the query parameters in an HTTP request and // returns its ref name and type, if any. -func getParamRefTypeName(request *http.Request) (retRefType, retRefName string, err error) { +func GetParamRefTypeName(request *http.Request) (retRefType, retRefName string, err error) { rawQuery := request.URL.RawQuery queryValues, err := url.ParseQuery(rawQuery) if err != nil { @@ -28,12 +28,12 @@ for _, refType := range []string{"commit", "branch", "tag"} { refName, ok := queryValues[refType] if ok { if done { - err = errDupRefSpec + err = ErrDupRefSpec return } done = true if len(refName) != 1 { - err = errDupRefSpec + err = ErrDupRefSpec return } retRefName = refName[0] @@ -41,17 +41,17 @@ retRefType = refType } } if !done { - err = errNoRefSpec + err = ErrNoRefSpec } return } -// parseReqURI parses an HTTP request URL, and returns a slice of path segments +// ParseReqURI parses an HTTP request URL, and returns a slice of path segments // and the query parameters. It handles %2F correctly. -func parseReqURI(requestURI string) (segments []string, params url.Values, err error) { +func ParseReqURI(requestURI string) (segments []string, params url.Values, err error) { path, paramsStr, _ := strings.Cut(requestURI, "?") - segments, err = pathToSegments(path) + segments, err = PathToSegments(path) if err != nil { return } @@ -60,7 +60,7 @@ params, err = url.ParseQuery(paramsStr) return } -func pathToSegments(path string) (segments []string, err error) { +func PathToSegments(path string) (segments []string, err error) { segments = strings.Split(strings.TrimPrefix(path, "/"), "/") for i, segment := range segments { @@ -73,10 +73,10 @@ return } -// redirectDir returns true and redirects the user to a version of the URL with +// RedirectDir returns true and redirects the user to a version of the URL with // a trailing slash, if and only if the request URL does not already have a // trailing slash. -func redirectDir(writer http.ResponseWriter, request *http.Request) bool { +func RedirectDir(writer http.ResponseWriter, request *http.Request) bool { requestURI := request.RequestURI pathEnd := strings.IndexAny(requestURI, "?#") @@ -95,10 +95,10 @@ } return false } -// redirectNoDir returns true and redirects the user to a version of the URL +// RedirectNoDir returns true and redirects the user to a version of the URL // without a trailing slash, if and only if the request URL has a trailing // slash. -func redirectNoDir(writer http.ResponseWriter, request *http.Request) bool { +func RedirectNoDir(writer http.ResponseWriter, request *http.Request) bool { requestURI := request.RequestURI pathEnd := strings.IndexAny(requestURI, "?#") @@ -117,9 +117,9 @@ } return false } -// redirectUnconditionally unconditionally redirects the user back to the +// RedirectUnconditionally unconditionally redirects the user back to the // current page while preserving query parameters. -func redirectUnconditionally(writer http.ResponseWriter, request *http.Request) { +func RedirectUnconditionally(writer http.ResponseWriter, request *http.Request) { requestURI := request.RequestURI pathEnd := strings.IndexAny(requestURI, "?#") @@ -134,17 +134,17 @@ http.Redirect(writer, request, path+rest, http.StatusSeeOther) } -// segmentsToURL joins URL segments to the path component of a URL. +// SegmentsToURL joins URL segments to the path component of a URL. // Each segment is escaped properly first. -func segmentsToURL(segments []string) string { +func SegmentsToURL(segments []string) string { for i, segment := range segments { segments[i] = url.PathEscape(segment) } return strings.Join(segments, "/") } -// anyContain returns true if and only if ss contains a string that contains c. -func anyContain(ss []string, c string) bool { +// AnyContain returns true if and only if ss contains a string that contains c. +func AnyContain(ss []string, c string) bool { for _, s := range ss { if strings.Contains(s, c) { return true -- 2.48.1