github.com/stripe/stripe-go/v76@v76.25.0/form/form.go (about) 1 package form 2 3 import ( 4 "bytes" 5 "fmt" 6 "net/url" 7 "reflect" 8 "sort" 9 "strconv" 10 "strings" 11 "sync" 12 ) 13 14 const tagName = "form" 15 16 // Appender is the interface implemented by types that can append themselves to 17 // a collection of form values. 18 // 19 // This is usually something that shouldn't be used, but is needed in a few 20 // places where authors deviated from norms while implementing various 21 // parameters. 22 type Appender interface { 23 // AppendTo is invoked by the form package on any types found to implement 24 // Appender so that they have a chance to encode themselves. Note that 25 // AppendTo is called in addition to normal encoding, so other form tags on 26 // the struct are still fair game. 27 AppendTo(values *Values, keyParts []string) 28 } 29 30 // encoderFunc is used to encode any type from a request. 31 // 32 // A note about encodeZero: Since some types in the Stripe API are defaulted to 33 // non-zero values, and Go defaults types to their zero values, any type that 34 // has a Stripe API default of a non-zero value is defined as a Go pointer, 35 // meaning nil defaults to the Stripe API non-zero value. To override this, a 36 // check is made to see if the value is the zero-value for that type. If it is 37 // and encodeZero is true, it's encoded. This is ignored as a parameter when 38 // dealing with types like structs, where the decision cannot be made 39 // preemptively. 40 type encoderFunc func(values *Values, v reflect.Value, keyParts []string, encodeZero bool, options *formOptions) 41 42 // field represents a single field found in a struct. It caches information 43 // about that field so that we can make encoding faster. 44 type field struct { 45 formName string 46 index int 47 isAppender bool 48 isPtr bool 49 options *formOptions 50 } 51 52 type formOptions struct { 53 // Empty indicates that a field's value should be emptied in that its value 54 // should be an empty string. It's used to workaround the fact that an 55 // empty string is a string's zero value and wouldn't normally be encoded. 56 Empty bool 57 58 // HighPrecision indicates that this field should be treated as a high 59 // precision decimal, a decimal whose precision is important to the API and 60 // which we want to encode as accurately as possible. 61 // 62 // All parameters are encoded using form encoding, so this of course 63 // encodes a value to a string, but notably, these high precision fields 64 // are sent back as strings in JSON, even though they might be surfaced as 65 // floats in this library. 66 // 67 // This isn't a perfect abstraction because floats are not precise in 68 // nature, and we might be better-advised to use a real high-precision data 69 // type like `big.Float`. That said, we suspect that this will be an 70 // adequate solution in the vast majority of cases and has a usability 71 // benefit, so we've gone this route. 72 HighPrecision bool 73 } 74 75 type structEncoder struct { 76 fields []*field 77 fieldEncs []encoderFunc 78 } 79 80 func (se *structEncoder) encode(values *Values, v reflect.Value, keyParts []string, _ bool, _ *formOptions) { 81 for i, f := range se.fields { 82 var fieldKeyParts []string 83 fieldV := v.Field(f.index) 84 85 // The wildcard on a form tag is a "special" value: it indicates a 86 // struct field that we should recurse into, but for which no part 87 // should be added to the key parts, meaning that its own subfields 88 // will be named at the same level as with the fields of the 89 // current structure. 90 if f.formName == "*" { 91 fieldKeyParts = keyParts 92 } else { 93 fieldKeyParts = append(keyParts, f.formName) 94 } 95 96 se.fieldEncs[i](values, fieldV, fieldKeyParts, f.isPtr, f.options) 97 if f.isAppender && (!f.isPtr || !fieldV.IsNil()) { 98 fieldV.Interface().(Appender).AppendTo(values, fieldKeyParts) 99 } 100 } 101 } 102 103 // --- 104 105 // Strict enables strict mode wherein the package will panic on an AppendTo 106 // function if it finds that a tag string was malformed. 107 var Strict = false 108 109 var encoderCache struct { 110 m map[reflect.Type]encoderFunc 111 mu sync.RWMutex // for coordinating concurrent operations on m 112 } 113 114 var structCache struct { 115 m map[reflect.Type]*structEncoder 116 mu sync.RWMutex // for coordinating concurrent operations on m 117 } 118 119 // AppendTo uses reflection to form encode into the given values collection 120 // based off the form tags that it defines. 121 func AppendTo(values *Values, i interface{}) { 122 reflectValue(values, reflect.ValueOf(i), false, nil) 123 } 124 125 // AppendToPrefixed is the same as AppendTo, but it allows a slice of key parts 126 // to be specified to prefix the form values. 127 // 128 // I was hoping not to have to expose this function, but I ended up needing it 129 // for recipients. Recipients is going away, and when it does, we can probably 130 // remove it again. 131 func AppendToPrefixed(values *Values, i interface{}, keyParts []string) { 132 reflectValue(values, reflect.ValueOf(i), false, keyParts) 133 } 134 135 // FormatKey takes a series of key parts that may be parameter keyParts, map keys, 136 // or array indices and unifies them into a single key suitable for Stripe's 137 // style of form encoding. 138 func FormatKey(parts []string) string { 139 if len(parts) < 1 { 140 panic("Not allowed 0-length parts slice") 141 } 142 143 key := parts[0] 144 for i := 1; i < len(parts); i++ { 145 key += "[" + parts[i] + "]" 146 } 147 return key 148 } 149 150 // --- 151 152 func boolEncoder(values *Values, v reflect.Value, keyParts []string, encodeZero bool, options *formOptions) { 153 val := v.Bool() 154 if !val && !encodeZero { 155 return 156 } 157 158 if options != nil { 159 switch { 160 case options.Empty: 161 values.Add(FormatKey(keyParts), "") 162 } 163 } else { 164 values.Add(FormatKey(keyParts), strconv.FormatBool(val)) 165 } 166 } 167 168 func buildArrayOrSliceEncoder(t reflect.Type) encoderFunc { 169 // Gets an encoder for the type that the array or slice will hold 170 elemF := getCachedOrBuildTypeEncoder(t.Elem()) 171 172 return func(values *Values, v reflect.Value, keyParts []string, _ bool, options *formOptions) { 173 // When encountering a slice that's been explicitly set (i.e. non-nil) 174 // and which is of 0 length, we take this as an indication that the 175 // user is trying to zero the API array. See the `additional_owners` 176 // property under `legal_entity` on account for an example of somewhere 177 // that this is useful. 178 // 179 // This only works for a slice (and not an array) because even a zeroed 180 // array always has a fixed length. 181 if t.Kind() == reflect.Slice && !v.IsNil() && v.Len() == 0 { 182 values.Add(FormatKey(keyParts), "") 183 return 184 } 185 186 var arrNames []string 187 188 for i := 0; i < v.Len(); i++ { 189 arrNames = append(keyParts, strconv.Itoa(i)) 190 191 indexV := v.Index(i) 192 elemF(values, indexV, arrNames, indexV.Kind() == reflect.Ptr, nil) 193 194 if isAppender(indexV.Type()) && !indexV.IsNil() { 195 indexV.Interface().(Appender).AppendTo(values, arrNames) 196 } 197 } 198 } 199 } 200 201 func buildPtrEncoder(t reflect.Type) encoderFunc { 202 // Gets an encoder for the type that the pointer wraps 203 elemF := getCachedOrBuildTypeEncoder(t.Elem()) 204 205 return func(values *Values, v reflect.Value, keyParts []string, _ bool, options *formOptions) { 206 // We take a nil to mean that the property wasn't set, so ignore it in 207 // the final encoding. 208 if v.IsNil() { 209 return 210 } 211 212 // Handle "zeroing" an array stored as a pointer to a slice. See 213 // comment in `buildArrayOrSliceEncoder` above. 214 if t.Elem().Kind() == reflect.Slice && v.Elem().Len() == 0 { 215 values.Add(FormatKey(keyParts), "") 216 return 217 } 218 219 // Otherwise, call into the appropriate encoder for the pointer's type. 220 elemF(values, v.Elem(), keyParts, true, options) 221 } 222 } 223 224 func buildStructEncoder(t reflect.Type) encoderFunc { 225 se := getCachedOrBuildStructEncoder(t) 226 return se.encode 227 } 228 229 func float32Encoder(values *Values, v reflect.Value, keyParts []string, encodeZero bool, options *formOptions) { 230 val := v.Float() 231 if val == 0.0 && !encodeZero { 232 return 233 } 234 prec := 4 235 if options != nil && options.HighPrecision { 236 // Special value that tells Go to format the float in as few required 237 // digits as necessary for it to be successfully parsable from a string 238 // back to the same original number. 239 prec = -1 240 } 241 values.Add(FormatKey(keyParts), strconv.FormatFloat(val, 'f', prec, 32)) 242 } 243 244 func float64Encoder(values *Values, v reflect.Value, keyParts []string, encodeZero bool, options *formOptions) { 245 val := v.Float() 246 if val == 0.0 && !encodeZero { 247 return 248 } 249 prec := 4 250 if options != nil && options.HighPrecision { 251 // Special value that tells Go to format the float in as few required 252 // digits as necessary for it to be successfully parsable from a string 253 // back to the same original number. 254 prec = -1 255 } 256 values.Add(FormatKey(keyParts), strconv.FormatFloat(val, 'f', prec, 64)) 257 } 258 259 func getCachedOrBuildStructEncoder(t reflect.Type) *structEncoder { 260 // Just acquire a read lock when extracting a value (note that in Go, a map 261 // cannot be read while it's also being written). 262 structCache.mu.RLock() 263 f := structCache.m[t] 264 structCache.mu.RUnlock() 265 266 if f != nil { 267 return f 268 } 269 270 // We do the work to get the encoder without holding a lock. This could 271 // result in duplicate work, but it will help us avoid a deadlock. Encoders 272 // may be built and stored recursively in the cases of something like an 273 // array or slice, so we need to make sure that this function is properly 274 // re-entrant. 275 f = makeStructEncoder(t) 276 277 structCache.mu.Lock() 278 defer structCache.mu.Unlock() 279 280 if structCache.m == nil { 281 structCache.m = make(map[reflect.Type]*structEncoder) 282 } 283 structCache.m[t] = f 284 285 return f 286 } 287 288 // getCachedOrBuildTypeEncoder tries to get an encoderFunc for the type from 289 // the cache, and falls back to building one if there wasn't a cached one 290 // available. If an encoder is built, it's stored back to the cache. 291 func getCachedOrBuildTypeEncoder(t reflect.Type) encoderFunc { 292 // Just acquire a read lock when extracting a value (note that in Go, a map 293 // cannot be read while it's also being written). 294 encoderCache.mu.RLock() 295 f := encoderCache.m[t] 296 encoderCache.mu.RUnlock() 297 298 if f != nil { 299 return f 300 } 301 302 // We do the work to get the encoder without holding a lock. This could 303 // result in duplicate work, but it will help us avoid a deadlock. Encoders 304 // may be built and stored recursively in the cases of something like an 305 // array or slice, so we need to make sure that this function is properly 306 // re-entrant. 307 f = makeTypeEncoder(t) 308 309 encoderCache.mu.Lock() 310 defer encoderCache.mu.Unlock() 311 312 if encoderCache.m == nil { 313 encoderCache.m = make(map[reflect.Type]encoderFunc) 314 } 315 encoderCache.m[t] = f 316 317 return f 318 } 319 320 func intEncoder(values *Values, v reflect.Value, keyParts []string, encodeZero bool, options *formOptions) { 321 val := v.Int() 322 if val == 0 && !encodeZero { 323 return 324 } 325 values.Add(FormatKey(keyParts), strconv.FormatInt(val, 10)) 326 } 327 328 func interfaceEncoder(values *Values, v reflect.Value, keyParts []string, encodeZero bool, _ *formOptions) { 329 // interfaceEncoder never encodes a `nil`, but it will pass through an 330 // `encodeZero` value into its chained encoder 331 if v.IsNil() { 332 return 333 } 334 reflectValue(values, v.Elem(), encodeZero, keyParts) 335 } 336 337 func isAppender(t reflect.Type) bool { 338 return t.Implements(reflect.TypeOf((*Appender)(nil)).Elem()) 339 } 340 341 func mapEncoder(values *Values, v reflect.Value, keyParts []string, _ bool, _ *formOptions) { 342 keys := make([]string, 0, v.Len()) 343 for _, keyVal := range v.MapKeys() { 344 if keyVal.Kind() != reflect.String { 345 if Strict { 346 panic("Don't support serializing maps with non-string keys") 347 } 348 // otherwise keyVal.String() will panic later 349 continue 350 } 351 keys = append(keys, keyVal.String()) 352 } 353 sort.Strings(keys) 354 for _, key := range keys { 355 // Unlike a property on a struct which will contain a zero value even 356 // if never set, any value found in a map has been explicitly set, so 357 // we always make an effort to encode them, even if a zero value 358 // (that's why we pass through `true` here). 359 reflectValue(values, v.MapIndex(reflect.ValueOf(key)), true, append(keyParts, key)) 360 } 361 } 362 363 func stringEncoder(values *Values, v reflect.Value, keyParts []string, encodeZero bool, options *formOptions) { 364 val := v.String() 365 if val == "" && !encodeZero { 366 return 367 } 368 values.Add(FormatKey(keyParts), val) 369 } 370 371 func uintEncoder(values *Values, v reflect.Value, keyParts []string, encodeZero bool, options *formOptions) { 372 val := v.Uint() 373 if val == 0 && !encodeZero { 374 return 375 } 376 values.Add(FormatKey(keyParts), strconv.FormatUint(val, 10)) 377 } 378 379 // reflectValue is roughly the shared entry point of any AppendTo functions. 380 // It's also called recursively in cases where a precise type isn't yet known 381 // and its encoding needs to be deferred down the chain; for example, when 382 // encoding interface{} or the values in an array or map containing 383 // interface{}. 384 func reflectValue(values *Values, v reflect.Value, encodeZero bool, keyParts []string) { 385 t := v.Type() 386 387 f := getCachedOrBuildTypeEncoder(t) 388 if f != nil { 389 f(values, v, keyParts, encodeZero || v.Kind() == reflect.Ptr, nil) 390 } 391 392 if isAppender(t) { 393 v.Interface().(Appender).AppendTo(values, keyParts) 394 } 395 } 396 397 func makeStructEncoder(t reflect.Type) *structEncoder { 398 // Don't specify capacity because we don't know how many fields are tagged with 399 // `form` 400 se := &structEncoder{} 401 402 for i := 0; i < t.NumField(); i++ { 403 reflectField := t.Field(i) 404 tag := reflectField.Tag.Get(tagName) 405 if Strict && tag == "" { 406 panic(fmt.Sprintf( 407 "All fields in structs to be form-encoded must have `form` tag; on: %s/%s "+ 408 "(hint: use an explicit `form:\"-\"` if the field should not be encoded", 409 t.Name(), reflectField.Name, 410 )) 411 } 412 413 formName, options := parseTag(tag) 414 415 // Like with encoding/json, a hyphen is an explicit way of saying 416 // that this field should not be encoded 417 if formName == "-" { 418 continue 419 } 420 421 fldTyp := reflectField.Type 422 fldKind := fldTyp.Kind() 423 424 if Strict && options != nil { 425 if options.Empty && fldKind != reflect.Bool { 426 panic(fmt.Sprintf( 427 "Cannot specify `empty` for non-boolean field; on: %s/%s", 428 t.Name(), reflectField.Name, 429 )) 430 } 431 432 var k reflect.Kind 433 if fldKind == reflect.Ptr { 434 k = fldTyp.Elem().Kind() 435 } else { 436 k = fldKind 437 } 438 439 fldIsFloat := k == reflect.Float32 || k == reflect.Float64 440 441 if options.HighPrecision && !fldIsFloat { 442 panic(fmt.Sprintf( 443 "Cannot specify `high_precision` for non-float field; on: %s/%s (%s)", 444 t.Name(), reflectField.Name, fldTyp, 445 )) 446 } 447 } 448 449 se.fields = append(se.fields, &field{ 450 formName: formName, 451 index: i, 452 isAppender: isAppender(fldTyp), 453 isPtr: fldKind == reflect.Ptr, 454 options: options, 455 }) 456 se.fieldEncs = append(se.fieldEncs, 457 getCachedOrBuildTypeEncoder(fldTyp)) 458 } 459 460 return se 461 } 462 463 func makeTypeEncoder(t reflect.Type) encoderFunc { 464 switch t.Kind() { 465 case reflect.Array, reflect.Slice: 466 return buildArrayOrSliceEncoder(t) 467 468 case reflect.Bool: 469 return boolEncoder 470 471 case reflect.Float32: 472 return float32Encoder 473 474 case reflect.Float64: 475 return float64Encoder 476 477 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 478 return intEncoder 479 480 case reflect.Interface: 481 return interfaceEncoder 482 483 case reflect.Map: 484 return mapEncoder 485 486 case reflect.Ptr: 487 return buildPtrEncoder(t) 488 489 case reflect.String: 490 return stringEncoder 491 492 case reflect.Struct: 493 return buildStructEncoder(t) 494 495 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 496 return uintEncoder 497 } 498 499 return nil 500 } 501 502 func parseTag(tag string) (string, *formOptions) { 503 var options *formOptions 504 parts := strings.Split(tag, ",") 505 name := parts[0] 506 507 for i := 1; i < len(parts); i++ { 508 switch parts[i] { 509 case "empty": 510 if options == nil { 511 options = &formOptions{} 512 } 513 options.Empty = true 514 515 case "high_precision": 516 if options == nil { 517 options = &formOptions{} 518 } 519 options.HighPrecision = true 520 521 default: 522 if Strict { 523 part := parts[i] 524 if part == "" { 525 part = "(empty)" 526 } 527 panic(fmt.Sprintf("Don't know how to handle form tag part: %s (tag: %s)", 528 part, tag)) 529 } 530 } 531 } 532 533 return name, options 534 } 535 536 // --- 537 538 // Values is a collection of values that can be submitted along with a 539 // request that specifically allows for duplicate keys and encodes its entries 540 // in the same order that they were added. 541 type Values struct { 542 values []formValue 543 } 544 545 // Add adds a key/value tuple to the form. 546 func (f *Values) Add(key, val string) { 547 f.values = append(f.values, formValue{key, val}) 548 } 549 550 // Encode encodes the keys and values into “URL encoded” form 551 // ("bar=baz&foo=quux"). 552 func (f *Values) Encode() string { 553 var buf bytes.Buffer 554 for _, v := range f.values { 555 if buf.Len() > 0 { 556 buf.WriteByte('&') 557 } 558 key := url.QueryEscape(v.Key) 559 key = strings.Replace(key, "%5B", "[", -1) 560 key = strings.Replace(key, "%5D", "]", -1) 561 buf.WriteString(key) 562 buf.WriteString("=") 563 buf.WriteString(url.QueryEscape(v.Value)) 564 } 565 return buf.String() 566 } 567 568 // Empty returns true if no parameters have been set. 569 func (f *Values) Empty() bool { 570 return len(f.values) == 0 571 } 572 573 // Set sets the first instance of a parameter for the given key to the given 574 // value. If no parameters exist with the key, a new one is added. 575 // 576 // Note that Set is O(n) and may be quite slow for a very large parameter list. 577 func (f *Values) Set(key, val string) { 578 for i, v := range f.values { 579 if v.Key == key { 580 f.values[i].Value = val 581 return 582 } 583 } 584 585 f.Add(key, val) 586 } 587 588 // Get retrieves the list of values for the given key. If no values exist 589 // for the key, nil will be returned. 590 // 591 // Note that Get is O(n) and may be quite slow for a very large parameter list. 592 func (f *Values) Get(key string) []string { 593 var results []string 594 for i, v := range f.values { 595 if v.Key == key { 596 results = append(results, f.values[i].Value) 597 } 598 } 599 return results 600 } 601 602 // ToValues converts an instance of Values into an instance of 603 // url.Values. This can be useful in cases where it's useful to make an 604 // unordered comparison of two sets of request values. 605 // 606 // Note that url.Values is incapable of representing certain Rack form types in 607 // a cohesive way. For example, an array of maps in Rack is encoded with a 608 // string like: 609 // 610 // arr[][foo]=foo0&arr[][bar]=bar0&arr[][foo]=foo1&arr[][bar]=bar1 611 // 612 // Because url.Values is a map, values will be handled in a way that's grouped 613 // by their key instead of in the order they were added. Therefore the above 614 // may by encoded to something like (maps are unordered so the actual result is 615 // somewhat non-deterministic): 616 // 617 // arr[][foo]=foo0&arr[][foo]=foo1&arr[][bar]=bar0&arr[][bar]=bar1 618 // 619 // And thus result in an incorrect request to Stripe. 620 func (f *Values) ToValues() url.Values { 621 values := url.Values{} 622 for _, v := range f.values { 623 values.Add(v.Key, v.Value) 624 } 625 return values 626 } 627 628 // A key/value tuple for use in the Values type. 629 type formValue struct { 630 Key string 631 Value string 632 }