package xurl import ( "fmt" "net" "net/url" "strings" "github.com/ignite/cli/v29/ignite/pkg/errors" ) const ( schemeTCP = "tcp" schemeHTTP = "http" schemeHTTPS = "https" schemeWS = "ws" ) // TCP ensures that a URL contains a TCP scheme. func TCP(s string) (string, error) { u, err := parseURL(s) if err != nil { return "", err } u.Scheme = schemeTCP return u.String(), nil } // HTTP ensures that a URL contains an HTTP scheme. func HTTP(s string) (string, error) { u, err := parseURL(s) if err != nil { return "", err } u.Scheme = schemeHTTP return u.String(), nil } // HTTPS ensures that a URL contains an HTTPS scheme. func HTTPS(s string) (string, error) { u, err := parseURL(s) if err != nil { return "", err } u.Scheme = schemeHTTPS return u.String(), nil } // MightHTTPS ensures that a URL contains an HTTPS scheme when the current scheme is not HTTP. // When the URL contains an HTTP scheme it is not modified. func MightHTTPS(s string) (string, error) { if strings.HasPrefix(strings.ToLower(s), "http://") { return s, nil } return HTTPS(s) } // WS ensures that a URL contains a WS scheme. func WS(s string) (string, error) { u, err := parseURL(s) if err != nil { return "", err } u.Scheme = schemeWS return u.String(), nil } // HTTPEnsurePort ensures that url has a port number suits with the connection type. func HTTPEnsurePort(s string) string { u, err := url.Parse(s) if err != nil || u.Port() != "" { return s } port := "80" if u.Scheme == schemeHTTPS { port = "443" } u.Host = fmt.Sprintf("%s:%s", u.Hostname(), port) return u.String() } // Address ensures that address contains localhost as host if non specified. func Address(address string) string { if strings.HasPrefix(address, ":") { return "localhost" + address } return address } func IsHTTP(address string) bool { return strings.HasPrefix(address, "http") } func parseURL(s string) (*url.URL, error) { if s == "" { return nil, errors.New("url is empty") } // Handle the case where the URI is an IP:PORT or HOST:PORT // without scheme prefix because that case can't be URL parsed. // When the URI has no scheme it is parsed as a path by "url.Parse" // placing the colon within the path, which is invalid. if host, isAddrPort := addressPort(s); isAddrPort { return &url.URL{Host: host}, nil } p, err := url.Parse(Address(s)) return p, err } func addressPort(s string) (string, bool) { // Check that the value doesn't contain a URI path if strings.Contains(s, "/") { return "", false } // Use the net split function to support IPv6 addresses host, port, err := net.SplitHostPort(s) if err != nil { return "", false } if host == "" { host = "0.0.0.0" } return net.JoinHostPort(host, port), true }