I'm trying to ensure that URLs passed to my go program are valid. However, I can't seem to work out how to. I thought I could just feed it through url.Parse
, but that doesn't seem to do the job.
package main
import (
"fmt"
"net/url"
)
func main() {
url, err := url.Parse("http:::/not.valid/a//a??a?b=&&c#hi")
if err != nil {
panic(err)
}
fmt.Println("It's valid!", url.String())
}
Is there anything along the lines of filter_var I can use?
You can check that your URL has a Scheme, Host, and/or a Path.
If you inspect the URL returned, you can see that the invalid part is inserted into the Opaque data section (so in a sense, it is valid).
url.URL{Scheme:"http", Opaque:"::/not.valid/a//a", Host:"", Path:"", RawQuery:"?a?b=&&c", Fragment:"hi"}
If you parse a URL and don't have a Scheme, Host and Path you can probably assume it's not valid. (though a host without a path is often OK, since it implies /
, so you need to check for that)
u, err := url.Parse("http:::/not.valid/a//a??a?b=&&c#hi")
if err != nil {
log.Fatal(err)
}
if u.Scheme == "" || u.Host == "" || u.Path == "" {
log.Fatal("invalid URL")
}
The url.Parse() function will return an error mainly if viaRequest
is true, meaning if the URL is assumed to have arrived via an HTTP request.
Which is not the case when you call url.Parse()
directly: see the source code.
if url, err = parse(u, false); err != nil {
return nil, err
}
And func parse(rawurl string, viaRequest bool) (url *URL, err error) {
only returns err
if viaRequest
is true.
That is why you never see any error when using url.Parse()
directly.
In that latter case, where no err
is ever returned, you can check the fields of the URL
object returned.
An empty url.Scheme
, or an url.Path
which isn't the one expected would indicate an error.
have a try of this package go validator and the IsURL func is what you want.(you can use regexp package as well)
package main
import (
"fmt"
"regexp"
)
const URL string = `^((ftp|http|https):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(((([a-z\x{00a1}-\x{ffff}0-9]+-?-?_?)*[a-z\x{00a1}-\x{ffff}0-9]+)\.)?)?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?_?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?)|localhost)(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$`
func Matches(str, pattern string) bool {
match, _ := regexp.MatchString(pattern, str)
return match
}
func main() {
u1 := "http:::/not.valid/a//a??a?b=&&c#hi"
u2 := "http://golang.fastrl.com"
func(us ...string) {
for _, u := range us {
fmt.Println(Matches(u, URL))
}
}(u1, u2)
}