github.com/twilio/twilio-go@v1.20.1/client/form/encode.go (about)

     1  // Forked code from https://github.com/ajg/form
     2  
     3  // Copyright 2014 Alvaro J. Genial. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  // nolint
     7  package form
     8  
     9  import (
    10  	"encoding"
    11  	"errors"
    12  	"fmt"
    13  	"io"
    14  	"net/url"
    15  	"reflect"
    16  	"strconv"
    17  	"strings"
    18  	"time"
    19  )
    20  
    21  // NewEncoder returns a new form Encoder.
    22  func NewEncoder(w io.Writer) *Encoder {
    23  	return &Encoder{w, defaultDelimiter, defaultEscape, false}
    24  }
    25  
    26  // Encoder provides a way to encode to a Writer.
    27  type Encoder struct {
    28  	w io.Writer
    29  	d rune
    30  	e rune
    31  	z bool
    32  }
    33  
    34  // DelimitWith sets r as the delimiter used for composite keys by Encoder e and returns the latter; it is '.' by default.
    35  func (e *Encoder) DelimitWith(r rune) *Encoder {
    36  	e.d = r
    37  	return e
    38  }
    39  
    40  // EscapeWith sets r as the escape used for delimiters (and to escape itself) by Encoder e and returns the latter; it is '\\' by default.
    41  func (e *Encoder) EscapeWith(r rune) *Encoder {
    42  	e.e = r
    43  	return e
    44  }
    45  
    46  // KeepZeros sets whether Encoder e should keep zero (default) values in their literal form when encoding, and returns the former; by default zero values are not kept, but are rather encoded as the empty string.
    47  func (e *Encoder) KeepZeros(z bool) *Encoder {
    48  	e.z = z
    49  	return e
    50  }
    51  
    52  // Encode encodes dst as form and writes it out using the Encoder's Writer.
    53  func (e Encoder) Encode(dst interface{}) error {
    54  	v := reflect.ValueOf(dst)
    55  	n, err := encodeToNode(v, e.z)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	s := n.values(e.d, e.e).Encode()
    60  	l, err := io.WriteString(e.w, s)
    61  	switch {
    62  	case err != nil:
    63  		return err
    64  	case l != len(s):
    65  		return errors.New("could not write data completely")
    66  	}
    67  	return nil
    68  }
    69  
    70  // EncodeToString encodes dst as a form and returns it as a string.
    71  func EncodeToString(dst interface{}) (string, error) {
    72  	return EncodeToStringWith(dst, defaultDelimiter, defaultEscape, defaultKeepZeros)
    73  }
    74  
    75  // EncodeToStringWith encodes dst as a form with delimiter d, escape e, keeping zero values if z, and returns it as a string.
    76  func EncodeToStringWith(dst interface{}, d rune, e rune, z bool) (string, error) {
    77  	v := reflect.ValueOf(dst)
    78  	n, err := encodeToNode(v, z)
    79  	if err != nil {
    80  		return "", err
    81  	}
    82  	vs := n.values(d, e)
    83  	return vs.Encode(), nil
    84  }
    85  
    86  // EncodeToValues encodes dst as a form and returns it as Values.
    87  func EncodeToValues(dst interface{}) (url.Values, error) {
    88  	return EncodeToValuesWith(dst, defaultDelimiter, defaultEscape, defaultKeepZeros)
    89  }
    90  
    91  // EncodeToValuesWith encodes dst as a form with delimiter d, escape e, keeping zero values if z, and returns it as Values.
    92  func EncodeToValuesWith(dst interface{}, d rune, e rune, z bool) (url.Values, error) {
    93  	v := reflect.ValueOf(dst)
    94  	n, err := encodeToNode(v, z)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	vs := n.values(d, e)
    99  	return vs, nil
   100  }
   101  
   102  func encodeToNode(v reflect.Value, z bool) (n node, err error) {
   103  	defer func() {
   104  		if e := recover(); e != nil {
   105  			err = fmt.Errorf("%v", e)
   106  		}
   107  	}()
   108  	return getNode(encodeValue(v, z)), nil
   109  }
   110  
   111  func encodeValue(v reflect.Value, z bool) interface{} {
   112  	t := v.Type()
   113  	k := v.Kind()
   114  
   115  	if s, ok := marshalValue(v); ok {
   116  		return s
   117  	} else if !z && isEmptyValue(v) {
   118  		return "" // Treat the zero value as the empty string.
   119  	}
   120  
   121  	switch k {
   122  	case reflect.Ptr, reflect.Interface:
   123  		return encodeValue(v.Elem(), z)
   124  	case reflect.Struct:
   125  		if t.ConvertibleTo(timeType) {
   126  			return encodeTime(v)
   127  		} else if t.ConvertibleTo(urlType) {
   128  			return encodeURL(v)
   129  		}
   130  		return encodeStruct(v, z)
   131  	case reflect.Slice:
   132  		return encodeSlice(v, z)
   133  	case reflect.Array:
   134  		return encodeArray(v, z)
   135  	case reflect.Map:
   136  		return encodeMap(v, z)
   137  	case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func:
   138  		panic(t.String() + " has unsupported kind " + t.Kind().String())
   139  	default:
   140  		return encodeBasic(v)
   141  	}
   142  }
   143  
   144  func encodeStruct(v reflect.Value, z bool) interface{} {
   145  	t := v.Type()
   146  	n := node{}
   147  	for i := 0; i < t.NumField(); i++ {
   148  		f := t.Field(i)
   149  		k, oe := fieldInfo(f)
   150  
   151  		if k == "-" {
   152  			continue
   153  		} else if fv := v.Field(i); oe && isEmptyValue(fv) {
   154  			delete(n, k)
   155  		} else {
   156  			n[k] = encodeValue(fv, z)
   157  		}
   158  	}
   159  	return n
   160  }
   161  
   162  func encodeMap(v reflect.Value, z bool) interface{} {
   163  	n := node{}
   164  	for _, i := range v.MapKeys() {
   165  		k := getString(encodeValue(i, z))
   166  		n[k] = encodeValue(v.MapIndex(i), z)
   167  	}
   168  	return n
   169  }
   170  
   171  func encodeArray(v reflect.Value, z bool) interface{} {
   172  	n := node{}
   173  	for i := 0; i < v.Len(); i++ {
   174  		n[strconv.Itoa(i)] = encodeValue(v.Index(i), z)
   175  	}
   176  	return n
   177  }
   178  
   179  func encodeSlice(v reflect.Value, z bool) interface{} {
   180  	t := v.Type()
   181  	if t.Elem().Kind() == reflect.Uint8 {
   182  		return string(v.Bytes()) // Encode byte slices as a single string by default.
   183  	}
   184  	n := node{}
   185  	for i := 0; i < v.Len(); i++ {
   186  		n[strconv.Itoa(i)] = encodeValue(v.Index(i), z)
   187  	}
   188  	return n
   189  }
   190  
   191  func encodeTime(v reflect.Value) string {
   192  	t := v.Convert(timeType).Interface().(time.Time)
   193  	if t.Year() == 0 && (t.Month() == 0 || t.Month() == 1) && (t.Day() == 0 || t.Day() == 1) {
   194  		return t.Format("15:04:05.999999999Z07:00")
   195  	} else if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 && t.Nanosecond() == 0 {
   196  		return t.Format("2006-01-02")
   197  	}
   198  	return t.Format("2006-01-02T15:04:05.999999999Z07:00")
   199  }
   200  
   201  func encodeURL(v reflect.Value) string {
   202  	u := v.Convert(urlType).Interface().(url.URL)
   203  	return u.String()
   204  }
   205  
   206  func encodeBasic(v reflect.Value) string {
   207  	t := v.Type()
   208  	switch k := t.Kind(); k {
   209  	case reflect.Bool:
   210  		return strconv.FormatBool(v.Bool())
   211  	case reflect.Int,
   212  		reflect.Int8,
   213  		reflect.Int16,
   214  		reflect.Int32,
   215  		reflect.Int64:
   216  		return strconv.FormatInt(v.Int(), 10)
   217  	case reflect.Uint,
   218  		reflect.Uint8,
   219  		reflect.Uint16,
   220  		reflect.Uint32,
   221  		reflect.Uint64:
   222  		return strconv.FormatUint(v.Uint(), 10)
   223  	case reflect.Float32:
   224  		return strconv.FormatFloat(v.Float(), 'g', -1, 32)
   225  	case reflect.Float64:
   226  		return strconv.FormatFloat(v.Float(), 'g', -1, 64)
   227  	case reflect.Complex64, reflect.Complex128:
   228  		s := fmt.Sprintf("%g", v.Complex())
   229  		return strings.TrimSuffix(strings.TrimPrefix(s, "("), ")")
   230  	case reflect.String:
   231  		return v.String()
   232  	}
   233  	panic(t.String() + " has unsupported kind " + t.Kind().String())
   234  }
   235  
   236  func isEmptyValue(v reflect.Value) bool {
   237  	switch t := v.Type(); v.Kind() {
   238  	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
   239  		return v.Len() == 0
   240  	case reflect.Bool:
   241  		return !v.Bool()
   242  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   243  		return v.Int() == 0
   244  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   245  		return v.Uint() == 0
   246  	case reflect.Float32, reflect.Float64:
   247  		return v.Float() == 0
   248  	case reflect.Complex64, reflect.Complex128:
   249  		return v.Complex() == 0
   250  	case reflect.Interface, reflect.Ptr:
   251  		return v.IsNil()
   252  	case reflect.Struct:
   253  		if t.ConvertibleTo(timeType) {
   254  			return v.Convert(timeType).Interface().(time.Time).IsZero()
   255  		}
   256  		return reflect.DeepEqual(v, reflect.Zero(t))
   257  	}
   258  	return false
   259  }
   260  
   261  // canIndexOrdinally returns whether a value contains an ordered sequence of elements.
   262  func canIndexOrdinally(v reflect.Value) bool {
   263  	if !v.IsValid() {
   264  		return false
   265  	}
   266  	switch t := v.Type(); t.Kind() {
   267  	case reflect.Ptr, reflect.Interface:
   268  		return canIndexOrdinally(v.Elem())
   269  	case reflect.Slice, reflect.Array:
   270  		return true
   271  	}
   272  	return false
   273  }
   274  
   275  func fieldInfo(f reflect.StructField) (k string, oe bool) {
   276  	if f.PkgPath != "" { // Skip private fields.
   277  		return omittedKey, oe
   278  	}
   279  
   280  	k = f.Name
   281  	tag := f.Tag.Get("form")
   282  	if tag == "" {
   283  		return k, oe
   284  	}
   285  
   286  	ps := strings.SplitN(tag, ",", 2)
   287  	if ps[0] != "" {
   288  		k = ps[0]
   289  	}
   290  	if len(ps) == 2 {
   291  		oe = ps[1] == "omitempty"
   292  	}
   293  	return k, oe
   294  }
   295  
   296  func findField(v reflect.Value, n string, ignoreCase bool) (reflect.Value, bool) {
   297  	t := v.Type()
   298  	l := v.NumField()
   299  
   300  	var lowerN string
   301  	caseInsensitiveMatch := -1
   302  	if ignoreCase {
   303  		lowerN = strings.ToLower(n)
   304  	}
   305  
   306  	// First try named fields.
   307  	for i := 0; i < l; i++ {
   308  		f := t.Field(i)
   309  		k, _ := fieldInfo(f)
   310  		if k == omittedKey {
   311  			continue
   312  		} else if n == k {
   313  			return v.Field(i), true
   314  		} else if ignoreCase && lowerN == strings.ToLower(k) {
   315  			caseInsensitiveMatch = i
   316  		}
   317  	}
   318  
   319  	// If no exact match was found try case insensitive match.
   320  	if caseInsensitiveMatch != -1 {
   321  		return v.Field(caseInsensitiveMatch), true
   322  	}
   323  
   324  	// Then try anonymous (embedded) fields.
   325  	for i := 0; i < l; i++ {
   326  		f := t.Field(i)
   327  		k, _ := fieldInfo(f)
   328  		if k == omittedKey || !f.Anonymous { // || k != "" ?
   329  			continue
   330  		}
   331  		fv := v.Field(i)
   332  		fk := fv.Kind()
   333  		for fk == reflect.Ptr || fk == reflect.Interface {
   334  			fv = fv.Elem()
   335  			fk = fv.Kind()
   336  		}
   337  
   338  		if fk != reflect.Struct {
   339  			continue
   340  		}
   341  		if ev, ok := findField(fv, n, ignoreCase); ok {
   342  			return ev, true
   343  		}
   344  	}
   345  
   346  	return reflect.Value{}, false
   347  }
   348  
   349  var (
   350  	stringType    = reflect.TypeOf(string(""))
   351  	stringMapType = reflect.TypeOf(map[string]interface{}{})
   352  	timeType      = reflect.TypeOf(time.Time{})
   353  	timePtrType   = reflect.TypeOf(&time.Time{})
   354  	urlType       = reflect.TypeOf(url.URL{})
   355  )
   356  
   357  func skipTextMarshalling(t reflect.Type) bool {
   358  	/*// Skip time.Time because its text unmarshaling is overly rigid:
   359  	return t == timeType || t == timePtrType*/
   360  	// Skip time.Time & convertibles because its text unmarshaling is overly rigid:
   361  	return t.ConvertibleTo(timeType) || t.ConvertibleTo(timePtrType)
   362  }
   363  
   364  func unmarshalValue(v reflect.Value, x interface{}) bool {
   365  	if skipTextMarshalling(v.Type()) {
   366  		return false
   367  	}
   368  
   369  	tu, ok := v.Interface().(encoding.TextUnmarshaler)
   370  	if !ok && !v.CanAddr() {
   371  		return false
   372  	} else if !ok {
   373  		return unmarshalValue(v.Addr(), x)
   374  	}
   375  
   376  	s := getString(x)
   377  	if err := tu.UnmarshalText([]byte(s)); err != nil {
   378  		panic(err)
   379  	}
   380  	return true
   381  }
   382  
   383  func marshalValue(v reflect.Value) (string, bool) {
   384  	if skipTextMarshalling(v.Type()) {
   385  		return "", false
   386  	}
   387  
   388  	tm, ok := v.Interface().(encoding.TextMarshaler)
   389  	if !ok && !v.CanAddr() {
   390  		return "", false
   391  	} else if !ok {
   392  		return marshalValue(v.Addr())
   393  	}
   394  
   395  	bs, err := tm.MarshalText()
   396  	if err != nil {
   397  		panic(err)
   398  	}
   399  	return string(bs), true
   400  }