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

fix CSRF middleware not being able to extract token from multipart/form-data form #2136

Merged
merged 1 commit into from Mar 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions middleware/extractor.go
Expand Up @@ -168,8 +168,8 @@ func valuesFromCookie(name string) ValuesExtractor {
// valuesFromForm returns a function that extracts values from the form field.
func valuesFromForm(name string) ValuesExtractor {
return func(c echo.Context) ([]string, error) {
if parseErr := c.Request().ParseForm(); parseErr != nil {
return nil, fmt.Errorf("valuesFromForm parse form failed: %w", parseErr)
if c.Request().Form == nil {
_ = c.Request().ParseMultipartForm(32 << 20) // same what `c.Request().FormValue(name)` does
}
values := c.Request().Form[name]
if len(values) == 0 {
Expand Down
39 changes: 29 additions & 10 deletions middleware/extractor_test.go
@@ -1,9 +1,11 @@
package middleware

import (
"bytes"
"fmt"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"mime/multipart"
"net/http"
"net/http/httptest"
"net/url"
Expand Down Expand Up @@ -499,6 +501,25 @@ func TestValuesFromForm(t *testing.T) {
return req
}

exampleMultiPartFormRequest := func(mod func(w *multipart.Writer)) *http.Request {
var b bytes.Buffer
w := multipart.NewWriter(&b)
w.WriteField("name", "Jon Snow")
w.WriteField("emails[]", "jon@labstack.com")
if mod != nil {
mod(w)
}

fw, _ := w.CreateFormFile("upload", "my.file")
fw.Write([]byte(`<div>hi</div>`))
w.Close()

req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(b.String()))
req.Header.Add(echo.HeaderContentType, w.FormDataContentType())

return req
}

var testCases = []struct {
name string
givenRequest *http.Request
Expand All @@ -520,6 +541,14 @@ func TestValuesFromForm(t *testing.T) {
whenName: "emails[]",
expectValues: []string{"jon@labstack.com", "snow@labstack.com"},
},
{
name: "ok, POST multipart/form, multiple value",
givenRequest: exampleMultiPartFormRequest(func(w *multipart.Writer) {
w.WriteField("emails[]", "snow@labstack.com")
}),
whenName: "emails[]",
expectValues: []string{"jon@labstack.com", "snow@labstack.com"},
},
{
name: "ok, GET form, single value",
givenRequest: exampleGetFormRequest(nil),
Expand All @@ -540,16 +569,6 @@ func TestValuesFromForm(t *testing.T) {
whenName: "nope",
expectError: errFormExtractorValueMissing.Error(),
},
{
name: "nok, POST form, form parsing error",
givenRequest: func() *http.Request {
req := httptest.NewRequest(http.MethodPost, "/", nil)
req.Body = nil
return req
}(),
whenName: "name",
expectError: "valuesFromForm parse form failed: missing form body",
},
{
name: "ok, cut values over extractorLimit",
givenRequest: examplePostFormRequest(func(v *url.Values) {
Expand Down