X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/ea6f25f0dde5c750eacea29662c19149c7800134..HEAD:/lib/controller/router/request.go diff --git a/lib/controller/router/request.go b/lib/controller/router/request.go index 977a15f3ab..254a8b7fab 100644 --- a/lib/controller/router/request.go +++ b/lib/controller/router/request.go @@ -55,15 +55,31 @@ func guessAndParse(k, v string) (interface{}, error) { // foo=["bar","baz"]? } -// Parse req as an Arvados V1 API request and return the request -// parameters. +// Return a map of incoming HTTP request parameters. Also load +// parameters into opts, unless opts is nil. // // If the request has a parameter whose name is attrsKey (e.g., // "collection"), it is renamed to "attrs". -func (rtr *router) loadRequestParams(req *http.Request, attrsKey string) (map[string]interface{}, error) { +func (rtr *router) loadRequestParams(req *http.Request, attrsKey string, opts interface{}) (map[string]interface{}, error) { + // Here we call ParseForm and ParseMultipartForm explicitly + // (even though ParseMultipartForm calls ParseForm if + // necessary) to ensure we catch errors encountered in + // ParseForm. In the non-multipart-form case, + // ParseMultipartForm returns ErrNotMultipart and hides the + // ParseForm error. err := req.ParseForm() + if err == nil { + err = req.ParseMultipartForm(int64(rtr.config.MaxRequestSize)) + if err == http.ErrNotMultipart { + err = nil + } + } if err != nil { - return nil, httpError(http.StatusBadRequest, err) + if err.Error() == "http: request body too large" { + return nil, httpError(http.StatusRequestEntityTooLarge, err) + } else { + return nil, httpError(http.StatusBadRequest, err) + } } params := map[string]interface{}{} @@ -125,15 +141,35 @@ func (rtr *router) loadRequestParams(req *http.Request, attrsKey string) (map[st delete(params, attrsKey) } - if order, ok := params["order"].(string); ok { + for _, paramname := range []string{"include", "order"} { // We must accept strings ("foo, bar desc") and arrays // (["foo", "bar desc"]) because RailsAPI does. // Convert to an array here before trying to unmarshal // into options structs. - if order == "" { - delete(params, "order") - } else { - params["order"] = strings.Split(order, ",") + if val, ok := params[paramname].(string); ok { + if val == "" { + delete(params, paramname) + } else { + params[paramname] = strings.Split(val, ",") + } + } + } + + if opts != nil { + // Load all path, query, and form params into opts. + err = rtr.transcode(params, opts) + if err != nil { + return nil, fmt.Errorf("transcode: %w", err) + } + + // Special case: if opts has Method or Header fields, load the + // request method/header. + err = rtr.transcode(struct { + Method string + Header http.Header + }{req.Method, req.Header}, opts) + if err != nil { + return nil, fmt.Errorf("transcode: %w", err) } } @@ -170,6 +206,9 @@ var boolParams = map[string]bool{ "redirect_to_new_user": true, "send_notification_email": true, "bypass_federation": true, + "recursive": true, + "exclude_home_project": true, + "no_forward": true, } func stringToBool(s string) bool {