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  }