labstack / echox

Echo cookbook and website
https://echo.labstack.com
MIT License
408 stars 285 forks source link

Go-Validation example crashes server when issuing correct data #181

Closed aphsa closed 3 years ago

aphsa commented 3 years ago

The example provided in this link(https://github.com/labstack/echox/blob/master/website/content/guide/request.md) will fail with the following message:

http server started on [::]:1323
echo: http: panic serving 127.0.0.1:39328: runtime error: invalid memory address or nil pointer dereference
goroutine 18 [running]:
net/http.(*conn).serve.func1(0xc00038a000)
        /home/testuser/go/src/net/http/server.go:1801 +0x147
panic(0x735ca0, 0x9b3b00)
        /home/testuser/go/src/runtime/panic.go:975 +0x47a
main.(*CustomValidator).Validate(0xc0000101b8, 0x718000, 0xc00039a020, 0x0, 0x0)
        /home/testuser/code/golang/validatejson/main.go:22 +0x6a
github.com/labstack/echo/v4.(*context).Validate(0xc00038a0a0, 0x718000, 0xc00039a020, 0x0, 0x0)
        /home/testuser/go/pkg/mod/github.com/labstack/echo/v4@v4.2.0/context.go:433 +0x5b
main.main.func1(0x7fa880, 0xc00038a0a0, 0x0, 0x0)
        /home/testuser/code/golang/validatejson/main.go:33 +0x1f1
github.com/labstack/echo/v4.(*Echo).add.func1(0x7fa880, 0xc00038a0a0, 0x0, 0x0)
        /home/testuser/go/pkg/mod/github.com/labstack/echo/v4@v4.2.0/echo.go:536 +0x62
github.com/labstack/echo/v4.(*Echo).ServeHTTP(0xc0002d2800, 0x7f6920, 0xc0003a0000, 0xc000382100)
        /home/testuser/go/pkg/mod/github.com/labstack/echo/v4@v4.2.0/echo.go:646 +0x187
net/http.serverHandler.ServeHTTP(0xc0002f6000, 0x7f6920, 0xc0003a0000, 0xc000382100)
        /home/testuser/go/src/net/http/server.go:2843 +0xa3
net/http.(*conn).serve(0xc00038a000, 0x7f71a0, 0xc00038e000)
        /home/testuser/go/src/net/http/server.go:1925 +0x8ad
created by net/http.(*Server).Serve
        /home/testuser/go/src/net/http/server.go:2969 +0x36c

When using the following request

$ curl -X POST http://localhost:1323/users   -H 'Content-Type: application/json'   -d '{"name":"Joe","email":"joe@domain.com"}'
curl: (52) Empty reply from server

go version
go version go1.15.8 linux/amd64

$ cat go.mod
module validatejson
go 1.15

require (
        github.com/go-playground/validator/v10 v10.4.1
        github.com/labstack/echo/v4 v4.2.0
)

`

aldas commented 3 years ago

I'm unable to reproduce this problem. Can you provide code that you are running.

This is how I tried

x@x:~/code/newproject$ go mod init newproject
go: creating new go.mod: module newproject
x@x:~/code/newproject$ ls
go.mod
x@x:~/code/newproject$ go get github.com/go-playground/validator/v10
go: github.com/go-playground/validator/v10 upgrade => v10.4.1
go: downloading golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
go: downloading golang.org/x/sys v0.0.0-20190412213103-97732733099d
x@x:~/code/newproject$ go get github.com/labstack/echo/v4
go: downloading github.com/labstack/echo v1.4.4
go: downloading github.com/labstack/echo/v4 v4.2.0
go: downloading github.com/labstack/echo v3.3.10+incompatible
go: github.com/labstack/echo/v4 upgrade => v4.2.0
x@x:~/code/newproject$ ls
go.mod  go.sum
x@x:~/code/newproject$ touch main.go

main.go contents is:

package main

import (
    "github.com/go-playground/validator/v10"
    "github.com/labstack/echo/v4"
    "net/http"
)

type (
    User struct {
        Name  string `json:"name" validate:"required"`
        Email string `json:"email" validate:"required,email"`
    }

    CustomValidator struct {
        validator *validator.Validate
    }
)

func (cv *CustomValidator) Validate(i interface{}) error {
    return echo.NewHTTPError(http.StatusInternalServerError, cv.validator.Struct(i).Error())
}

func main() {
    e := echo.New()
    e.Validator = &CustomValidator{validator: validator.New()}
    e.POST("/users", func(c echo.Context) (err error) {
        u := new(User)
        if err = c.Bind(u); err != nil {
            return echo.NewHTTPError(http.StatusBadRequest, err.Error())
        }
        if err = c.Validate(u); err != nil {
            return echo.NewHTTPError(http.StatusBadRequest, err.Error())
        }
        return c.JSON(http.StatusOK, u)
    })
    e.Logger.Fatal(e.Start(":1323"))
}

I'll start server

x@x:~/code/newproject$ go run main.go

   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.2.0
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:1323

and make request

x@x:~/code/newproject$ curl -v -X POST http://localhost:1323/users   -H 'Content-Type: application/json'   -d '{"name":"Joe","email":"joe@invalid-domain"}'
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 127.0.0.1:1323...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 1323 (#0)
> POST /users HTTP/1.1
> Host: localhost:1323
> User-Agent: curl/7.68.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 43
> 
* upload completely sent off: 43 out of 43 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Content-Type: application/json; charset=UTF-8
< Date: Fri, 12 Feb 2021 08:40:11 GMT
< Content-Length: 111
< 
{"message":"code=500, message=Key: 'User.Email' Error:Field validation for 'Email' failed on the 'email' tag"}
* Connection #0 to host localhost left intact
x@x:~/code/newproject$ cat go.mod 
module newproject

go 1.15

require (
    github.com/go-playground/validator/v10 v10.4.1
    github.com/labstack/echo/v4 v4.2.0
)
x@x:~/code/newproject$ cat go.sum 
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
aphsa commented 3 years ago

Please copy paste this request. Note the "domain.com" in the end:

curl -X POST http://localhost:1323/users   -H 'Content-Type: application/json'   -d '{"name":"Joe","email":"joe@domain.com"}'
aldas commented 3 years ago

Ok, this is because this is valid struct and there is no error and we can not take error text from nil

actual method should be

func (cv *CustomValidator) Validate(i interface{}) error {
    if err := cv.validator.Struct(i); err != nil {
        return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
    }
    return nil
}