Merge branch '15795-sys-root-token' refs #15795
[arvados.git] / lib / controller / router / request.go
index 47d8bb1109d645b0ca3f266fc29f1b6b5d84a62a..4d18395b6a87b7cc7aa421f78e118c18551453ca 100644 (file)
@@ -13,7 +13,7 @@ import (
        "strconv"
        "strings"
 
-       "github.com/julienschmidt/httprouter"
+       "github.com/gorilla/mux"
 )
 
 // Parse req as an Arvados V1 API request and return the request
@@ -27,9 +27,32 @@ func (rtr *router) loadRequestParams(req *http.Request, attrsKey string) (map[st
                return nil, httpError(http.StatusBadRequest, err)
        }
        params := map[string]interface{}{}
+
+       // Load parameters from req.Form, which (after
+       // req.ParseForm()) includes the query string and -- when
+       // 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 == "":
@@ -55,11 +78,6 @@ func (rtr *router) loadRequestParams(req *http.Request, attrsKey string) (map[st
                                        return nil, err
                                }
                                params[k] = j
-                       case k == "limit" || k == "offset":
-                               params[k], err = strconv.ParseInt(v, 10, 64)
-                               if err != nil {
-                                       return nil, err
-                               }
                        default:
                                params[k] = v
                        }
@@ -91,19 +109,11 @@ 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 != "" {
-               if v, ok := v.(map[string]interface{}); ok {
-                       // Delete field(s) that appear in responses
-                       // but not in update attrs, so clients can
-                       // fetch-modify-update.
-                       delete(v, "etag")
-                       delete(v, "unsigned_manifest_text")
-               }
                params["attrs"] = v
                delete(params, attrsKey)
        }
@@ -140,6 +150,11 @@ func (rtr *router) transcode(src interface{}, dst interface{}) error {
        return err
 }
 
+var intParams = map[string]bool{
+       "limit":  true,
+       "offset": true,
+}
+
 var boolParams = map[string]bool{
        "distinct":             true,
        "ensure_unique_name":   true,