eclipse/lib/gitcache/giturls.go

120 lines
2.2 KiB
Go

// Copyright (C) 2024 Umorpha Systems
// SPDX-License-Identifier: AGPL-3.0-or-later
package gitcache
import (
_url "net/url"
"path"
"path/filepath"
"regexp"
"strings"
)
// reIsURL mimics git's url.c:is_url()
var reIsURL = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9+.-]*://`)
// NormalizeURL parses a URL in accordance with the "GIT URLS"
// section of git-fetch(1), and normalizes it.
func NormalizeURL(url string) (string, bool) {
switch {
case reIsURL.MatchString(url):
u, err := _url.Parse(url)
if err != nil {
return "", false
}
// work this left-to-right
// 1. scheme
switch u.Scheme {
case "ssh",
"git",
"http", "https",
"ftp", "ftps",
"file":
// OK
default:
return "", false
}
// 2. userinfo
if u.User != nil {
if u.Scheme == "ssh" {
u.User = _url.User(u.User.Username())
} else {
u.User = nil
}
}
// 3. host[:port]
if u.Host == "" && u.Scheme != "file" {
return "", false
}
u.Host = strings.ToLower(u.Host)
// 4. path
u.Path = path.Clean(u.Path)
switch u.Path {
case ".", "/":
u.Path = ""
}
if u.Host == "" && u.Path == "" {
u.Path = "/"
}
// 5. query
switch u.Scheme {
case "http", "https":
// > Clients MUST strip a trailing `/`, if present, from the
// > user supplied `$GIT_URL` string
// -- gitprotocol-http(5)
//
// ... and that might include the query
u.RawQuery = strings.TrimRight(u.RawQuery, "/")
}
// 6. fragment
u.Fragment = ""
return u.String(), true
case filepath.IsAbs(url):
u := &_url.URL{
Scheme: "file",
Path: filepath.ToSlash(url),
}
url, ok := NormalizeURL(u.String())
if !ok {
panic("should not happen")
}
return url, true
default: // scp-like
uauth, upath, ok := strings.Cut(url, ":")
if !ok {
return "", false
}
if strings.Contains(uauth, "/") {
return "", false
}
if !path.IsAbs(upath) {
if strings.HasPrefix(upath, "~") {
upath = "/" + upath
} else {
upath = "/~/" + upath
}
}
u := &_url.URL{
Scheme: "ssh",
Path: path.Clean(upath),
}
atIdx := strings.LastIndex(uauth, "@")
if atIdx < 0 {
u.Host = uauth
} else {
u.User = _url.User(uauth[:atIdx])
u.Host = uauth[atIdx+1:]
}
return NormalizeURL(u.String())
}
}