X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/3a28574402bbeb5df3ea8f32f2f60a7a2f20e4fa..8b17f2ab7bcfcad4dcf9e3aa2cc203417053b23e:/lib/controller/router/request.go diff --git a/lib/controller/router/request.go b/lib/controller/router/request.go index 377f7243c0..eae9e0a8ce 100644 --- a/lib/controller/router/request.go +++ b/lib/controller/router/request.go @@ -13,9 +13,48 @@ import ( "strconv" "strings" - "github.com/julienschmidt/httprouter" + "github.com/gorilla/mux" ) +func guessAndParse(k, v string) (interface{}, error) { + // All of these form values arrive as strings, so we need some + // type-guessing to accept non-string inputs: + // + // Values for parameters that take ints (limit=1) or bools + // (include_trash=1) are parsed accordingly. + // + // "null" and "" are nil. + // + // Values that look like JSON objects, arrays, or strings are + // parsed as JSON. + // + // The rest are left as strings. + switch { + case intParams[k]: + return strconv.ParseInt(v, 10, 64) + case boolParams[k]: + return stringToBool(v), nil + case v == "null" || v == "": + return nil, nil + case strings.HasPrefix(v, "["): + var j []interface{} + err := json.Unmarshal([]byte(v), &j) + return j, err + case strings.HasPrefix(v, "{"): + var j map[string]interface{} + err := json.Unmarshal([]byte(v), &j) + return j, err + case strings.HasPrefix(v, "\""): + var j string + err := json.Unmarshal([]byte(v), &j) + return j, err + default: + return v, nil + } + // TODO: Need to accept "?foo[]=bar&foo[]=baz" as + // foo=["bar","baz"]? +} + // Parse req as an Arvados V1 API request and return the request // parameters. // @@ -33,56 +72,11 @@ func (rtr *router) loadRequestParams(req *http.Request, attrsKey string) (map[st // Content-Type is application/x-www-form-urlencoded -- the // request body. for k, values := range req.Form { - // All of these form values arrive as strings, so we - // need some type-guessing to accept non-string - // inputs: - // - // Values for parameters that take ints (limit=1) or - // bools (include_trash=1) are parsed accordingly. - // - // "null" and "" are nil. - // - // Values that look like JSON objects, arrays, or - // strings are parsed as JSON. - // - // The rest are left as strings. for _, v := range values { - switch { - case intParams[k]: - params[k], err = strconv.ParseInt(v, 10, 64) - if err != nil { - return nil, err - } - case boolParams[k]: - params[k] = stringToBool(v) - case v == "null" || v == "": - params[k] = nil - case strings.HasPrefix(v, "["): - var j []interface{} - err := json.Unmarshal([]byte(v), &j) - if err != nil { - return nil, err - } - params[k] = j - case strings.HasPrefix(v, "{"): - var j map[string]interface{} - err := json.Unmarshal([]byte(v), &j) - if err != nil { - return nil, err - } - params[k] = j - case strings.HasPrefix(v, "\""): - var j string - err := json.Unmarshal([]byte(v), &j) - if err != nil { - return nil, err - } - params[k] = j - default: - params[k] = v + params[k], err = guessAndParse(k, v) + if err != nil { + return nil, err } - // TODO: Need to accept "?foo[]=bar&foo[]=baz" - // as foo=["bar","baz"]? } } @@ -98,7 +92,20 @@ func (rtr *router) loadRequestParams(req *http.Request, attrsKey string) (map[st return nil, httpError(http.StatusBadRequest, err) } for k, v := range jsonParams { - params[k] = v + switch v := v.(type) { + case string: + // The Ruby "arv" cli tool sends a + // JSON-encode params map with + // JSON-encoded values. + dec, err := guessAndParse(k, v) + if err != nil { + return nil, err + } + jsonParams[k] = dec + params[k] = dec + default: + params[k] = v + } } if attrsKey != "" && params[attrsKey] == nil { // Copy top-level parameters from JSON request @@ -109,9 +116,8 @@ func (rtr *router) loadRequestParams(req *http.Request, attrsKey string) (map[st } } - routeParams, _ := req.Context().Value(httprouter.ParamsKey).(httprouter.Params) - for _, p := range routeParams { - params[p.Key] = p.Value + for k, v := range mux.Vars(req) { + params[k] = v } if v, ok := params[attrsKey]; ok && attrsKey != "" { @@ -157,10 +163,15 @@ var intParams = map[string]bool{ } var boolParams = map[string]bool{ - "distinct": true, - "ensure_unique_name": true, - "include_trash": true, - "include_old_versions": true, + "distinct": true, + "ensure_unique_name": true, + "include_trash": true, + "include_old_versions": true, + "redirect_to_new_user": true, + "send_notification_email": true, + "bypass_federation": true, + "recursive": true, + "exclude_home_project": true, } func stringToBool(s string) bool {