Pulse/pkg/netutil/http_urls.go
2026-03-31 09:34:31 +01:00

54 lines
1.4 KiB
Go

package netutil
import (
"fmt"
"net/url"
"strings"
)
// NormalizeHTTPBaseURL parses and canonicalizes an HTTP(S) base URL. If the
// input has no scheme, defaultScheme is applied.
func NormalizeHTTPBaseURL(rawURL, defaultScheme string) (*url.URL, error) {
parsed, err := parseHTTPURL(rawURL, defaultScheme)
if err != nil {
return nil, err
}
parsed.RawQuery = ""
return parsed, nil
}
// ValidateAbsoluteHTTPURL validates an already absolute HTTP(S) URL.
func ValidateAbsoluteHTTPURL(rawURL string) (*url.URL, error) {
return parseHTTPURL(rawURL, "")
}
func parseHTTPURL(rawURL, defaultScheme string) (*url.URL, error) {
s := strings.TrimSpace(rawURL)
if s == "" {
return nil, fmt.Errorf("URL cannot be empty")
}
if !strings.Contains(s, "://") {
if defaultScheme == "" {
return nil, fmt.Errorf("URL must include http:// or https://")
}
s = strings.TrimSuffix(defaultScheme, "://") + "://" + s
}
parsed, err := url.ParseRequestURI(s)
if err != nil {
return nil, fmt.Errorf("invalid URL format")
}
if parsed.User != nil {
return nil, fmt.Errorf("embedded credentials are not allowed")
}
if parsed.Fragment != "" {
return nil, fmt.Errorf("URL fragments are not allowed")
}
if parsed.Hostname() == "" {
return nil, fmt.Errorf("URL must have a hostname")
}
if parsed.Scheme != "http" && parsed.Scheme != "https" {
return nil, fmt.Errorf("URL scheme must be http or https")
}
return parsed, nil
}