Skip to content

Commit

Permalink
feat: Add method PostFormArray to app.RequestContext. (#1172)
Browse files Browse the repository at this point in the history
  • Loading branch information
snowykami authored Sep 2, 2024
1 parent c29f150 commit 4a8a710
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
40 changes: 40 additions & 0 deletions pkg/app/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,17 @@ func (ctx *RequestContext) multipartFormValue(key string) (string, bool) {
return "", false
}

func (ctx *RequestContext) multipartFormValueArray(key string) ([]string, bool) {
mf, err := ctx.MultipartForm()
if err == nil && mf.Value != nil {
vv := mf.Value[key]
if len(vv) > 0 {
return vv, true
}
}
return nil, false
}

func (ctx *RequestContext) RequestBodyStream() io.Reader {
return ctx.Request.BodyStream()
}
Expand Down Expand Up @@ -1366,6 +1377,13 @@ func (ctx *RequestContext) PostForm(key string) string {
return value
}

// PostFormArray returns the specified key from a POST urlencoded form or multipart form
// when it exists, otherwise it returns an empty array `([])`.
func (ctx *RequestContext) PostFormArray(key string) []string {
values, _ := ctx.GetPostFormArray(key)
return values
}

// DefaultPostForm returns the specified key from a POST urlencoded form or multipart form
// when it exists, otherwise it returns the specified defaultValue string.
//
Expand Down Expand Up @@ -1393,6 +1411,28 @@ func (ctx *RequestContext) GetPostForm(key string) (string, bool) {
return ctx.multipartFormValue(key)
}

// GetPostFormArray is like PostFormArray(key). It returns the specified key from a POST urlencoded
// form or multipart form when it exists `([]string, true)` (even when the value is an empty string),
// otherwise it returns ([]string(nil), false).
//
// For example, during a PATCH request to update the item's tags:
//
// tag=tag1 tag=tag2 tag=tag3 --> (["tag1", "tag2", "tag3"], true) := GetPostFormArray("tags") // set tags to ["tag1", "tag2", "tag3"]
// tags= --> (nil, true) := GetPostFormArray("tags") // set tags to nil
// --> (nil, false) := GetPostFormArray("tags") // do nothing with tags
func (ctx *RequestContext) GetPostFormArray(key string) ([]string, bool) {
vs := ctx.PostArgs().PeekAll(key)
values := make([]string, len(vs))
for i, v := range vs {
values[i] = string(v)
}
if len(values) == 0 {
return ctx.multipartFormValueArray(key)
} else {
return values, true
}
}

// bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function.
func bodyAllowedForStatus(status int) bool {
switch {
Expand Down
42 changes: 42 additions & 0 deletions pkg/app/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,40 @@ hello=world`)
}
}

func TestPostFormArray(t *testing.T) {
t.Parallel()

ctx := makeCtxByReqString(t, `POST /upload HTTP/1.1
Host: localhost:10000
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJwfATyF8tmxSJnLg
Content-Length: 521
------WebKitFormBoundaryJwfATyF8tmxSJnLg
Content-Disposition: form-data; name="tag"
red
------WebKitFormBoundaryJwfATyF8tmxSJnLg
Content-Disposition: form-data; name="tag"
green
------WebKitFormBoundaryJwfATyF8tmxSJnLg
Content-Disposition: form-data; name="tag"
blue
------WebKitFormBoundaryJwfATyF8tmxSJnLg--
`)
assert.DeepEqual(t, []string{"red", "green", "blue"}, ctx.PostFormArray("tag"))

ctx = makeCtxByReqString(t, `POST /upload HTTP/1.1
Host: localhost:10000
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 26
tag=red&tag=green&tag=blue
`)
assert.DeepEqual(t, []string{"red", "green", "blue"}, ctx.PostFormArray("tag"))
}

func TestDefaultPostForm(t *testing.T) {
ctx := makeCtxByReqString(t, `POST /upload HTTP/1.1
Host: localhost:10000
Expand Down Expand Up @@ -930,6 +964,14 @@ func TestGetPostForm(t *testing.T) {
assert.DeepEqual(t, true, exists)
}

func TestGetPostFormArray(t *testing.T) {
c := NewContext(0)
c.Request.Header.SetContentTypeBytes([]byte(consts.MIMEApplicationHTMLForm))
c.Request.SetBodyString("a=1&b=2&b=3")
v, _ := c.GetPostFormArray("b")
assert.DeepEqual(t, []string{"2", "3"}, v)
}

func TestRemoteAddr(t *testing.T) {
c := NewContext(0)
c.Request.SetRequestURI("http://aaa.com?a=1&b=")
Expand Down

0 comments on commit 4a8a710

Please sign in to comment.