mirror of
https://github.com/makeworld-the-better-one/amfora.git
synced 2024-11-29 03:52:51 +03:00
eab0a6a626
Fixes #115
103 lines
2.8 KiB
Go
103 lines
2.8 KiB
Go
package client
|
|
|
|
// Functions that transform and normalize URLs
|
|
// Originally used to be in display/util.go
|
|
// Moved here for #115, so URLs in the [auth] config section could be normalized
|
|
|
|
import (
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/makeworld-the-better-one/go-gemini"
|
|
"golang.org/x/text/unicode/norm"
|
|
)
|
|
|
|
// See doc for NormalizeURL
|
|
func normalizeURL(u string) (*url.URL, string) {
|
|
u = norm.NFC.String(u)
|
|
|
|
tmp, err := gemini.GetPunycodeURL(u)
|
|
if err != nil {
|
|
return nil, u
|
|
}
|
|
u = tmp
|
|
parsed, _ := url.Parse(u)
|
|
|
|
if parsed.Scheme == "" {
|
|
// Always add scheme
|
|
parsed.Scheme = "gemini"
|
|
} else if parsed.Scheme != "gemini" {
|
|
// Not a gemini URL, nothing to do
|
|
return nil, u
|
|
}
|
|
|
|
parsed.User = nil // No passwords in Gemini
|
|
parsed.Fragment = "" // No fragments either
|
|
if parsed.Port() == "1965" {
|
|
// Always remove default port
|
|
hostname := parsed.Hostname()
|
|
if strings.Contains(hostname, ":") {
|
|
parsed.Host = "[" + parsed.Hostname() + "]"
|
|
} else {
|
|
parsed.Host = parsed.Hostname()
|
|
}
|
|
}
|
|
|
|
// Add slash to the end of a URL with just a domain
|
|
// gemini://example.com -> gemini://example.com/
|
|
if parsed.Path == "" {
|
|
parsed.Path = "/"
|
|
} else {
|
|
// Decode and re-encode path
|
|
// This removes needless encoding, like that of ASCII chars
|
|
// And encodes anything that wasn't but should've been
|
|
parsed.RawPath = strings.ReplaceAll(url.PathEscape(parsed.Path), "%2F", "/")
|
|
}
|
|
|
|
// Do the same to the query string
|
|
un, err := gemini.QueryUnescape(parsed.RawQuery)
|
|
if err == nil {
|
|
parsed.RawQuery = gemini.QueryEscape(un)
|
|
}
|
|
|
|
return parsed, ""
|
|
}
|
|
|
|
// NormalizeURL attempts to make URLs that are different strings
|
|
// but point to the same place all look the same.
|
|
//
|
|
// Example: gemini://gus.guru:1965/ and //gus.guru/.
|
|
// This function will take both output the same URL each time.
|
|
//
|
|
// It will also percent-encode invalid characters, and decode chars
|
|
// that don't need to be encoded. It will also apply Unicode NFC
|
|
// normalization.
|
|
//
|
|
// The string passed must already be confirmed to be a URL.
|
|
// Detection of a search string vs. a URL must happen elsewhere.
|
|
//
|
|
// It only works with absolute URLs.
|
|
func NormalizeURL(u string) string {
|
|
pu, s := normalizeURL(u)
|
|
if pu != nil {
|
|
// Could be normalized, return it
|
|
return pu.String()
|
|
}
|
|
// Return the best URL available up to that point
|
|
return s
|
|
}
|
|
|
|
// FixUserURL will take a user-typed URL and add a gemini scheme to it if
|
|
// necessary. It is not the same as normalizeURL, and that func should still
|
|
// be used, afterward.
|
|
//
|
|
// For example "example.com" will become "gemini://example.com", but
|
|
// "//example.com" will be left untouched.
|
|
func FixUserURL(u string) string {
|
|
if !strings.HasPrefix(u, "//") && !strings.HasPrefix(u, "gemini://") && !strings.Contains(u, "://") {
|
|
// Assume it's a Gemini URL
|
|
u = "gemini://" + u
|
|
}
|
|
return u
|
|
}
|