package config import ( "fmt" "net/url" "strings" ) // Resolve turns a short topic, host/topic, or absolute URL into an origin and // a single topic name. defaultHost is used only for short names. func Resolve(topic, defaultHost string) (origin, name string, err error) { topic = strings.TrimSpace(topic) if topic == "" { return "", "", fmt.Errorf("empty topic") } if !strings.Contains(topic, "://") && strings.Contains(topic, "/") { return Resolve("https://"+topic, "") } if strings.Contains(topic, "://") { u, err := url.Parse(topic) if err != nil || u.Host == "" || (u.Scheme != "https" && u.Scheme != "http") { return "", "", fmt.Errorf("invalid topic URL %q", topic) } path := strings.Trim(u.Path, "/") if path == "" { return "", "", fmt.Errorf("topic URL %q has no topic", topic) } base := u.Scheme + "://" + u.Host if i := strings.LastIndex(path, "/"); i >= 0 { base += "/" + path[:i] path = path[i+1:] } if err := checkName(path); err != nil { return "", "", err } return base, path, nil } if err := checkName(topic); err != nil { return "", "", err } origin, err = normalizeOrigin(defaultHost) if err != nil { return "", "", fmt.Errorf("topic %q: %w", topic, err) } return origin, topic, nil } func checkName(name string) error { if name == "" || strings.Contains(name, ",") || strings.ContainsAny(name, " \t") { return fmt.Errorf("invalid topic name %q", name) } return nil } func normalizeOrigin(host string) (string, error) { host = strings.TrimSpace(host) if host == "" { return "", fmt.Errorf("no default-host") } if !strings.Contains(host, "://") { host = "https://" + host } u, err := url.Parse(strings.TrimRight(host, "/")) if err != nil || u.Host == "" || (u.Scheme != "https" && u.Scheme != "http") { return "", fmt.Errorf("invalid host %q", host) } origin := u.Scheme + "://" + u.Host if path := strings.Trim(u.Path, "/"); path != "" { origin += "/" + path } return origin, nil }