19597: Parse multipart/form-data request body. 19597-multipart-request
authorTom Clegg <tom@curii.com>
Wed, 21 Dec 2022 19:31:26 +0000 (14:31 -0500)
committerTom Clegg <tom@curii.com>
Wed, 21 Dec 2022 19:31:26 +0000 (14:31 -0500)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@curii.com>

lib/controller/router/request.go
lib/controller/router/request_test.go

index 31f2e1d7baf5098a377ffe9d1acd7b737958231d..c0a2f23cc12c0ed2ddaf2566cb5bc6eff494fbf1 100644 (file)
@@ -62,6 +62,12 @@ func guessAndParse(k, v string) (interface{}, error) {
 // "collection"), it is renamed to "attrs".
 func (rtr *router) loadRequestParams(req *http.Request, attrsKey string) (map[string]interface{}, error) {
        err := req.ParseForm()
+       if err == nil {
+               err = req.ParseMultipartForm(int64(rtr.config.MaxRequestSize))
+               if err == http.ErrNotMultipart {
+                       err = nil
+               }
+       }
        if err != nil {
                if err.Error() == "http: request body too large" {
                        return nil, httpError(http.StatusRequestEntityTooLarge, err)
index 4544a6bb65f4692af7ffb15b190f6803c6f1bbc9..82f1fb8e89df9e8085b0a0e90a8a467365c0caa0 100644 (file)
@@ -8,6 +8,7 @@ import (
        "bytes"
        "encoding/json"
        "io"
+       "mime/multipart"
        "net/http"
        "net/http/httptest"
        "net/url"
@@ -116,7 +117,7 @@ func (tr *testReq) Request() *http.Request {
        }
        if tr.json {
                req.Header.Set("Content-Type", "application/json")
-       } else {
+       } else if tr.header.Get("Content-Type") == "" {
                req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
        }
        for k, v := range tr.header {
@@ -131,11 +132,18 @@ func (tr *testReq) bodyContent() string {
 
 func (s *RouterSuite) TestAttrsInBody(c *check.C) {
        attrs := map[string]interface{}{"foo": "bar"}
+
+       multipartBody := new(bytes.Buffer)
+       multipartWriter := multipart.NewWriter(multipartBody)
+       multipartWriter.WriteField("attrs", `{"foo":"bar"}`)
+       multipartWriter.Close()
+
        for _, tr := range []testReq{
                {attrsKey: "model_name", json: true, attrs: attrs},
                {attrsKey: "model_name", json: true, attrs: attrs, jsonAttrsTop: true},
                {attrsKey: "model_name", json: true, attrs: attrs, jsonAttrsTop: true, jsonStringParam: true},
                {attrsKey: "model_name", json: true, attrs: attrs, jsonAttrsTop: false, jsonStringParam: true},
+               {body: multipartBody, header: http.Header{"Content-Type": []string{multipartWriter.FormDataContentType()}}},
        } {
                c.Logf("tr: %#v", tr)
                req := tr.Request()