Skip to content

Commit

Permalink
Make url and http_url work with url.URL.
Browse files Browse the repository at this point in the history
  • Loading branch information
bfabio committed Feb 14, 2024
1 parent b328f72 commit 0244df6
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 112 deletions.
58 changes: 33 additions & 25 deletions baked_in.go
Expand Up @@ -1453,33 +1453,37 @@ func isFileURL(path string) bool {
// isURL is the validation function for validating if the current field's value is a valid URL.
func isURL(fl FieldLevel) bool {
field := fl.Field()
var s string

switch field.Kind() {
case reflect.String:

s := strings.ToLower(field.String())

if len(s) == 0 {
return false
s = strings.ToLower(field.String())
default:
if stringer, ok := field.Interface().(fmt.Stringer); ok {
s = stringer.String()
} else {
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
}

if isFileURL(s) {
return true
}
if len(s) == 0 {
return false
}

url, err := url.Parse(s)
if err != nil || url.Scheme == "" {
return false
}
if isFileURL(s) {
return true
}

if url.Host == "" && url.Fragment == "" && url.Opaque == "" {
return false
}
url, err := url.Parse(s)
if err != nil || url.Scheme == "" {
return false
}

return true
if url.Host == "" && url.Fragment == "" && url.Opaque == "" {
return false
}

panic(fmt.Sprintf("Bad field type %T", field.Interface()))
return true
}

// isHttpURL is the validation function for validating if the current field's value is a valid HTTP(s) URL.
Expand All @@ -1489,20 +1493,24 @@ func isHttpURL(fl FieldLevel) bool {
}

field := fl.Field()
var s string
switch field.Kind() {
case reflect.String:

s := strings.ToLower(field.String())

url, err := url.Parse(s)
if err != nil || url.Host == "" {
return false
s = strings.ToLower(field.String())
default:
if stringer, ok := fl.Field().Interface().(fmt.Stringer); ok {
s = stringer.String()
} else {
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
}

return url.Scheme == "http" || url.Scheme == "https"
url, err := url.Parse(s)
if err != nil || url.Host == "" {
return false
}

panic(fmt.Sprintf("Bad field type %T", field.Interface()))
return url.Scheme == "http" || url.Scheme == "https"
}

// isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141.
Expand Down
192 changes: 105 additions & 87 deletions validator_test.go
Expand Up @@ -11,6 +11,7 @@ import (
"image"
"image/jpeg"
"image/png"
"net/url"
"os"
"path/filepath"
"reflect"
Expand Down Expand Up @@ -8134,59 +8135,70 @@ func TestUrnRFC2141(t *testing.T) {
PanicMatches(t, func() { _ = validate.Var(i, tag) }, "Bad field type int")
}

type Stringer string

func (s Stringer) String() string {
return string(s)
}

func TestUrl(t *testing.T) {
tests := []struct {
param string
param fmt.Stringer
expected bool
}{
{"http://foo.bar#com", true},
{"http://foobar.com", true},
{"https://foobar.com", true},
{"foobar.com", false},
{"http://foobar.coffee/", true},
{"http://foobar.中文网/", true},
{"http://foobar.org/", true},
{"http://foobar.org:8080/", true},
{"ftp://foobar.ru/", true},
{"http://user:pass@www.foobar.com/", true},
{"http://127.0.0.1/", true},
{"http://duckduckgo.com/?q=%2F", true},
{"http://localhost:3000/", true},
{"http://foobar.com/?foo=bar#baz=qux", true},
{"http://foobar.com?foo=bar", true},
{"http://www.xn--froschgrn-x9a.net/", true},
{"", false},
{"xyz://foobar.com", true},
{"invalid.", false},
{".com", false},
{"rtmp://foobar.com", true},
{"http://www.foo_bar.com/", true},
{"http://localhost:3000/", true},
{"http://foobar.com/#baz", true},
{"http://foobar.com#baz=qux", true},
{"http://foobar.com/t$-_.+!*\\'(),", true},
{"http://www.foobar.com/~foobar", true},
{"http://www.-foobar.com/", true},
{"http://www.foo---bar.com/", true},
{"mailto:someone@example.com", true},
{"irc://irc.server.org/channel", true},
{"irc://#channel@network", true},
{"/abs/test/dir", false},
{"./rel/test/dir", false},
{"irc:", false},
{"http://", false},
{"file://path/to/file.txt", true},
{"file:///c:/Windows/file.txt", true},
{"file://localhost/path/to/file.txt", true},
{"file://localhost/c:/WINDOWS/file.txt", true},
{"file://", true},
{"file:////remotehost/path/file.txt", true},
{Stringer("http://foo.bar#com"), true},
{Stringer("http://foobar.com"), true},
{Stringer("https://foobar.com"), true},
{Stringer("foobar.com"), false},
{Stringer("http://foobar.coffee/"), true},
{Stringer("http://foobar.中文网/"), true},
{Stringer("http://foobar.org/"), true},
{Stringer("http://foobar.org:8080/"), true},
{Stringer("ftp://foobar.ru/"), true},
{Stringer("http://user:pass@www.foobar.com/"), true},
{Stringer("http://127.0.0.1/"), true},
{Stringer("http://duckduckgo.com/?q=%2F"), true},
{Stringer("http://localhost:3000/"), true},
{Stringer("http://foobar.com/?foo=bar#baz=qux"), true},
{Stringer("http://foobar.com?foo=bar"), true},
{Stringer("http://www.xn--froschgrn-x9a.net/"), true},
{Stringer(""), false},
{Stringer("xyz://foobar.com"), true},
{Stringer("invalid."), false},
{Stringer(".com"), false},
{Stringer("rtmp://foobar.com"), true},
{Stringer("http://www.foo_bar.com/"), true},
{Stringer("http://localhost:3000/"), true},
{Stringer("http://foobar.com/#baz"), true},
{Stringer("http://foobar.com#baz=qux"), true},
{Stringer("http://foobar.com/t$-_.+!*\\'(),"), true},
{Stringer("http://www.foobar.com/~foobar"), true},
{Stringer("http://www.-foobar.com/"), true},
{Stringer("http://www.foo---bar.com/"), true},
{Stringer("mailto:someone@example.com"), true},
{Stringer("irc://irc.server.org/channel"), true},
{Stringer("irc://#channel@network"), true},
{Stringer("/abs/test/dir"), false},
{Stringer("./rel/test/dir"), false},
{Stringer("irc:"), false},
{Stringer("http://"), false},
{Stringer("file://path/to/file.txt"), true},
{Stringer("file:///c:/Windows/file.txt"), true},
{Stringer("file://localhost/path/to/file.txt"), true},
{Stringer("file://localhost/c:/WINDOWS/file.txt"), true},
{Stringer("file://"), true},
{Stringer("file:////remotehost/path/file.txt"), true},
{&url.URL{Scheme: "https", Host: "foobar.com"}, true},
{&url.URL{Scheme: "file"}, true},
{&url.URL{Scheme: "file"}, true},
{&url.URL{Scheme: "file", Path: "/"}, true},
{&url.URL{Host: "foobar.com"}, false},
{&url.URL{}, false},
}

validate := New()

for i, test := range tests {

errs := validate.Var(test.param, "url")

if test.expected {
Expand All @@ -8211,51 +8223,57 @@ func TestUrl(t *testing.T) {

func TestHttpUrl(t *testing.T) {
tests := []struct {
param string
param fmt.Stringer
expected bool
}{
{"http://foo.bar#com", true},
{"http://foobar.com", true},
{"HTTP://foobar.com", true},
{"https://foobar.com", true},
{"foobar.com", false},
{"http://foobar.coffee/", true},
{"http://foobar.中文网/", true},
{"http://foobar.org/", true},
{"http://foobar.org:8080/", true},
{"ftp://foobar.ru/", false},
{"file:///etc/passwd", false},
{"file://C:/windows/win.ini", false},
{"http://user:pass@www.foobar.com/", true},
{"http://127.0.0.1/", true},
{"http://duckduckgo.com/?q=%2F", true},
{"http://localhost:3000/", true},
{"http://foobar.com/?foo=bar#baz=qux", true},
{"http://foobar.com?foo=bar", true},
{"http://www.xn--froschgrn-x9a.net/", true},
{"", false},
{"a://b", false},
{"xyz://foobar.com", false},
{"invalid.", false},
{".com", false},
{"rtmp://foobar.com", false},
{"http://www.foo_bar.com/", true},
{"http://localhost:3000/", true},
{"http://foobar.com/#baz", true},
{"http://foobar.com#baz=qux", true},
{"http://foobar.com/t$-_.+!*\\'(),", true},
{"http://www.foobar.com/~foobar", true},
{"http://www.-foobar.com/", true},
{"http://www.foo---bar.com/", true},
{"mailto:someone@example.com", false},
{"irc://irc.server.org/channel", false},
{"irc://#channel@network", false},
{"/abs/test/dir", false},
{"./rel/test/dir", false},
{"http:", false},
{"http://", false},
{"http://#invalid", false},
{"https://1.1.1.1", true},
{Stringer("http://foo.bar#com"), true},
{Stringer("http://foobar.com"), true},
{Stringer("HTTP://foobar.com"), true},
{Stringer("https://foobar.com"), true},
{Stringer("foobar.com"), false},
{Stringer("http://foobar.coffee/"), true},
{Stringer("http://foobar.中文网/"), true},
{Stringer("http://foobar.org/"), true},
{Stringer("http://foobar.org:8080/"), true},
{Stringer("ftp://foobar.ru/"), false},
{Stringer("file:///etc/passwd"), false},
{Stringer("file://C:/windows/win.ini"), false},
{Stringer("http://user:pass@www.foobar.com/"), true},
{Stringer("http://127.0.0.1/"), true},
{Stringer("http://duckduckgo.com/?q=%2F"), true},
{Stringer("http://localhost:3000/"), true},
{Stringer("http://foobar.com/?foo=bar#baz=qux"), true},
{Stringer("http://foobar.com?foo=bar"), true},
{Stringer("http://www.xn--froschgrn-x9a.net/"), true},
{Stringer(""), false},
{Stringer("a://b"), false},
{Stringer("xyz://foobar.com"), false},
{Stringer("invalid."), false},
{Stringer(".com"), false},
{Stringer("rtmp://foobar.com"), false},
{Stringer("http://www.foo_bar.com/"), true},
{Stringer("http://localhost:3000/"), true},
{Stringer("http://foobar.com/#baz"), true},
{Stringer("http://foobar.com#baz=qux"), true},
{Stringer("http://foobar.com/t$-_.+!*\\'(),"), true},
{Stringer("http://www.foobar.com/~foobar"), true},
{Stringer("http://www.-foobar.com/"), true},
{Stringer("http://www.foo---bar.com/"), true},
{Stringer("mailto:someone@example.com"), false},
{Stringer("irc://irc.server.org/channel"), false},
{Stringer("irc://#channel@network"), false},
{Stringer("/abs/test/dir"), false},
{Stringer("./rel/test/dir"), false},
{Stringer("http:"), false},
{Stringer("http://"), false},
{Stringer("http://#invalid"), false},
{Stringer("https://1.1.1.1"), true},

{&url.URL{Scheme: "https", Host: "foobar.com"}, true},
{&url.URL{Scheme: "file"}, false},
{&url.URL{Scheme: "file", Path: "/"}, false},
{&url.URL{Host: "foobar.com"}, false},
{&url.URL{}, false},
}

validate := New()
Expand Down

0 comments on commit 0244df6

Please sign in to comment.