aicra/internal/reqdata/parameter.go

129 lines
2.7 KiB
Go
Raw Normal View History

package reqdata
2018-06-01 08:51:51 +00:00
2019-11-19 15:14:50 +00:00
import (
"encoding/json"
"fmt"
"reflect"
2020-02-28 16:50:55 +00:00
"git.xdrm.io/go/aicra/internal/cerr"
2019-11-19 15:14:50 +00:00
)
2020-02-28 16:50:55 +00:00
// ErrUnknownType is returned when encountering an unknown type
const ErrUnknownType = cerr.Error("unknown type")
// ErrInvalidJSON is returned when json parse failed
const ErrInvalidJSON = cerr.Error("invalid json")
// ErrInvalidRootType is returned when json is a map
const ErrInvalidRootType = cerr.Error("invalid json root type")
2019-04-30 22:02:28 +00:00
// Parameter represents an http request parameter
// that can be of type URL, GET, or FORM (multipart, json, urlencoded)
type Parameter struct {
// whether the value has been json-parsed
// for optimisation purpose, parameters are only parsed
// if they are required by the current service
2019-04-30 22:02:28 +00:00
Parsed bool
// whether the value is a file
File bool
// the actual parameter value
Value interface{}
}
2018-06-01 08:51:51 +00:00
// Parse parameter (json-like) if not already done
2020-02-28 16:50:55 +00:00
func (i *Parameter) Parse() error {
2018-06-01 08:51:51 +00:00
/* (1) Stop if already parsed or nil*/
if i.Parsed || i.Value == nil {
2020-02-28 16:50:55 +00:00
return nil
2018-06-01 08:51:51 +00:00
}
/* (2) Try to parse value */
2020-02-28 16:50:55 +00:00
parsed, err := parseParameter(i.Value)
if err != nil {
return err
}
i.Parsed = true
2020-02-28 16:50:55 +00:00
i.Value = parsed
2018-06-01 08:51:51 +00:00
2020-02-28 16:50:55 +00:00
return nil
2018-06-01 08:51:51 +00:00
}
2019-11-19 15:14:50 +00:00
// parseParameter parses http GET/POST data
// - []string
// - size = 1 : return json of first element
// - size > 1 : return array of json elements
// - string : return json if valid, else return raw string
2020-02-28 16:50:55 +00:00
func parseParameter(data interface{}) (interface{}, error) {
2019-11-19 15:14:50 +00:00
dtype := reflect.TypeOf(data)
dvalue := reflect.ValueOf(data)
switch dtype.Kind() {
/* (1) []string -> recursive */
case reflect.Slice:
// 1. ignore empty
2019-11-19 15:14:50 +00:00
if dvalue.Len() == 0 {
2020-02-28 16:50:55 +00:00
return data, nil
2019-11-19 15:14:50 +00:00
}
// 2. parse each element recursively
2019-11-19 15:14:50 +00:00
result := make([]interface{}, dvalue.Len())
for i, l := 0, dvalue.Len(); i < l; i++ {
element := dvalue.Index(i)
// ignore non-string
if element.Kind() != reflect.String {
result[i] = element.Interface()
2019-11-19 15:14:50 +00:00
continue
}
2020-02-28 16:50:55 +00:00
parsed, err := parseParameter(element.String())
if err != nil {
return data, err
}
result[i] = parsed
2019-11-19 15:14:50 +00:00
}
2020-02-28 16:50:55 +00:00
return result, nil
2019-11-19 15:14:50 +00:00
/* (2) string -> parse */
case reflect.String:
// build json wrapper
wrapper := fmt.Sprintf("{\"wrapped\":%s}", dvalue.String())
// try to parse as json
var result interface{}
err := json.Unmarshal([]byte(wrapper), &result)
// return if success
if err == nil {
mapval, ok := result.(map[string]interface{})
if !ok {
2020-02-28 16:50:55 +00:00
return dvalue.String(), ErrInvalidRootType
2019-11-19 15:14:50 +00:00
}
wrapped, ok := mapval["wrapped"]
if !ok {
2020-02-28 16:50:55 +00:00
return dvalue.String(), ErrInvalidJSON
2019-11-19 15:14:50 +00:00
}
2020-02-28 16:50:55 +00:00
return wrapped, nil
2019-11-19 15:14:50 +00:00
}
// else return as string
2020-02-28 16:50:55 +00:00
return dvalue.String(), nil
2019-11-19 15:14:50 +00:00
}
/* (3) NIL if unknown type */
return dvalue.Interface(), nil
2019-11-19 15:14:50 +00:00
}