Add nil checks to HTTP request validation dispatch (#44371)

Signed-off-by: Igor Suleymanov <igor.suleymanov@grafana.com>
This commit is contained in:
Igor Suleymanov 2022-01-24 17:43:44 +02:00 committed by GitHub
parent a7423d8760
commit fdeaf7a5c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 2 deletions

View File

@ -26,14 +26,27 @@ type Validator interface {
}
func validate(obj interface{}) error {
// First check if obj is nil, because we cannot validate those.
if obj == nil {
return nil
}
// Second, check if obj has a nil interface value.
// This is to prevent panics when obj is an instance of uninitialised struct pointer / interface.
t := reflect.TypeOf(obj)
v := reflect.ValueOf(obj)
if v.Kind() == reflect.Ptr && v.IsNil() {
return nil
}
// If type has a Validate() method - use that
if validator, ok := obj.(Validator); ok {
return validator.Validate()
}
// Otherwise, use reflection to match `binding:"Required"` struct field tags.
// Resolve all pointers and interfaces, until we get a concrete type.
t := reflect.TypeOf(obj)
v := reflect.ValueOf(obj)
for v.Kind() == reflect.Interface || v.Kind() == reflect.Ptr {
t = t.Elem()
v = v.Elem()

View File

@ -50,8 +50,22 @@ func (sv StructWithValidation) Validate() error {
return nil
}
type StructWithPointerValidation struct {
A int
}
func (sv *StructWithPointerValidation) Validate() error {
if sv.A < 10 {
return errors.New("too small")
}
return nil
}
func TestValidationSuccess(t *testing.T) {
var nilInterface *StructWithPointerValidation
for _, x := range []interface{}{
nil,
42,
"foo",
struct{ A int }{},
@ -65,6 +79,8 @@ func TestValidationSuccess(t *testing.T) {
StructWithStruct{StructWithInt{3}},
StructWithStructPointer{&StructWithInt{3}},
StructWithValidation{42},
&StructWithPointerValidation{42},
nilInterface,
} {
if err := validate(x); err != nil {
t.Error("Validation failed:", x, err)
@ -93,6 +109,7 @@ func TestValidationFailure(t *testing.T) {
StructWithStructPointer{},
StructWithStructPointer{&StructWithInt{}},
StructWithValidation{2},
&StructWithPointerValidation{2},
} {
if err := validate(x); err == nil {
t.Error("Validation should fail:", i, x)