Skip to content

Commit 91330cf

Browse files
committed
refactor: stricter type checking in http query parser
1 parent 11d59a2 commit 91330cf

File tree

1 file changed

+28
-32
lines changed

1 file changed

+28
-32
lines changed

http/parse.go

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -60,33 +60,45 @@ func parseRequest(r *http.Request, root *cmds.Command) (*cmds.Request, error) {
6060
return nil, ErrNotFound
6161
}
6262

63-
opts, stringArgs2 := parseOptions(r)
64-
iopts := make(map[string]interface{}, len(opts))
63+
opts := make(map[string]interface{})
6564
optDefs, err := root.GetOptions(pth)
6665
if err != nil {
6766
return nil, err
6867
}
69-
for k, v := range opts {
70-
iopts[k] = v
71-
if optDef, ok := optDefs[k]; ok {
72-
name := optDef.Names()[0]
73-
if k != name {
74-
iopts[name] = v
75-
delete(iopts, k)
68+
69+
query := r.URL.Query()
70+
// Note: len(v) is guaranteed by the above function to always be greater than 0
71+
for k, v := range query {
72+
if k == "arg" {
73+
stringArgs = append(stringArgs, v...)
74+
} else {
75+
optDef, ok := optDefs[k]
76+
if !ok {
77+
opts[k] = v[0]
78+
continue
7679
}
7780

78-
if optDef.Type() != cmds.Strings && len(v) > 0 {
79-
iopts[name] = v[0]
81+
name := optDef.Names()[0]
82+
opts[name] = v
83+
84+
switch optType := optDef.Type(); optType {
85+
case cmds.Strings:
86+
opts[name] = v
87+
case cmds.Bool, cmds.Int, cmds.Int64, cmds.Uint, cmds.Uint64, cmds.Float, cmds.String:
88+
if len(v) > 1 {
89+
return nil, fmt.Errorf("expected key %s to have only a single value, received %v", name, v)
90+
}
91+
opts[name] = v[0]
92+
default:
93+
return nil, fmt.Errorf("unsupported option type. key: %s, type: %v", k, optType)
8094
}
8195
}
8296
}
8397
// default to setting encoding to JSON
84-
if _, ok := iopts[cmds.EncLong]; !ok {
85-
iopts[cmds.EncLong] = cmds.JSON
98+
if _, ok := opts[cmds.EncLong]; !ok {
99+
opts[cmds.EncLong] = cmds.JSON
86100
}
87101

88-
stringArgs = append(stringArgs, stringArgs2...)
89-
90102
// count required argument definitions
91103
numRequired := 0
92104
for _, argDef := range cmd.Arguments {
@@ -154,7 +166,7 @@ func parseRequest(r *http.Request, root *cmds.Command) (*cmds.Request, error) {
154166
}
155167

156168
ctx := logging.ContextWithLoggable(r.Context(), uuidLoggable())
157-
req, err := cmds.NewRequest(ctx, pth, iopts, args, f, root)
169+
req, err := cmds.NewRequest(ctx, pth, opts, args, f, root)
158170
if err != nil {
159171
return nil, err
160172
}
@@ -168,22 +180,6 @@ func parseRequest(r *http.Request, root *cmds.Command) (*cmds.Request, error) {
168180
return req, err
169181
}
170182

171-
func parseOptions(r *http.Request) (map[string][]string, []string) {
172-
opts := make(map[string][]string)
173-
var args []string
174-
175-
query := r.URL.Query()
176-
for k, v := range query {
177-
if k == "arg" {
178-
args = v
179-
} else {
180-
opts[k] = v
181-
}
182-
}
183-
184-
return opts, args
185-
}
186-
187183
// parseResponse decodes a http.Response to create a cmds.Response
188184
func parseResponse(httpRes *http.Response, req *cmds.Request) (cmds.Response, error) {
189185
res := &Response{

0 commit comments

Comments
 (0)