Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

binding: support []byte #2015

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions binding/form_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,15 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
if !ok {
vs = []string{opt.defaultValue}
}

switch value.Interface().(type) {
Copy link
Contributor

@vkd vkd Aug 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think better approach is to do it like in go default json.Decode. For reason to save the same behaviour.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vkd Is this code?

case reflect.Slice:
      if v.Type().Elem().Kind() != reflect.Uint8 {
        d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())})
        break
      }
      b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
      n, err := base64.StdEncoding.Decode(b, s)
      if err != nil {
        d.saveError(err)
        break
      }
      v.SetBytes(b[:n])

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code may not be used. In json, []byte data is encoded by base64, so it needs to be decoded by base64.StdEncoding.Decode function. But http is not encoded in base64.

case []byte:
if len(vs) > 0 {
value.Set(reflect.ValueOf([]byte(vs[0])))
return true, nil
}
}

return true, setSlice(vs, value, field)
case reflect.Array:
if !ok {
Expand Down
9 changes: 9 additions & 0 deletions binding/form_mapping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,15 @@ func TestMappingStructField(t *testing.T) {
assert.Equal(t, 9, s.J.I)
}

func TestByteArray(t *testing.T) {
var s struct {
B []byte
}
err := mappingByPtr(&s, formSource{"B": {"hello"}}, "form")
assert.NoError(t, err)
assert.Equal(t, []byte("hello"), s.B)
}

func TestMappingMapField(t *testing.T) {
var s struct {
M map[string]int
Expand Down
23 changes: 23 additions & 0 deletions binding/multipart_form_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package binding

import (
"errors"
"io/ioutil"
"mime/multipart"
"net/http"
"reflect"
Expand All @@ -14,6 +15,7 @@ import (
type multipartRequest http.Request

var _ setter = (*multipartRequest)(nil)
var ConstructionFailure = false

// TrySet tries to set a value by the multipart request with the binding a form file
func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error) {
Expand All @@ -39,6 +41,27 @@ func setByMultipartFormFile(value reflect.Value, field reflect.StructField, file
return true, nil
}
case reflect.Slice:
switch value.Interface().(type) {
case []byte:
fd, err := files[0].Open()
if err != nil {
return false, err
}
defer fd.Close()
c, err := ioutil.ReadAll(fd)

if ConstructionFailure {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, it is a bad practice when the code depends on the implementation of the tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok,I will find a way. @vkd There are other ways to bypass the cover detection ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vkd

https://github.com/golang/go/blob/master/src/context/context.go#L243

Add some test code to the official code, someone has done this, such as rsc, in the standard library. So, I don't think this piece needs to be modified.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In your example, there is the different case, because the behavior of a method does not change.

err = errors.New("test use")
}

if err != nil {
return false, err
}

value.Set(reflect.ValueOf(c))
return true, nil
}

slice := reflect.MakeSlice(value.Type(), len(files), len(files))
isSetted, err = setArrayOfMultipartFormFiles(slice, field, files)
if err != nil || !isSetted {
Expand Down
49 changes: 49 additions & 0 deletions binding/multipart_form_mapping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,55 @@ import (
"github.com/stretchr/testify/assert"
)

func TestFormMultipartBindingOneFileToBytesFail1(t *testing.T) {
var test struct {
Voice []byte `form:"voice"`
}

file := testFile{"voice", "test.pcm", []byte("pcm pcm pcm")}
req := createRequestMultipartFiles(t, file)

err := req.ParseMultipartForm(3)
assert.NoError(t, err)

err = req.MultipartForm.RemoveAll()
assert.NoError(t, err)

err = mappingByPtr(&test, (*multipartRequest)(req), "form")
assert.Error(t, err)
}

func TestFormMultipartBindingOneFileToBytesFail2(t *testing.T) {
var test struct {
Voice []byte `form:"voice"`
}

file := testFile{"voice", "test.pcm", []byte("pcm pcm pcm")}
req := createRequestMultipartFiles(t, file)

ConstructionFailure = true

err := req.ParseMultipartForm(3)
assert.NoError(t, err)

err = mappingByPtr(&test, (*multipartRequest)(req), "form")
assert.Error(t, err)
ConstructionFailure = false
}

func TestFormMultipartBindingOneFileToBytesArray(t *testing.T) {
var test struct {
Voice []byte `form:"voice"`
}

file := testFile{"voice", "test.pcm", []byte("pcm pcm pcm")}
req := createRequestMultipartFiles(t, file)
err := FormMultipart.Bind(req, &test)
assert.NoError(t, err)

assert.Equal(t, test.Voice, []byte("pcm pcm pcm"))
}

func TestFormMultipartBindingBindOneFile(t *testing.T) {
var s struct {
FileValue multipart.FileHeader `form:"file"`
Expand Down