2019-05-01 11:44:45 +00:00
|
|
|
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
|
2019-05-02 05:54:45 +00:00
|
|
|
// 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
|
|
|
|
}
|
2020-02-28 17:41:05 +00:00
|
|
|
|
|
|
|
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:
|
|
|
|
|
2020-03-02 21:24:36 +00:00
|
|
|
// 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
|
|
|
}
|
|
|
|
|
2020-03-02 21:24:36 +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 {
|
2020-03-02 21:42:17 +00:00
|
|
|
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 */
|
2020-02-28 16:50:55 +00:00
|
|
|
return dvalue, ErrUnknownType
|
2019-11-19 15:14:50 +00:00
|
|
|
|
|
|
|
}
|