Repository: go-playground/validator (go)

Issue:
Url validation accepts `https:` as valid url.
- [ √ ] I have looked at the documentation [here](https://pkg.go.dev/github.com/go-playground/validator/v10#section-documentation) first?
- [ √ ] I have looked at the examples provided that may showcase my question [here](/_examples)?

### Package version eg. v9, v10: 

v10

### Issue, Question or Enhancement:

Url validation accepts `https:` as valid url.

### Code sample, to showcase or reproduce:

```go
package main

import (
	"fmt"

	"github.com/go-playground/validator/v10"
)

type User struct {
	Url string `json:"url" validate:"required,url"`
}

func main() {
	validate := validator.New()
	user := &User{Url: "https:"}
	err := validate.Struct(user)
	if err != nil {
		panic(err)
	}
	fmt.Println("ok")
}
```
This code results in ok print, but expected result should be panic on error


Pull request:
Fix: #1112 URL validation accepts "http:" as valid url
## Fixes Or Enhances
Fixes #1112 

**Make sure that you've checked the boxes below before you submit PR:**
- [x] Tests exist or have been written that cover this particular change.

@go-playground/validator-maintainers

Benchmarks before:
```
GO111MODULE=on go test -bench=. -benchmem ./...
goos: linux
goarch: amd64
pkg: github.com/go-playground/validator/v10
cpu: AMD Ryzen 7 PRO 3700U w/ Radeon Vega Mobile Gfx
BenchmarkFieldSuccess-8                                       	11801617	        93.70 ns/op	       0 B/op	       0 allocs/op
BenchmarkFieldSuccessParallel-8                               	54093084	        20.37 ns/op	       0 B/op	       0 allocs/op
BenchmarkFieldFailure-8                                       	 1362246	       973.9 ns/op	     200 B/op	       4 allocs/op
BenchmarkFieldFailureParallel-8                               	 6183358	       176.7 ns/op	     200 B/op	       4 allocs/op
BenchmarkFieldArrayDiveSuccess-8                              	 1000000	      1645 ns/op	     145 B/op	       8 allocs/op
BenchmarkFieldArrayDiveSuccessParallel-8                      	 4890320	       228.8 ns/op	     145 B/op	       8 allocs/op
BenchmarkFieldArrayDiveFailure-8                              	 1000000	      2394 ns/op	     348 B/op	      13 allocs/op
BenchmarkFieldArrayDiveFailureParallel-8                      	 2763897	       410.4 ns/op	     349 B/op	      13 allocs/op
BenchmarkFieldMapDiveSuccess-8                                	  602858	      3888 ns/op	     288 B/op	      14 allocs/op
BenchmarkFieldMapDiveSuccessParallel-8                        	 2359784	       516.7 ns/op	     288 B/op	      14 allocs/op
BenchmarkFieldMapDiveFailure-8                                	  624718	      3158 ns/op	     376 B/op	      13 allocs/op
BenchmarkFieldMapDiveFailureParallel-8                        	 2218954	       495.2 ns/op	     376 B/op	      13 allocs/op
BenchmarkFieldMapDiveWithKeysSuccess-8                        	  534006	      4128 ns/op	     288 B/op	      14 allocs/op
BenchmarkFieldMapDiveWithKeysSuccessParallel-8                	 1714122	       669.2 ns/op	     288 B/op	      14 allocs/op
BenchmarkFieldMapDiveWithKeysFailure-8                        	  459775	      4310 ns/op	     553 B/op	      16 allocs/op
BenchmarkFieldMapDiveWithKeysFailureParallel-8                	 1275787	       958.4 ns/op	     553 B/op	      16 allocs/op
BenchmarkFieldCustomTypeSuccess-8                             	 1944307	       584.1 ns/op	      32 B/op	       2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-8                     	11220068	       107.1 ns/op	      32 B/op	       2 allocs/op
BenchmarkFieldCustomTypeFailure-8                             	 1661941	       680.6 ns/op	     184 B/op	       3 allocs/op
BenchmarkFieldCustomTypeFailureParallel-8                     	 6390658	       203.3 ns/op	     184 B/op	       3 allocs/op
BenchmarkFieldOrTagSuccess-8                                  	 1000000	      1131 ns/op	      16 B/op	       1 allocs/op
BenchmarkFieldOrTagSuccessParallel-8                          	 4221580	       259.6 ns/op	      16 B/op	       1 allocs/op
BenchmarkFieldOrTagFailure-8                                  	 1393892	       934.2 ns/op	     216 B/op	       5 allocs/op
BenchmarkFieldOrTagFailureParallel-8                          	 5197488	       212.3 ns/op	     216 B/op	       5 allocs/op
BenchmarkStructLevelValidationSuccess-8                       	 2816329	       452.1 ns/op	      16 B/op	       1 allocs/op
BenchmarkStructLevelValidationSuccessParallel-8               	17393395	        75.46 ns/op	      16 B/op	       1 allocs/op
BenchmarkStructLevelValidationFailure-8                       	 1000000	      1588 ns/op	     264 B/op	       7 allocs/op
BenchmarkStructLevelValidationFailureParallel-8               	 4049802	       292.1 ns/op	     264 B/op	       7 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-8                      	 1250786	       879.9 ns/op	      32 B/op	       2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-8              	 7151274	       150.8 ns/op	      32 B/op	       2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-8                      	  967278	      2294 ns/op	     416 B/op	       9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-8              	 2779010	       420.0 ns/op	     432 B/op	      10 allocs/op
BenchmarkStructFilteredSuccess-8                              	 1000000	      1805 ns/op	     248 B/op	       7 allocs/op
BenchmarkStructFilteredSuccessParallel-8                      	 3521836	       330.2 ns/op	     248 B/op	       7 allocs/op
BenchmarkStructFilteredFailure-8                              	  902488	      1346 ns/op	     232 B/op	       6 allocs/op
BenchmarkStructFilteredFailureParallel-8                      	 3735235	       274.8 ns/op	     232 B/op	       6 allocs/op
BenchmarkStructPartialSuccess-8                               	 1000000	      1596 ns/op	     240 B/op	       5 allocs/op
BenchmarkStructPartialSuccessParallel-8                       	 4368409	       264.4 ns/op	     240 B/op	       5 allocs/op
BenchmarkStructPartialFailure-8                               	  717194	      2519 ns/op	     456 B/op	      10 allocs/op
BenchmarkStructPartialFailureParallel-8                       	 2608501	       469.6 ns/op	     456 B/op	      10 allocs/op
BenchmarkStructExceptSuccess-8                                	  780676	      2380 ns/op	     456 B/op	      10 allocs/op
BenchmarkStructExceptSuccessParallel-8                        	 4490192	       246.6 ns/op	     224 B/op	       4 allocs/op
BenchmarkStructExceptFailure-8                                	  976275	      2091 ns/op	     440 B/op	       9 allocs/op
BenchmarkStructExceptFailureParallel-8                        	 2592588	       469.4 ns/op	     440 B/op	       9 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-8                      	 1000000	      1123 ns/op	      56 B/op	       3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-8              	 5899574	       202.4 ns/op	      56 B/op	       3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-8                      	  851788	      1740 ns/op	     272 B/op	       8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-8              	 3188026	       368.7 ns/op	     272 B/op	       8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8           	 1000000	      1578 ns/op	      64 B/op	       4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8   	 4619691	       241.5 ns/op	      64 B/op	       4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-8           	  829128	      2893 ns/op	     288 B/op	       9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8   	 2677923	       398.1 ns/op	     288 B/op	       9 allocs/op
BenchmarkStructSimpleSuccess-8                                	 3592005	       345.2 ns/op	       0 B/op	       0 allocs/op
BenchmarkStructSimpleSuccessParallel-8                        	14831719	        76.84 ns/op	       0 B/op	       0 allocs/op
BenchmarkStructSimpleFailure-8                                	  795216	      2249 ns/op	     416 B/op	       9 allocs/op
BenchmarkStructSimpleFailureParallel-8                        	 2835547	       390.4 ns/op	     416 B/op	       9 allocs/op
BenchmarkStructComplexSuccess-8                               	  459040	      5754 ns/op	     288 B/op	       9 allocs/op
BenchmarkStructComplexSuccessParallel-8                       	 1591882	       695.9 ns/op	     288 B/op	       9 allocs/op
BenchmarkStructComplexFailure-8                               	  101236	     14735 ns/op	    3105 B/op	      52 allocs/op
BenchmarkStructComplexFailureParallel-8                       	  419730	      2822 ns/op	    3105 B/op	      52 allocs/op
BenchmarkOneof-8                                              	 7499676	       159.7 ns/op	       0 B/op	       0 allocs/op
BenchmarkOneofParallel-8                                      	25018995	        44.49 ns/op	       0 B/op	       0 allocs/op
```

Benchmarks after:
```
GO111MODULE=on go test -bench=. -benchmem ./...
goos: linux
goarch: amd64
pkg: github.com/go-playground/validator/v10
cpu: AMD Ryzen 7 PRO 3700U w/ Radeon Vega Mobile Gfx
BenchmarkFieldSuccess-8                                       	12974497	        92.64 ns/op	       0 B/op	       0 allocs/op
BenchmarkFieldSuccessParallel-8                               	46178876	        22.92 ns/op	       0 B/op	       0 allocs/op
BenchmarkFieldFailure-8                                       	 1345202	       921.7 ns/op	     200 B/op	       4 allocs/op
BenchmarkFieldFailureParallel-8                               	 6294452	       174.0 ns/op	     200 B/op	       4 allocs/op
BenchmarkFieldArrayDiveSuccess-8                              	 1000000	      1610 ns/op	     145 B/op	       8 allocs/op
BenchmarkFieldArrayDiveSuccessParallel-8                      	 4974109	       223.0 ns/op	     145 B/op	       8 allocs/op
BenchmarkFieldArrayDiveFailure-8                              	 1000000	      2327 ns/op	     348 B/op	      13 allocs/op
BenchmarkFieldArrayDiveFailureParallel-8                      	 2909164	       399.9 ns/op	     349 B/op	      13 allocs/op
BenchmarkFieldMapDiveSuccess-8                                	  551305	      3845 ns/op	     288 B/op	      14 allocs/op
BenchmarkFieldMapDiveSuccessParallel-8                        	 2488228	       467.0 ns/op	     288 B/op	      14 allocs/op
BenchmarkFieldMapDiveFailure-8                                	  772414	      3410 ns/op	     376 B/op	      13 allocs/op
BenchmarkFieldMapDiveFailureParallel-8                        	 2193524	       488.3 ns/op	     376 B/op	      13 allocs/op
BenchmarkFieldMapDiveWithKeysSuccess-8                        	  642025	      3966 ns/op	     288 B/op	      14 allocs/op
BenchmarkFieldMapDiveWithKeysSuccessParallel-8                	 1863225	       554.4 ns/op	     288 B/op	      14 allocs/op
BenchmarkFieldMapDiveWithKeysFailure-8                        	  559651	      4328 ns/op	     553 B/op	      16 allocs/op
BenchmarkFieldMapDiveWithKeysFailureParallel-8                	 1647622	       683.6 ns/op	     553 B/op	      16 allocs/op
BenchmarkFieldCustomTypeSuccess-8                             	 2121175	       616.3 ns/op	      32 B/op	       2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-8                     	11822690	        93.81 ns/op	      32 B/op	       2 allocs/op
BenchmarkFieldCustomTypeFailure-8                             	 1485889	       797.6 ns/op	     184 B/op	       3 allocs/op
BenchmarkFieldCustomTypeFailureParallel-8                     	 7947081	       148.4 ns/op	     184 B/op	       3 allocs/op
BenchmarkFieldOrTagSuccess-8                                  	 1000000	      1167 ns/op	      16 B/op	       1 allocs/op
BenchmarkFieldOrTagSuccessParallel-8                          	 4742452	       218.4 ns/op	      16 B/op	       1 allocs/op
BenchmarkFieldOrTagFailure-8                                  	 1203343	      1057 ns/op	     216 B/op	       5 allocs/op
BenchmarkFieldOrTagFailureParallel-8                          	 5406589	       204.8 ns/op	     216 B/op	       5 allocs/op
BenchmarkStructLevelValidationSuccess-8                       	 3298723	       489.8 ns/op	      16 B/op	       1 allocs/op
BenchmarkStructLevelValidationSuccessParallel-8               	14399948	        74.10 ns/op	      16 B/op	       1 allocs/op
BenchmarkStructLevelValidationFailure-8                       	 1000000	      1513 ns/op	     264 B/op	       7 allocs/op
BenchmarkStructLevelValidationFailureParallel-8               	 4103812	       278.4 ns/op	     264 B/op	       7 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-8                      	 1406757	      1091 ns/op	      32 B/op	       2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-8              	 7505160	       141.8 ns/op	      32 B/op	       2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-8                      	  883422	      2300 ns/op	     416 B/op	       9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-8              	 2746707	       415.6 ns/op	     432 B/op	      10 allocs/op
BenchmarkStructFilteredSuccess-8                              	 1000000	      1779 ns/op	     248 B/op	       7 allocs/op
BenchmarkStructFilteredSuccessParallel-8                      	 3896308	       302.1 ns/op	     248 B/op	       7 allocs/op
BenchmarkStructFilteredFailure-8                              	 1000000	      1517 ns/op	     232 B/op	       6 allocs/op
BenchmarkStructFilteredFailureParallel-8                      	 4696162	       246.0 ns/op	     232 B/op	       6 allocs/op
BenchmarkStructPartialSuccess-8                               	 1000000	      1636 ns/op	     240 B/op	       5 allocs/op
BenchmarkStructPartialSuccessParallel-8                       	 4503459	       255.5 ns/op	     240 B/op	       5 allocs/op
BenchmarkStructPartialFailure-8                               	  857544	      2530 ns/op	     456 B/op	      10 allocs/op
BenchmarkStructPartialFailureParallel-8                       	 2814386	       415.4 ns/op	     456 B/op	      10 allocs/op
BenchmarkStructExceptSuccess-8                                	  712800	      2558 ns/op	     456 B/op	      10 allocs/op
BenchmarkStructExceptSuccessParallel-8                        	 4881768	       231.8 ns/op	     224 B/op	       4 allocs/op
BenchmarkStructExceptFailure-8                                	  980643	      2203 ns/op	     440 B/op	       9 allocs/op
BenchmarkStructExceptFailureParallel-8                        	 3072993	       393.5 ns/op	     440 B/op	       9 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-8                      	 1000000	      1350 ns/op	      56 B/op	       3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-8              	 6480792	       163.9 ns/op	      56 B/op	       3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-8                      	  890593	      2411 ns/op	     272 B/op	       8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-8              	 3336048	       365.9 ns/op	     272 B/op	       8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-8           	  839727	      1641 ns/op	      64 B/op	       4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8   	 4652806	       237.4 ns/op	      64 B/op	       4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-8           	  680821	      3032 ns/op	     288 B/op	       9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8   	 2641432	       409.4 ns/op	     288 B/op	       9 allocs/op
BenchmarkStructSimpleSuccess-8                                	 3409771	       375.2 ns/op	       0 B/op	       0 allocs/op
BenchmarkStructSimpleSuccessParallel-8                        	14754860	        81.12 ns/op	       0 B/op	       0 allocs/op
BenchmarkStructSimpleFailure-8                                	  802147	      2292 ns/op	     416 B/op	       9 allocs/op
BenchmarkStructSimpleFailureParallel-8                        	 2884316	       390.0 ns/op	     416 B/op	       9 allocs/op
BenchmarkStructComplexSuccess-8                               	  407000	      5694 ns/op	     288 B/op	       9 allocs/op
BenchmarkStructComplexSuccessParallel-8                       	 1722357	       686.1 ns/op	     288 B/op	       9 allocs/op
BenchmarkStructComplexFailure-8                               	  105184	     14341 ns/op	    3105 B/op	      52 allocs/op
BenchmarkStructComplexFailureParallel-8                       	  435258	      2783 ns/op	    3105 B/op	      52 allocs/op
BenchmarkOneof-8                                              	 6750638	       175.3 ns/op	       0 B/op	       0 allocs/op
BenchmarkOneofParallel-8                                      	25553877	        45.96 ns/op	       0 B/op	       0 allocs/op
```

The fix doesn't appear to affect the overall performance.

Patch:
diff --git a/baked_in.go b/baked_in.go
index 8e6b169..e676f1d 100644
--- a/baked_in.go
+++ b/baked_in.go
@@ -1414,25 +1414,21 @@ func isURL(fl FieldLevel) bool {
 	switch field.Kind() {
 	case reflect.String:
 
-		var i int
 		s := field.String()
 
-		// checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
-		// emulate browser and strip the '#' suffix prior to validation. see issue-#237
-		if i = strings.Index(s, "#"); i > -1 {
-			s = s[:i]
-		}
-
 		if len(s) == 0 {
 			return false
 		}
 
-		url, err := url.ParseRequestURI(s)
-
+		url, err := url.Parse(s)
 		if err != nil || url.Scheme == "" {
 			return false
 		}
 
+		if url.Host == "" && url.Fragment == "" && url.Opaque == "" {
+			return false
+		}
+
 		return true
 	}
 
@@ -1450,7 +1446,13 @@ func isHttpURL(fl FieldLevel) bool {
 	case reflect.String:
 
 		s := strings.ToLower(field.String())
-		return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://")
+
+		url, err := url.Parse(s)
+		if err != nil || url.Host == "" {
+			return false
+		}
+
+		return url.Scheme == "http" || url.Scheme == "https"
 	}
 
 	panic(fmt.Sprintf("Bad field type %T", field.Interface()))
@@ -2568,9 +2570,17 @@ func isDirPath(fl FieldLevel) bool {
 func isJSON(fl FieldLevel) bool {
 	field := fl.Field()
 
-	if field.Kind() == reflect.String {
+	switch field.Kind() {
+	case reflect.String:
 		val := field.String()
 		return json.Valid([]byte(val))
+	case reflect.Slice:
+		fieldType := field.Type()
+
+		if fieldType.ConvertibleTo(byteSliceType) {
+			b := field.Convert(byteSliceType).Interface().([]byte)
+			return json.Valid(b)
+		}
 	}
 
 	panic(fmt.Sprintf("Bad field type %T", field.Interface()))
diff --git a/validator_instance.go b/validator_instance.go
index d2ee8fe..d9dbf0c 100644
--- a/validator_instance.go
+++ b/validator_instance.go
@@ -53,6 +53,8 @@ var (
 	timeDurationType = reflect.TypeOf(time.Duration(0))
 	timeType         = reflect.TypeOf(time.Time{})
 
+	byteSliceType = reflect.TypeOf([]byte{})
+
 	defaultCField = &cField{namesEqual: true}
 )
 


Test patch:
diff --git a/validator_test.go b/validator_test.go
index a60e4bc..74f4945 100644
--- a/validator_test.go
+++ b/validator_test.go
@@ -8039,6 +8039,8 @@ func TestUrl(t *testing.T) {
 		{"irc://#channel@network", true},
 		{"/abs/test/dir", false},
 		{"./rel/test/dir", false},
+		{"irc:", false},
+		{"http://", false},
 	}
 
 	validate := New()
@@ -8110,6 +8112,10 @@ func TestHttpUrl(t *testing.T) {
 		{"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},
 	}
 
 	validate := New()
@@ -11958,7 +11964,7 @@ func TestGetTag(t *testing.T) {
 
 func TestJSONValidation(t *testing.T) {
 	tests := []struct {
-		param    string
+		param    interface{}
 		expected bool
 	}{
 		{`foo`, false},
@@ -11975,6 +11981,34 @@ func TestJSONValidation(t *testing.T) {
 		{`true`, true},
 		{`null`, true},
 		{`"null"`, true},
+		{json.RawMessage(`foo`), false},
+		{json.RawMessage(`}{`), false},
+		{json.RawMessage(`{]`), false},
+		{json.RawMessage(`{}`), true},
+		{json.RawMessage(`{"foo":"bar"}`), true},
+		{json.RawMessage(`{"foo":"bar","bar":{"baz":["qux"]}}`), true},
+		{json.RawMessage(`{"foo": 3 "bar": 4}`), false},
+		{json.RawMessage(`{"foo": 3 ,"bar": 4`), false},
+		{json.RawMessage(`{foo": 3, "bar": 4}`), false},
+		{json.RawMessage(`foo`), false},
+		{json.RawMessage(`1`), true},
+		{json.RawMessage(`true`), true},
+		{json.RawMessage(`null`), true},
+		{json.RawMessage(`"null"`), true},
+		{[]byte(`foo`), false},
+		{[]byte(`}{`), false},
+		{[]byte(`{]`), false},
+		{[]byte(`{}`), true},
+		{[]byte(`{"foo":"bar"}`), true},
+		{[]byte(`{"foo":"bar","bar":{"baz":["qux"]}}`), true},
+		{[]byte(`{"foo": 3 "bar": 4}`), false},
+		{[]byte(`{"foo": 3 ,"bar": 4`), false},
+		{[]byte(`{foo": 3, "bar": 4}`), false},
+		{[]byte(`foo`), false},
+		{[]byte(`1`), true},
+		{[]byte(`true`), true},
+		{[]byte(`null`), true},
+		{[]byte(`"null"`), true},
 	}
 
 	validate := New()