123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- // Copyright 2014 Alvaro J. Genial. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package form
- import (
- "fmt"
- "io"
- "io/ioutil"
- "net/url"
- "reflect"
- "strconv"
- "time"
- )
- // NewDecoder returns a new form Decoder.
- func NewDecoder(r io.Reader) *Decoder {
- return &Decoder{r, defaultDelimiter, defaultEscape, false, false}
- }
- // Decoder decodes data from a form (application/x-www-form-urlencoded).
- type Decoder struct {
- r io.Reader
- d rune
- e rune
- ignoreUnknown bool
- ignoreCase bool
- }
- // DelimitWith sets r as the delimiter used for composite keys by Decoder d and returns the latter; it is '.' by default.
- func (d *Decoder) DelimitWith(r rune) *Decoder {
- d.d = r
- return d
- }
- // EscapeWith sets r as the escape used for delimiters (and to escape itself) by Decoder d and returns the latter; it is '\\' by default.
- func (d *Decoder) EscapeWith(r rune) *Decoder {
- d.e = r
- return d
- }
- // Decode reads in and decodes form-encoded data into dst.
- func (d Decoder) Decode(dst interface{}) error {
- bs, err := ioutil.ReadAll(d.r)
- if err != nil {
- return err
- }
- vs, err := url.ParseQuery(string(bs))
- if err != nil {
- return err
- }
- v := reflect.ValueOf(dst)
- return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
- }
- // IgnoreUnknownKeys if set to true it will make the Decoder ignore values
- // that are not found in the destination object instead of returning an error.
- func (d *Decoder) IgnoreUnknownKeys(ignoreUnknown bool) {
- d.ignoreUnknown = ignoreUnknown
- }
- // IgnoreCase if set to true it will make the Decoder try to set values in the
- // destination object even if the case does not match.
- func (d *Decoder) IgnoreCase(ignoreCase bool) {
- d.ignoreCase = ignoreCase
- }
- // DecodeString decodes src into dst.
- func (d Decoder) DecodeString(dst interface{}, src string) error {
- vs, err := url.ParseQuery(src)
- if err != nil {
- return err
- }
- v := reflect.ValueOf(dst)
- return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
- }
- // DecodeValues decodes vs into dst.
- func (d Decoder) DecodeValues(dst interface{}, vs url.Values) error {
- v := reflect.ValueOf(dst)
- return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
- }
- // DecodeString decodes src into dst.
- func DecodeString(dst interface{}, src string) error {
- return NewDecoder(nil).DecodeString(dst, src)
- }
- // DecodeValues decodes vs into dst.
- func DecodeValues(dst interface{}, vs url.Values) error {
- return NewDecoder(nil).DecodeValues(dst, vs)
- }
- func (d Decoder) decodeNode(v reflect.Value, n node) (err error) {
- defer func() {
- if e := recover(); e != nil {
- err = fmt.Errorf("%v", e)
- }
- }()
- if v.Kind() == reflect.Slice {
- return fmt.Errorf("could not decode directly into slice; use pointer to slice")
- }
- d.decodeValue(v, n)
- return nil
- }
- func (d Decoder) decodeValue(v reflect.Value, x interface{}) {
- t := v.Type()
- k := v.Kind()
- if k == reflect.Ptr && v.IsNil() {
- v.Set(reflect.New(t.Elem()))
- }
- if unmarshalValue(v, x) {
- return
- }
- empty := isEmpty(x)
- switch k {
- case reflect.Ptr:
- d.decodeValue(v.Elem(), x)
- return
- case reflect.Interface:
- if !v.IsNil() {
- d.decodeValue(v.Elem(), x)
- return
- } else if empty {
- return // Allow nil interfaces only if empty.
- } else {
- panic("form: cannot decode non-empty value into into nil interface")
- }
- }
- if empty {
- v.Set(reflect.Zero(t)) // Treat the empty string as the zero value.
- return
- }
- switch k {
- case reflect.Struct:
- if t.ConvertibleTo(timeType) {
- d.decodeTime(v, x)
- } else if t.ConvertibleTo(urlType) {
- d.decodeURL(v, x)
- } else {
- d.decodeStruct(v, x)
- }
- case reflect.Slice:
- d.decodeSlice(v, x)
- case reflect.Array:
- d.decodeArray(v, x)
- case reflect.Map:
- d.decodeMap(v, x)
- case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func:
- panic(t.String() + " has unsupported kind " + k.String())
- default:
- d.decodeBasic(v, x)
- }
- }
- func (d Decoder) decodeStruct(v reflect.Value, x interface{}) {
- t := v.Type()
- for k, c := range getNode(x) {
- if f, ok := findField(v, k, d.ignoreCase); !ok && k == "" {
- panic(getString(x) + " cannot be decoded as " + t.String())
- } else if !ok {
- if !d.ignoreUnknown {
- panic(k + " doesn't exist in " + t.String())
- }
- } else if !f.CanSet() {
- panic(k + " cannot be set in " + t.String())
- } else {
- d.decodeValue(f, c)
- }
- }
- }
- func (d Decoder) decodeMap(v reflect.Value, x interface{}) {
- t := v.Type()
- if v.IsNil() {
- v.Set(reflect.MakeMap(t))
- }
- for k, c := range getNode(x) {
- i := reflect.New(t.Key()).Elem()
- d.decodeValue(i, k)
- w := v.MapIndex(i)
- if w.IsValid() { // We have an actual element value to decode into.
- if w.Kind() == reflect.Interface {
- w = w.Elem()
- }
- w = reflect.New(w.Type()).Elem()
- } else if t.Elem().Kind() != reflect.Interface { // The map's element type is concrete.
- w = reflect.New(t.Elem()).Elem()
- } else {
- // The best we can do here is to decode as either a string (for scalars) or a map[string]interface {} (for the rest).
- // We could try to guess the type based on the string (e.g. true/false => bool) but that'll get ugly fast,
- // especially if we have to guess the kind (slice vs. array vs. map) and index type (e.g. string, int, etc.)
- switch c.(type) {
- case node:
- w = reflect.MakeMap(stringMapType)
- case string:
- w = reflect.New(stringType).Elem()
- default:
- panic("value is neither node nor string")
- }
- }
- d.decodeValue(w, c)
- v.SetMapIndex(i, w)
- }
- }
- func (d Decoder) decodeArray(v reflect.Value, x interface{}) {
- t := v.Type()
- for k, c := range getNode(x) {
- i, err := strconv.Atoi(k)
- if err != nil {
- panic(k + " is not a valid index for type " + t.String())
- }
- if l := v.Len(); i >= l {
- panic("index is above array size")
- }
- d.decodeValue(v.Index(i), c)
- }
- }
- func (d Decoder) decodeSlice(v reflect.Value, x interface{}) {
- t := v.Type()
- if t.Elem().Kind() == reflect.Uint8 {
- // Allow, but don't require, byte slices to be encoded as a single string.
- if s, ok := x.(string); ok {
- v.SetBytes([]byte(s))
- return
- }
- }
- // NOTE: Implicit indexing is currently done at the parseValues level,
- // so if if an implicitKey reaches here it will always replace the last.
- implicit := 0
- for k, c := range getNode(x) {
- var i int
- if k == implicitKey {
- i = implicit
- implicit++
- } else {
- explicit, err := strconv.Atoi(k)
- if err != nil {
- panic(k + " is not a valid index for type " + t.String())
- }
- i = explicit
- implicit = explicit + 1
- }
- // "Extend" the slice if it's too short.
- if l := v.Len(); i >= l {
- delta := i - l + 1
- v.Set(reflect.AppendSlice(v, reflect.MakeSlice(t, delta, delta)))
- }
- d.decodeValue(v.Index(i), c)
- }
- }
- func (d Decoder) decodeBasic(v reflect.Value, x interface{}) {
- t := v.Type()
- switch k, s := t.Kind(), getString(x); k {
- case reflect.Bool:
- if b, e := strconv.ParseBool(s); e == nil {
- v.SetBool(b)
- } else {
- panic("could not parse bool from " + strconv.Quote(s))
- }
- case reflect.Int,
- reflect.Int8,
- reflect.Int16,
- reflect.Int32,
- reflect.Int64:
- if i, e := strconv.ParseInt(s, 10, 64); e == nil {
- v.SetInt(i)
- } else {
- panic("could not parse int from " + strconv.Quote(s))
- }
- case reflect.Uint,
- reflect.Uint8,
- reflect.Uint16,
- reflect.Uint32,
- reflect.Uint64:
- if u, e := strconv.ParseUint(s, 10, 64); e == nil {
- v.SetUint(u)
- } else {
- panic("could not parse uint from " + strconv.Quote(s))
- }
- case reflect.Float32,
- reflect.Float64:
- if f, e := strconv.ParseFloat(s, 64); e == nil {
- v.SetFloat(f)
- } else {
- panic("could not parse float from " + strconv.Quote(s))
- }
- case reflect.Complex64,
- reflect.Complex128:
- var c complex128
- if n, err := fmt.Sscanf(s, "%g", &c); n == 1 && err == nil {
- v.SetComplex(c)
- } else {
- panic("could not parse complex from " + strconv.Quote(s))
- }
- case reflect.String:
- v.SetString(s)
- default:
- panic(t.String() + " has unsupported kind " + k.String())
- }
- }
- func (d Decoder) decodeTime(v reflect.Value, x interface{}) {
- t := v.Type()
- s := getString(x)
- // TODO: Find a more efficient way to do this.
- for _, f := range allowedTimeFormats {
- if p, err := time.Parse(f, s); err == nil {
- v.Set(reflect.ValueOf(p).Convert(v.Type()))
- return
- }
- }
- panic("cannot decode string `" + s + "` as " + t.String())
- }
- func (d Decoder) decodeURL(v reflect.Value, x interface{}) {
- t := v.Type()
- s := getString(x)
- if u, err := url.Parse(s); err == nil {
- v.Set(reflect.ValueOf(*u).Convert(v.Type()))
- return
- }
- panic("cannot decode string `" + s + "` as " + t.String())
- }
- var allowedTimeFormats = []string{
- "2006-01-02T15:04:05.999999999Z07:00",
- "2006-01-02T15:04:05.999999999Z07",
- "2006-01-02T15:04:05.999999999Z",
- "2006-01-02T15:04:05.999999999",
- "2006-01-02T15:04:05Z07:00",
- "2006-01-02T15:04:05Z07",
- "2006-01-02T15:04:05Z",
- "2006-01-02T15:04:05",
- "2006-01-02T15:04Z",
- "2006-01-02T15:04",
- "2006-01-02T15Z",
- "2006-01-02T15",
- "2006-01-02",
- "2006-01",
- "2006",
- "15:04:05.999999999Z07:00",
- "15:04:05.999999999Z07",
- "15:04:05.999999999Z",
- "15:04:05.999999999",
- "15:04:05Z07:00",
- "15:04:05Z07",
- "15:04:05Z",
- "15:04:05",
- "15:04Z",
- "15:04",
- "15Z",
- "15",
- }
|