Repository: gin-gonic/gin
Pull request #2851 (2021-08-31 13:05:47)

fix: check obj type in protobufBinding
Change-Id: I194f7010835974b489b497c6d1f1b4e47b99864e

- With pull requests:
  - Open your pull request against `master`
  - Your pull request should have no more than two commits, if not you should squash them.
  - It should pass all tests in the available continuous integration systems such as GitHub Actions.
  - You should add/modify tests to cover your proposed code changes.
  - If your pull request contains a new feature, please document it on the README.

Solve https://github.com/gin-gonic/gin/issues/2850

codecov[bot]: # [Codecov](https://codecov.io/gh/gin-gonic/gin/pull/2851?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) Report
> Merging [#2851](https://codecov.io/gh/gin-gonic/gin/pull/2851?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) (f21906a) into [master](https://codecov.io/gh/gin-gonic/gin/commit/30cdbfcf4c904bb2bcc0f474ff1660a1efb852da?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) (30cdbfc) will **decrease** coverage by `0.09%`.
> The diff coverage is `40.00%`.

[![Impacted file tree graph](https://codecov.io/gh/gin-gonic/gin/pull/2851/graphs/tree.svg?width=650&height=150&src=pr&token=Qpqxhwery8&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic)](https://codecov.io/gh/gin-gonic/gin/pull/2851?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic)

```diff
@@            Coverage Diff             @@
##           master    #2851      +/-   ##
==========================================
- Coverage   98.75%   98.65%   -0.10%     
==========================================
  Files          41       41              
  Lines        3054     3058       +4     
==========================================
+ Hits         3016     3017       +1     
- Misses         26       28       +2     
- Partials       12       13       +1     
```

| Flag | Coverage Δ | |
|---|---|---|
| go-1.13 | `98.65% <40.00%> (-0.10%)` | :arrow_down: |
| go-1.14 | `98.49% <40.00%> (-0.10%)` | :arrow_down: |
| go-1.15 | `98.49% <40.00%> (-0.10%)` | :arrow_down: |
| go-1.16 | `98.49% <40.00%> (-0.10%)` | :arrow_down: |
| macos-latest | `98.65% <40.00%> (-0.10%)` | :arrow_down: |
| nomsgpack | `98.63% <40.00%> (-0.10%)` | :arrow_down: |
| ubuntu-latest | `98.65% <40.00%> (-0.10%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/gin-gonic/gin/pull/2851?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic) | Coverage Δ | |
|---|---|---|
| [binding/protobuf.go](https://codecov.io/gh/gin-gonic/gin/pull/2851/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic#diff-YmluZGluZy9wcm90b2J1Zi5nbw==) | `82.35% <40.00%> (-17.65%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/gin-gonic/gin/pull/2851?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/gin-gonic/gin/pull/2851?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic). Last update [30cdbfc...f21906a](https://codecov.io/gh/gin-gonic/gin/pull/2851?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gin-gonic).

appleboy: build fail

Patch:
diff --git a/.github/workflows/gin.yml b/.github/workflows/gin.yml
index 21895f2..6eb5a64 100644
--- a/.github/workflows/gin.yml
+++ b/.github/workflows/gin.yml
@@ -21,13 +21,13 @@ jobs:
       - name: Setup golangci-lint
         uses: golangci/golangci-lint-action@v2
         with:
-          version: v1.42.0
+          version: v1.42.1
           args: --verbose
   test:
     strategy:
       matrix:
         os: [ubuntu-latest, macos-latest]
-        go: [1.13, 1.14, 1.15, 1.16]
+        go: [1.13, 1.14, 1.15, 1.16, 1.17]
         test-tags: ['', nomsgpack]
         include:
           - os: ubuntu-latest
diff --git a/binding/protobuf.go b/binding/protobuf.go
index ca02897..a4e4715 100644
--- a/binding/protobuf.go
+++ b/binding/protobuf.go
@@ -5,6 +5,7 @@
 package binding
 
 import (
+	"errors"
 	"io/ioutil"
 	"net/http"
 
@@ -26,7 +27,11 @@ func (b protobufBinding) Bind(req *http.Request, obj interface{}) error {
 }
 
 func (protobufBinding) BindBody(body []byte, obj interface{}) error {
-	if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil {
+	msg, ok := obj.(proto.Message)
+	if !ok {
+		return errors.New("obj is not ProtoMessage")
+	}
+	if err := proto.Unmarshal(body, msg); err != nil {
 		return err
 	}
 	// Here it's same to return validate(obj), but util now we can't add
diff --git a/context.go b/context.go
index 56c20f2..6284948 100644
--- a/context.go
+++ b/context.go
@@ -383,6 +383,15 @@ func (c *Context) Param(key string) string {
 	return c.Params.ByName(key)
 }
 
+// AddParam adds param to context and
+// replaces path param key with given value for e2e testing purposes
+// Example Route: "/user/:id"
+// AddParam("id", 1)
+// Result: "/user/1"
+func (c *Context) AddParam(key, value string) {
+	c.Params = append(c.Params, Param{Key: key, Value: value})
+}
+
 // Query returns the keyed url query value if it exists,
 // otherwise it returns an empty string `("")`.
 // It is shortcut for `c.Request.URL.Query().Get(key)`
diff --git a/go.mod b/go.mod
index 844dc45..26b9271 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.13
 require (
 	github.com/gin-contrib/sse v0.1.0
 	github.com/go-playground/validator/v10 v10.9.0
-	github.com/goccy/go-json v0.7.7
+	github.com/goccy/go-json v0.7.8
 	github.com/json-iterator/go v1.1.11
 	github.com/mattn/go-isatty v0.0.13
 	github.com/stretchr/testify v1.7.0
diff --git a/go.sum b/go.sum
index 266f4ac..8aaf41a 100644
--- a/go.sum
+++ b/go.sum
@@ -12,8 +12,8 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j
 github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
 github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A=
 github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
-github.com/goccy/go-json v0.7.7 h1:MflzqwHECILPg/0qDYB+jx+sJeNojJHEbRYsa8q7j/o=
-github.com/goccy/go-json v0.7.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-json v0.7.8 h1:CvMH7LotYymYuLGEohBM1lTZWX4g6jzWUUl2aLFuBoE=
+github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=


Test patch:
diff --git a/binding/binding_test.go b/binding/binding_test.go
index 17df7dc..5b0ce39 100644
--- a/binding/binding_test.go
+++ b/binding/binding_test.go
@@ -1339,6 +1339,13 @@ func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body
 	err := b.Bind(req, &obj)
 	assert.Error(t, err)
 
+	invalid_obj := FooStruct{}
+	req.Body = ioutil.NopCloser(strings.NewReader(`{"msg":"hello"}`))
+	req.Header.Add("Content-Type", MIMEPROTOBUF)
+	err = b.Bind(req, &invalid_obj)
+	assert.Error(t, err)
+	assert.Equal(t, err.Error(), "obj is not ProtoMessage")
+
 	obj = protoexample.Test{}
 	req = requestWithBody("POST", badPath, badBody)
 	req.Header.Add("Content-Type", MIMEPROTOBUF)
diff --git a/context_1.16_test.go b/context_1.16_test.go
new file mode 100644
index 0000000..053e6c5
--- /dev/null
+++ b/context_1.16_test.go
@@ -0,0 +1,31 @@
+// Copyright 2021 Gin Core Team.  All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+//go:build !go1.17
+// +build !go1.17
+
+package gin
+
+import (
+	"bytes"
+	"mime/multipart"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestContextFormFileFailed16(t *testing.T) {
+	buf := new(bytes.Buffer)
+	mw := multipart.NewWriter(buf)
+	mw.Close()
+	c, _ := CreateTestContext(httptest.NewRecorder())
+	c.Request, _ = http.NewRequest("POST", "/", nil)
+	c.Request.Header.Set("Content-Type", mw.FormDataContentType())
+	c.engine.MaxMultipartMemory = 8 << 20
+	f, err := c.FormFile("file")
+	assert.Error(t, err)
+	assert.Nil(t, f)
+}
diff --git a/context_1.17_test.go b/context_1.17_test.go
new file mode 100644
index 0000000..431d54c
--- /dev/null
+++ b/context_1.17_test.go
@@ -0,0 +1,33 @@
+// Copyright 2021 Gin Core Team.  All rights reserved.
+// Use of this source code is governed by a MIT style
+// license that can be found in the LICENSE file.
+
+//go:build go1.17
+// +build go1.17
+
+package gin
+
+import (
+	"bytes"
+	"mime/multipart"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestContextFormFileFailed17(t *testing.T) {
+	buf := new(bytes.Buffer)
+	mw := multipart.NewWriter(buf)
+	mw.Close()
+	c, _ := CreateTestContext(httptest.NewRecorder())
+	c.Request, _ = http.NewRequest("POST", "/", nil)
+	c.Request.Header.Set("Content-Type", mw.FormDataContentType())
+	c.engine.MaxMultipartMemory = 8 << 20
+	assert.Panics(t, func() {
+		f, err := c.FormFile("file")
+		assert.Error(t, err)
+		assert.Nil(t, f)
+	})
+}
diff --git a/context_test.go b/context_test.go
index 176eaae..f9792e3 100644
--- a/context_test.go
+++ b/context_test.go
@@ -87,19 +87,6 @@ func TestContextFormFile(t *testing.T) {
 	assert.NoError(t, c.SaveUploadedFile(f, "test"))
 }
 
-func TestContextFormFileFailed(t *testing.T) {
-	buf := new(bytes.Buffer)
-	mw := multipart.NewWriter(buf)
-	mw.Close()
-	c, _ := CreateTestContext(httptest.NewRecorder())
-	c.Request, _ = http.NewRequest("POST", "/", nil)
-	c.Request.Header.Set("Content-Type", mw.FormDataContentType())
-	c.engine.MaxMultipartMemory = 8 << 20
-	f, err := c.FormFile("file")
-	assert.Error(t, err)
-	assert.Nil(t, f)
-}
-
 func TestContextMultipartForm(t *testing.T) {
 	buf := new(bytes.Buffer)
 	mw := multipart.NewWriter(buf)
@@ -2150,3 +2137,14 @@ func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
 		})
 	}
 }
+
+func TestContextAddParam(t *testing.T) {
+	c := &Context{}
+	id := "id"
+	value := "1"
+	c.AddParam(id, value)
+
+	v, ok := c.Params.Get(id)
+	assert.Equal(t, ok, true)
+	assert.Equal(t, value, v)
+}