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 }