package gopher import ( "errors" "regexp" ) //------------------------------------------------\\ // + + + T Y P E S + + + \\ //--------------------------------------------------\\ // The url struct represents a URL for the rest of the system. // It includes component parts as well as a full URL string. type Url struct { Scheme string Host string Port string Gophertype string Resource string Full string IsBinary bool } //------------------------------------------------\\ // + + + F U N C T I O N S + + + \\ //--------------------------------------------------\\ // MakeUrl is a Url constructor that takes in a string // representation of a url and returns a Url struct and // an error (or nil). func MakeUrl(u string) (Url, error) { var out Url re := regexp.MustCompile(`^((?Pgopher|http|https|ftp|telnet):\/\/)?(?P[\w\-\.\d]+)(?::(?P\d+)?)?(?:/(?P[01345679gIhisp])?)?(?P(?:[\/|Uu].*)?)?$`) match := re.FindStringSubmatch(u) if valid := re.MatchString(u); !valid { return out, errors.New("Invalid URL or command character") } for i, name := range re.SubexpNames() { switch name { case "scheme": out.Scheme = match[i] case "host": out.Host = match[i] case "port": out.Port = match[i] case "type": out.Gophertype = match[i] case "resource": out.Resource = match[i] } } if out.Scheme == "" { out.Scheme = "gopher" } if out.Host == "" { return out, errors.New("No host.") } if out.Scheme == "gopher" && out.Port == "" { out.Port = "70" } else if out.Scheme == "http" || out.Scheme == "https" && out.Port == "" { out.Port = "80" } if out.Gophertype == "" && (out.Resource == "" || out.Resource == "/") { out.Gophertype = "1" } switch out.Gophertype { case "1", "0", "h", "7": out.IsBinary = false default: out.IsBinary = true } if out.Scheme == "gopher" && out.Gophertype == "" { out.Gophertype = "0" } out.Full = out.Scheme + "://" + out.Host + ":" + out.Port + "/" + out.Gophertype + out.Resource return out, nil }