github.com/stripe/stripe-go/v76@v76.25.0/stripe.go (about) 1 // Package stripe provides the binding for Stripe REST APIs. 2 package stripe 3 4 import ( 5 "bytes" 6 "context" 7 "crypto/tls" 8 "crypto/x509" 9 "encoding/json" 10 "errors" 11 "fmt" 12 "io" 13 "io/ioutil" 14 "math/rand" 15 "net/http" 16 "net/url" 17 "os/exec" 18 "reflect" 19 "regexp" 20 "runtime" 21 "strings" 22 "sync" 23 "time" 24 25 "github.com/stripe/stripe-go/v76/form" 26 ) 27 28 // 29 // Public constants 30 // 31 32 const ( 33 // APIVersion is the currently supported API version 34 APIVersion string = apiVersion 35 36 // APIBackend is a constant representing the API service backend. 37 APIBackend SupportedBackend = "api" 38 39 // APIURL is the URL of the API service backend. 40 APIURL string = "https://api.stripe.com" 41 42 // ClientVersion is the version of the stripe-go library being used. 43 ClientVersion string = clientversion 44 45 // ConnectURL is the URL for OAuth. 46 ConnectURL string = "https://connect.stripe.com" 47 48 // ConnectBackend is a constant representing the connect service backend for 49 // OAuth. 50 ConnectBackend SupportedBackend = "connect" 51 52 // DefaultMaxNetworkRetries is the default maximum number of retries made 53 // by a Stripe client. 54 DefaultMaxNetworkRetries int64 = 2 55 56 // UnknownPlatform is the string returned as the system name if we couldn't get 57 // one from `uname`. 58 UnknownPlatform string = "unknown platform" 59 60 // UploadsBackend is a constant representing the uploads service backend. 61 UploadsBackend SupportedBackend = "uploads" 62 63 // UploadsURL is the URL of the uploads service backend. 64 UploadsURL string = "https://files.stripe.com" 65 ) 66 67 // 68 // Public variables 69 // 70 71 // EnableTelemetry is a global override for enabling client telemetry, which 72 // sends request performance metrics to Stripe via the `X-Stripe-Client-Telemetry` 73 // header. If set to true, all clients will send telemetry metrics. Defaults to 74 // true. 75 // 76 // Telemetry can also be disabled on a per-client basis by instead creating a 77 // `BackendConfig` with `EnableTelemetry: false`. 78 var EnableTelemetry = true 79 80 // Key is the Stripe API key used globally in the binding. 81 var Key string 82 83 // 84 // Public types 85 // 86 87 // APIResponse encapsulates some common features of a response from the 88 // Stripe API. 89 type APIResponse struct { 90 // Header contain a map of all HTTP header keys to values. Its behavior and 91 // caveats are identical to that of http.Header. 92 Header http.Header 93 94 // IdempotencyKey contains the idempotency key used with this request. 95 // Idempotency keys are a Stripe-specific concept that helps guarantee that 96 // requests that fail and need to be retried are not duplicated. 97 IdempotencyKey string 98 99 // RawJSON contains the response body as raw bytes. 100 RawJSON []byte 101 102 // RequestID contains a string that uniquely identifies the Stripe request. 103 // Used for debugging or support purposes. 104 RequestID string 105 106 // Status is a status code and message. e.g. "200 OK" 107 Status string 108 109 // StatusCode is a status code as integer. e.g. 200 110 StatusCode int 111 112 duration *time.Duration 113 } 114 115 // StreamingAPIResponse encapsulates some common features of a response from the 116 // Stripe API whose body can be streamed. This is used for "file downloads", and 117 // the `Body` property is an io.ReadCloser, so the user can stream it to another 118 // location such as a file or network request without buffering the entire body 119 // into memory. 120 type StreamingAPIResponse struct { 121 Header http.Header 122 IdempotencyKey string 123 Body io.ReadCloser 124 RequestID string 125 Status string 126 StatusCode int 127 duration *time.Duration 128 } 129 130 func newAPIResponse(res *http.Response, resBody []byte, requestDuration *time.Duration) *APIResponse { 131 return &APIResponse{ 132 Header: res.Header, 133 IdempotencyKey: res.Header.Get("Idempotency-Key"), 134 RawJSON: resBody, 135 RequestID: res.Header.Get("Request-Id"), 136 Status: res.Status, 137 StatusCode: res.StatusCode, 138 duration: requestDuration, 139 } 140 } 141 142 func newStreamingAPIResponse(res *http.Response, body io.ReadCloser, requestDuration *time.Duration) *StreamingAPIResponse { 143 return &StreamingAPIResponse{ 144 Header: res.Header, 145 IdempotencyKey: res.Header.Get("Idempotency-Key"), 146 Body: body, 147 RequestID: res.Header.Get("Request-Id"), 148 Status: res.Status, 149 StatusCode: res.StatusCode, 150 duration: requestDuration, 151 } 152 } 153 154 // APIResource is a type assigned to structs that may come from Stripe API 155 // endpoints and contains facilities common to all of them. 156 type APIResource struct { 157 LastResponse *APIResponse `json:"-"` 158 } 159 160 // APIStream is a type assigned to streaming responses that may come from Stripe API 161 type APIStream struct { 162 LastResponse *StreamingAPIResponse 163 } 164 165 // SetLastResponse sets the HTTP response that returned the API resource. 166 func (r *APIResource) SetLastResponse(response *APIResponse) { 167 r.LastResponse = response 168 } 169 170 // SetLastResponse sets the HTTP response that returned the API resource. 171 func (r *APIStream) SetLastResponse(response *StreamingAPIResponse) { 172 r.LastResponse = response 173 } 174 175 // AppInfo contains information about the "app" which this integration belongs 176 // to. This should be reserved for plugins that wish to identify themselves 177 // with Stripe. 178 type AppInfo struct { 179 Name string `json:"name"` 180 PartnerID string `json:"partner_id"` 181 URL string `json:"url"` 182 Version string `json:"version"` 183 } 184 185 // formatUserAgent formats an AppInfo in a way that's suitable to be appended 186 // to a User-Agent string. Note that this format is shared between all 187 // libraries so if it's changed, it should be changed everywhere. 188 func (a *AppInfo) formatUserAgent() string { 189 str := a.Name 190 if a.Version != "" { 191 str += "/" + a.Version 192 } 193 if a.URL != "" { 194 str += " (" + a.URL + ")" 195 } 196 return str 197 } 198 199 // Backend is an interface for making calls against a Stripe service. 200 // This interface exists to enable mocking for during testing if needed. 201 type Backend interface { 202 Call(method, path, key string, params ParamsContainer, v LastResponseSetter) error 203 CallStreaming(method, path, key string, params ParamsContainer, v StreamingLastResponseSetter) error 204 CallRaw(method, path, key string, body *form.Values, params *Params, v LastResponseSetter) error 205 CallMultipart(method, path, key, boundary string, body *bytes.Buffer, params *Params, v LastResponseSetter) error 206 SetMaxNetworkRetries(maxNetworkRetries int64) 207 } 208 209 // BackendConfig is used to configure a new Stripe backend. 210 type BackendConfig struct { 211 // EnableTelemetry allows request metrics (request id and duration) to be sent 212 // to Stripe in subsequent requests via the `X-Stripe-Client-Telemetry` header. 213 // 214 // This value is a pointer to allow us to differentiate an unset versus 215 // empty value. Use stripe.Bool for an easy way to set this value. 216 // 217 // Defaults to false. 218 EnableTelemetry *bool 219 220 // HTTPClient is an HTTP client instance to use when making API requests. 221 // 222 // If left unset, it'll be set to a default HTTP client for the package. 223 HTTPClient *http.Client 224 225 // LeveledLogger is the logger that the backend will use to log errors, 226 // warnings, and informational messages. 227 // 228 // LeveledLoggerInterface is implemented by LeveledLogger, and one can be 229 // initialized at the desired level of logging. LeveledLoggerInterface 230 // also provides out-of-the-box compatibility with a Logrus Logger, but may 231 // require a thin shim for use with other logging libraries that use less 232 // standard conventions like Zap. 233 // 234 // Defaults to DefaultLeveledLogger. 235 // 236 // To set a logger that logs nothing, set this to a stripe.LeveledLogger 237 // with a Level of LevelNull (simply setting this field to nil will not 238 // work). 239 LeveledLogger LeveledLoggerInterface 240 241 // MaxNetworkRetries sets maximum number of times that the library will 242 // retry requests that appear to have failed due to an intermittent 243 // problem. 244 // 245 // This value is a pointer to allow us to differentiate an unset versus 246 // empty value. Use stripe.Int64 for an easy way to set this value. 247 // 248 // Defaults to DefaultMaxNetworkRetries (2). 249 MaxNetworkRetries *int64 250 251 // URL is the base URL to use for API paths. 252 // 253 // This value is a pointer to allow us to differentiate an unset versus 254 // empty value. Use stripe.String for an easy way to set this value. 255 // 256 // If left empty, it'll be set to the default for the SupportedBackend. 257 URL *string 258 } 259 260 // BackendImplementation is the internal implementation for making HTTP calls 261 // to Stripe. 262 // 263 // The public use of this struct is deprecated. It will be unexported in a 264 // future version. 265 type BackendImplementation struct { 266 Type SupportedBackend 267 URL string 268 HTTPClient *http.Client 269 LeveledLogger LeveledLoggerInterface 270 MaxNetworkRetries int64 271 272 enableTelemetry bool 273 274 // networkRetriesSleep indicates whether the backend should use the normal 275 // sleep between retries. 276 // 277 // See also SetNetworkRetriesSleep. 278 networkRetriesSleep bool 279 280 requestMetricsBuffer chan requestMetrics 281 } 282 283 type metricsResponseSetter struct { 284 LastResponseSetter 285 backend *BackendImplementation 286 params *Params 287 } 288 289 func (s *metricsResponseSetter) SetLastResponse(response *APIResponse) { 290 var usage []string 291 if s.params != nil { 292 usage = s.params.usage 293 } 294 s.backend.maybeEnqueueTelemetryMetrics(response.RequestID, response.duration, usage) 295 s.LastResponseSetter.SetLastResponse(response) 296 } 297 298 func (s *metricsResponseSetter) UnmarshalJSON(b []byte) error { 299 return json.Unmarshal(b, s.LastResponseSetter) 300 } 301 302 type streamingLastResponseSetterWrapper struct { 303 StreamingLastResponseSetter 304 f func(*StreamingAPIResponse) 305 } 306 307 func (l *streamingLastResponseSetterWrapper) SetLastResponse(response *StreamingAPIResponse) { 308 l.f(response) 309 l.StreamingLastResponseSetter.SetLastResponse(response) 310 } 311 func (l *streamingLastResponseSetterWrapper) UnmarshalJSON(b []byte) error { 312 return json.Unmarshal(b, l.StreamingLastResponseSetter) 313 } 314 315 func extractParams(params ParamsContainer) (*form.Values, *Params, error) { 316 var formValues *form.Values 317 var commonParams *Params 318 319 if params != nil { 320 // This is a little unfortunate, but Go makes it impossible to compare 321 // an interface value to nil without the use of the reflect package and 322 // its true disciples insist that this is a feature and not a bug. 323 // 324 // Here we do invoke reflect because (1) we have to reflect anyway to 325 // use encode with the form package, and (2) the corresponding removal 326 // of boilerplate that this enables makes the small performance penalty 327 // worth it. 328 reflectValue := reflect.ValueOf(params) 329 330 if reflectValue.Kind() == reflect.Ptr && !reflectValue.IsNil() { 331 commonParams = params.GetParams() 332 333 if !reflectValue.Elem().FieldByName("Metadata").IsZero() { 334 if commonParams.Metadata != nil { 335 return nil, nil, fmt.Errorf("You cannot specify both the (deprecated) .Params.Metadata and .Metadata in %s", reflectValue.Elem().Type().Name()) 336 } 337 } 338 339 if !reflectValue.Elem().FieldByName("Expand").IsZero() { 340 if commonParams.Expand != nil { 341 return nil, nil, fmt.Errorf("You cannot specify both the (deprecated) .Params.Expand and .Expand in %s", reflectValue.Elem().Type().Name()) 342 } 343 } 344 345 formValues = &form.Values{} 346 form.AppendTo(formValues, params) 347 } 348 } 349 return formValues, commonParams, nil 350 } 351 352 // Call is the Backend.Call implementation for invoking Stripe APIs. 353 func (s *BackendImplementation) Call(method, path, key string, params ParamsContainer, v LastResponseSetter) error { 354 body, commonParams, err := extractParams(params) 355 if err != nil { 356 return err 357 } 358 return s.CallRaw(method, path, key, body, commonParams, v) 359 } 360 361 // CallStreaming is the Backend.Call implementation for invoking Stripe APIs 362 // without buffering the response into memory. 363 func (s *BackendImplementation) CallStreaming(method, path, key string, params ParamsContainer, v StreamingLastResponseSetter) error { 364 formValues, commonParams, err := extractParams(params) 365 if err != nil { 366 return err 367 } 368 369 var body string 370 if formValues != nil && !formValues.Empty() { 371 body = formValues.Encode() 372 373 // On `GET`, move the payload into the URL 374 if method == http.MethodGet { 375 path += "?" + body 376 body = "" 377 } 378 } 379 bodyBuffer := bytes.NewBufferString(body) 380 381 req, err := s.NewRequest(method, path, key, "application/x-www-form-urlencoded", commonParams) 382 if err != nil { 383 return err 384 } 385 386 responseSetter := streamingLastResponseSetterWrapper{ 387 v, 388 func(response *StreamingAPIResponse) { 389 var usage []string 390 if commonParams != nil { 391 usage = commonParams.usage 392 } 393 s.maybeEnqueueTelemetryMetrics(response.RequestID, response.duration, usage) 394 }, 395 } 396 397 if err := s.DoStreaming(req, bodyBuffer, &responseSetter); err != nil { 398 return err 399 } 400 401 return nil 402 } 403 404 // CallMultipart is the Backend.CallMultipart implementation for invoking Stripe APIs. 405 func (s *BackendImplementation) CallMultipart(method, path, key, boundary string, body *bytes.Buffer, params *Params, v LastResponseSetter) error { 406 contentType := "multipart/form-data; boundary=" + boundary 407 408 req, err := s.NewRequest(method, path, key, contentType, params) 409 if err != nil { 410 return err 411 } 412 413 if err := s.Do(req, body, v); err != nil { 414 return err 415 } 416 417 return nil 418 } 419 420 // CallRaw is the implementation for invoking Stripe APIs internally without a backend. 421 func (s *BackendImplementation) CallRaw(method, path, key string, form *form.Values, params *Params, v LastResponseSetter) error { 422 var body string 423 if form != nil && !form.Empty() { 424 body = form.Encode() 425 426 // On `GET`, move the payload into the URL 427 if method == http.MethodGet { 428 path += "?" + body 429 body = "" 430 } 431 } 432 bodyBuffer := bytes.NewBufferString(body) 433 434 req, err := s.NewRequest(method, path, key, "application/x-www-form-urlencoded", params) 435 if err != nil { 436 return err 437 } 438 439 responseSetter := metricsResponseSetter{ 440 LastResponseSetter: v, 441 backend: s, 442 params: params, 443 } 444 445 if err := s.Do(req, bodyBuffer, &responseSetter); err != nil { 446 return err 447 } 448 449 return nil 450 } 451 452 // NewRequest is used by Call to generate an http.Request. It handles encoding 453 // parameters and attaching the appropriate headers. 454 func (s *BackendImplementation) NewRequest(method, path, key, contentType string, params *Params) (*http.Request, error) { 455 if !strings.HasPrefix(path, "/") { 456 path = "/" + path 457 } 458 459 path = s.URL + path 460 461 // Body is set later by `Do`. 462 req, err := http.NewRequest(method, path, nil) 463 if err != nil { 464 s.LeveledLogger.Errorf("Cannot create Stripe request: %v", err) 465 return nil, err 466 } 467 468 authorization := "Bearer " + key 469 470 req.Header.Add("Authorization", authorization) 471 req.Header.Add("Content-Type", contentType) 472 req.Header.Add("Stripe-Version", APIVersion) 473 req.Header.Add("User-Agent", encodedUserAgent) 474 req.Header.Add("X-Stripe-Client-User-Agent", getEncodedStripeUserAgent()) 475 476 if params != nil { 477 if params.Context != nil { 478 req = req.WithContext(params.Context) 479 } 480 481 if params.IdempotencyKey != nil { 482 idempotencyKey := strings.TrimSpace(*params.IdempotencyKey) 483 if len(idempotencyKey) > 255 { 484 return nil, errors.New("cannot use an idempotency key longer than 255 characters") 485 } 486 487 req.Header.Add("Idempotency-Key", idempotencyKey) 488 } else if isHTTPWriteMethod(method) { 489 req.Header.Add("Idempotency-Key", NewIdempotencyKey()) 490 } 491 492 if params.StripeAccount != nil { 493 req.Header.Add("Stripe-Account", strings.TrimSpace(*params.StripeAccount)) 494 } 495 496 for k, v := range params.Headers { 497 for _, line := range v { 498 // Use Set to override the default value possibly set before 499 req.Header.Set(k, line) 500 } 501 } 502 } 503 504 return req, nil 505 } 506 507 func (s *BackendImplementation) maybeSetTelemetryHeader(req *http.Request) { 508 if s.enableTelemetry { 509 select { 510 case metrics := <-s.requestMetricsBuffer: 511 metricsJSON, err := json.Marshal(&requestTelemetry{LastRequestMetrics: metrics}) 512 if err == nil { 513 req.Header.Set("X-Stripe-Client-Telemetry", string(metricsJSON)) 514 } else { 515 s.LeveledLogger.Warnf("Unable to encode client telemetry: %v", err) 516 } 517 default: 518 // There are no metrics available, so don't send any. 519 // This default case needs to be here to prevent Do from blocking on an 520 // empty requestMetricsBuffer. 521 } 522 } 523 } 524 525 func (s *BackendImplementation) maybeEnqueueTelemetryMetrics(requestID string, requestDuration *time.Duration, usage []string) { 526 if !s.enableTelemetry || requestID == "" { 527 return 528 } 529 // If there's no duration to report and no usage to report, don't bother 530 if requestDuration == nil && len(usage) == 0 { 531 return 532 } 533 metrics := requestMetrics{ 534 RequestID: requestID, 535 } 536 if requestDuration != nil { 537 requestDurationMS := int(*requestDuration / time.Millisecond) 538 metrics.RequestDurationMS = &requestDurationMS 539 } 540 if len(usage) > 0 { 541 metrics.Usage = usage 542 } 543 select { 544 case s.requestMetricsBuffer <- metrics: 545 default: 546 } 547 } 548 549 func resetBodyReader(body *bytes.Buffer, req *http.Request) { 550 // This might look a little strange, but we set the request's body 551 // outside of `NewRequest` so that we can get a fresh version every 552 // time. 553 // 554 // The background is that back in the era of old style HTTP, it was 555 // safe to reuse `Request` objects, but with the addition of HTTP/2, 556 // it's now only sometimes safe. Reusing a `Request` with a body will 557 // break. 558 // 559 // See some details here: 560 // 561 // https://github.com/golang/go/issues/19653#issuecomment-341539160 562 // 563 // And our original bug report here: 564 // 565 // https://github.com/stripe/stripe-go/issues/642 566 // 567 // To workaround the problem, we put a fresh `Body` onto the `Request` 568 // every time we execute it, and this seems to empirically resolve the 569 // problem. 570 if body != nil { 571 // We can safely reuse the same buffer that we used to encode our body, 572 // but return a new reader to it everytime so that each read is from 573 // the beginning. 574 reader := bytes.NewReader(body.Bytes()) 575 576 req.Body = nopReadCloser{reader} 577 578 // And also add the same thing to `Request.GetBody`, which allows 579 // `net/http` to get a new body in cases like a redirect. This is 580 // usually not used, but it doesn't hurt to set it in case it's 581 // needed. See: 582 // 583 // https://github.com/stripe/stripe-go/issues/710 584 // 585 req.GetBody = func() (io.ReadCloser, error) { 586 reader := bytes.NewReader(body.Bytes()) 587 return nopReadCloser{reader}, nil 588 } 589 } 590 } 591 592 // requestWithRetriesAndTelemetry uses s.HTTPClient to make an HTTP request, 593 // and handles retries, telemetry, and emitting log statements. It attempts to 594 // avoid processing the *result* of the HTTP request. It receives a 595 // "handleResponse" func from the caller, and it defers to that to determine 596 // whether the request was a failure or success, and to convert the 597 // response/error into the appropriate type of error or an appropriate result 598 // type. 599 func (s *BackendImplementation) requestWithRetriesAndTelemetry( 600 req *http.Request, 601 body *bytes.Buffer, 602 handleResponse func(*http.Response, error) (interface{}, error), 603 ) (*http.Response, interface{}, *time.Duration, error) { 604 s.LeveledLogger.Infof("Requesting %v %v%v", req.Method, req.URL.Host, req.URL.Path) 605 s.maybeSetTelemetryHeader(req) 606 var resp *http.Response 607 var err error 608 var requestDuration time.Duration 609 var result interface{} 610 for retry := 0; ; { 611 start := time.Now() 612 resetBodyReader(body, req) 613 614 resp, err = s.HTTPClient.Do(req) 615 616 requestDuration = time.Since(start) 617 s.LeveledLogger.Infof("Request completed in %v (retry: %v)", requestDuration, retry) 618 619 result, err = handleResponse(resp, err) 620 621 // If the response was okay, or an error that shouldn't be retried, 622 // we're done, and it's safe to leave the retry loop. 623 shouldRetry, noRetryReason := s.shouldRetry(err, req, resp, retry) 624 625 if !shouldRetry { 626 s.LeveledLogger.Infof("Not retrying request: %v", noRetryReason) 627 break 628 } 629 630 sleepDuration := s.sleepTime(retry) 631 retry++ 632 633 s.LeveledLogger.Warnf("Initiating retry %v for request %v %v%v after sleeping %v", 634 retry, req.Method, req.URL.Host, req.URL.Path, sleepDuration) 635 636 time.Sleep(sleepDuration) 637 } 638 639 if err != nil { 640 return nil, nil, nil, err 641 } 642 643 return resp, result, &requestDuration, nil 644 } 645 646 func (s *BackendImplementation) logError(statusCode int, err error) { 647 if stripeErr, ok := err.(*Error); ok { 648 // The Stripe API makes a distinction between errors that were 649 // caused by invalid parameters or something else versus those 650 // that occurred *despite* valid parameters, the latter coming 651 // back with status 402. 652 // 653 // On a 402, log to info so as to not make an integration's log 654 // noisy with error messages that they don't have much control 655 // over. 656 // 657 // Note I use the constant 402 instead of an `http.Status*` 658 // constant because technically 402 is "Payment required". The 659 // Stripe API doesn't comply to the letter of the specification 660 // and uses it in a broader sense. 661 if statusCode == 402 { 662 s.LeveledLogger.Infof("User-compelled request error from Stripe (status %v): %v", 663 statusCode, stripeErr.redact()) 664 } else { 665 s.LeveledLogger.Errorf("Request error from Stripe (status %v): %v", 666 statusCode, stripeErr.redact()) 667 } 668 } else { 669 s.LeveledLogger.Errorf("Error decoding error from Stripe: %v", err) 670 } 671 } 672 673 // DoStreaming is used by CallStreaming to execute an API request. It uses the 674 // backend's HTTP client to execure the request. In successful cases, it sets 675 // a StreamingLastResponse onto v, but in unsuccessful cases handles unmarshaling 676 // errors returned by the API. 677 func (s *BackendImplementation) DoStreaming(req *http.Request, body *bytes.Buffer, v StreamingLastResponseSetter) error { 678 handleResponse := func(res *http.Response, err error) (interface{}, error) { 679 680 // Some sort of connection error 681 if err != nil { 682 s.LeveledLogger.Errorf("Request failed with error: %v", err) 683 return res.Body, err 684 } 685 686 // Successful response, return the body ReadCloser 687 if res.StatusCode < 400 { 688 return res.Body, err 689 } 690 691 // Failure: try and parse the json of the response 692 // when logging the error 693 var resBody []byte 694 resBody, err = ioutil.ReadAll(res.Body) 695 res.Body.Close() 696 if err == nil { 697 err = s.ResponseToError(res, resBody) 698 } else { 699 s.logError(res.StatusCode, err) 700 } 701 702 return res.Body, err 703 } 704 705 resp, result, requestDuration, err := s.requestWithRetriesAndTelemetry(req, body, handleResponse) 706 if err != nil { 707 return err 708 } 709 v.SetLastResponse(newStreamingAPIResponse(resp, result.(io.ReadCloser), requestDuration)) 710 return nil 711 } 712 713 // Do is used by Call to execute an API request and parse the response. It uses 714 // the backend's HTTP client to execute the request and unmarshals the response 715 // into v. It also handles unmarshaling errors returned by the API. 716 func (s *BackendImplementation) Do(req *http.Request, body *bytes.Buffer, v LastResponseSetter) error { 717 handleResponse := func(res *http.Response, err error) (interface{}, error) { 718 var resBody []byte 719 if err == nil { 720 resBody, err = ioutil.ReadAll(res.Body) 721 res.Body.Close() 722 } 723 724 if err != nil { 725 s.LeveledLogger.Errorf("Request failed with error: %v", err) 726 } else if res.StatusCode >= 400 { 727 err = s.ResponseToError(res, resBody) 728 729 s.logError(res.StatusCode, err) 730 } 731 732 return resBody, err 733 } 734 735 res, result, requestDuration, err := s.requestWithRetriesAndTelemetry(req, body, handleResponse) 736 if err != nil { 737 return err 738 } 739 resBody := result.([]byte) 740 s.LeveledLogger.Debugf("Response: %s", string(resBody)) 741 742 err = s.UnmarshalJSONVerbose(res.StatusCode, resBody, v) 743 v.SetLastResponse(newAPIResponse(res, resBody, requestDuration)) 744 return err 745 } 746 747 // ResponseToError converts a stripe response to an Error. 748 func (s *BackendImplementation) ResponseToError(res *http.Response, resBody []byte) error { 749 var raw rawError 750 if s.Type == ConnectBackend { 751 // If this is an OAuth request, deserialize as Error because OAuth errors 752 // are a different shape from the standard API errors. 753 var topLevelError Error 754 if err := s.UnmarshalJSONVerbose(res.StatusCode, resBody, &topLevelError); err != nil { 755 return err 756 } 757 raw.Error = &topLevelError 758 } else { 759 if err := s.UnmarshalJSONVerbose(res.StatusCode, resBody, &raw); err != nil { 760 return err 761 } 762 } 763 764 // no error in resBody 765 if raw.Error == nil { 766 err := errors.New(string(resBody)) 767 return err 768 } 769 raw.Error.HTTPStatusCode = res.StatusCode 770 raw.Error.RequestID = res.Header.Get("Request-Id") 771 772 var typedError error 773 switch raw.Error.Type { 774 case ErrorTypeAPI: 775 typedError = &APIError{stripeErr: raw.Error} 776 case ErrorTypeCard: 777 cardErr := &CardError{stripeErr: raw.Error} 778 779 // `DeclineCode` was traditionally only available on `CardError`, but 780 // we ended up moving it to the top-level error as well. However, keep 781 // it on `CardError` for backwards compatibility. 782 if raw.Error.DeclineCode != "" { 783 cardErr.DeclineCode = raw.Error.DeclineCode 784 } 785 786 typedError = cardErr 787 case ErrorTypeIdempotency: 788 typedError = &IdempotencyError{stripeErr: raw.Error} 789 case ErrorTypeInvalidRequest: 790 typedError = &InvalidRequestError{stripeErr: raw.Error} 791 } 792 raw.Error.Err = typedError 793 794 raw.Error.SetLastResponse(newAPIResponse(res, resBody, nil)) 795 796 return raw.Error 797 } 798 799 // SetMaxNetworkRetries sets max number of retries on failed requests 800 // 801 // This function is deprecated. Please use GetBackendWithConfig instead. 802 func (s *BackendImplementation) SetMaxNetworkRetries(maxNetworkRetries int64) { 803 s.MaxNetworkRetries = maxNetworkRetries 804 } 805 806 // SetNetworkRetriesSleep allows the normal sleep between network retries to be 807 // enabled or disabled. 808 // 809 // This function is available for internal testing only and should never be 810 // used in production. 811 func (s *BackendImplementation) SetNetworkRetriesSleep(sleep bool) { 812 s.networkRetriesSleep = sleep 813 } 814 815 // UnmarshalJSONVerbose unmarshals JSON, but in case of a failure logs and 816 // produces a more descriptive error. 817 func (s *BackendImplementation) UnmarshalJSONVerbose(statusCode int, body []byte, v interface{}) error { 818 err := json.Unmarshal(body, v) 819 if err != nil { 820 // If we got invalid JSON back then something totally unexpected is 821 // happening (caused by a bug on the server side). Put a sample of the 822 // response body into the error message so we can get a better feel for 823 // what the problem was. 824 bodySample := string(body) 825 if len(bodySample) > 500 { 826 bodySample = bodySample[0:500] + " ..." 827 } 828 829 // Make sure a multi-line response ends up all on one line 830 bodySample = strings.Replace(bodySample, "\n", "\\n", -1) 831 832 newErr := fmt.Errorf("Couldn't deserialize JSON (response status: %v, body sample: '%s'): %v", 833 statusCode, bodySample, err) 834 s.LeveledLogger.Errorf("%s", newErr.Error()) 835 return newErr 836 } 837 838 return nil 839 } 840 841 // Regular expressions used to match a few error types that we know we don't 842 // want to retry. Unfortunately these errors aren't typed so we match on the 843 // error's message. 844 var ( 845 redirectsErrorRE = regexp.MustCompile(`stopped after \d+ redirects\z`) 846 schemeErrorRE = regexp.MustCompile(`unsupported protocol scheme`) 847 ) 848 849 // Checks if an error is a problem that we should retry on. This includes both 850 // socket errors that may represent an intermittent problem and some special 851 // HTTP statuses. 852 // 853 // Returns a boolean indicating whether a client should retry. If false, a 854 // second string parameter is also returned with a short message indicating why 855 // no retry should occur. This can be used for logging/informational purposes. 856 func (s *BackendImplementation) shouldRetry(err error, req *http.Request, resp *http.Response, numRetries int) (bool, string) { 857 if numRetries >= int(s.MaxNetworkRetries) { 858 return false, "max retries exceeded" 859 } 860 861 stripeErr, _ := err.(*Error) 862 863 // Don't retry if the context was canceled or its deadline was exceeded. 864 if req.Context() != nil && req.Context().Err() != nil { 865 switch req.Context().Err() { 866 case context.Canceled: 867 return false, "context canceled" 868 case context.DeadlineExceeded: 869 return false, "context deadline exceeded" 870 default: 871 return false, fmt.Sprintf("unknown context error: %v", req.Context().Err()) 872 } 873 } 874 875 // We retry most errors that come out of HTTP requests except for a curated 876 // list that we know not to be retryable. This list is probably not 877 // exhaustive, so it'd be okay to add new errors to it. It'd also be okay to 878 // flip this to an inverted strategy of retrying only errors that we know 879 // to be retryable in a future refactor, if a good methodology is found for 880 // identifying that full set of errors. 881 if stripeErr == nil && err != nil { 882 if urlErr, ok := err.(*url.Error); ok { 883 // Don't retry too many redirects. 884 if redirectsErrorRE.MatchString(urlErr.Error()) { 885 return false, urlErr.Error() 886 } 887 888 // Don't retry invalid protocol scheme. 889 if schemeErrorRE.MatchString(urlErr.Error()) { 890 return false, urlErr.Error() 891 } 892 893 // Don't retry TLS certificate validation problems. 894 if _, ok := urlErr.Err.(x509.UnknownAuthorityError); ok { 895 return false, urlErr.Error() 896 } 897 } 898 899 // Do retry every other type of non-Stripe error. 900 return true, "" 901 } 902 903 // The API may ask us not to retry (e.g. if doing so would be a no-op), or 904 // advise us to retry (e.g. in cases of lock timeouts). Defer to those 905 // instructions if given. 906 if resp.Header.Get("Stripe-Should-Retry") == "false" { 907 return false, "`Stripe-Should-Retry` header returned `false`" 908 } 909 if resp.Header.Get("Stripe-Should-Retry") == "true" { 910 return true, "" 911 } 912 913 // 409 Conflict 914 if resp.StatusCode == http.StatusConflict { 915 return true, "" 916 } 917 918 // 429 Too Many Requests 919 // 920 // There are a few different problems that can lead to a 429. The most 921 // common is rate limiting, on which we *don't* want to retry because 922 // that'd likely contribute to more contention problems. However, some 429s 923 // are lock timeouts, which is when a request conflicted with another 924 // request or an internal process on some particular object. These 429s are 925 // safe to retry. 926 if resp.StatusCode == http.StatusTooManyRequests { 927 if stripeErr != nil && stripeErr.Code == ErrorCodeLockTimeout { 928 return true, "" 929 } 930 } 931 932 // 500 Internal Server Error 933 // 934 // We only bother retrying these for non-POST requests. POSTs end up being 935 // cached by the idempotency layer so there's no purpose in retrying them. 936 if resp.StatusCode >= http.StatusInternalServerError && req.Method != http.MethodPost { 937 return true, "" 938 } 939 940 // 503 Service Unavailable 941 if resp.StatusCode == http.StatusServiceUnavailable { 942 return true, "" 943 } 944 945 return false, "response not known to be safe for retry" 946 } 947 948 // sleepTime calculates sleeping/delay time in milliseconds between failure and a new one request. 949 func (s *BackendImplementation) sleepTime(numRetries int) time.Duration { 950 // We disable sleeping in some cases for tests. 951 if !s.networkRetriesSleep { 952 return 0 * time.Second 953 } 954 955 // Apply exponential backoff with minNetworkRetriesDelay on the 956 // number of num_retries so far as inputs. 957 delay := minNetworkRetriesDelay + minNetworkRetriesDelay*time.Duration(numRetries*numRetries) 958 959 // Do not allow the number to exceed maxNetworkRetriesDelay. 960 if delay > maxNetworkRetriesDelay { 961 delay = maxNetworkRetriesDelay 962 } 963 964 // Apply some jitter by randomizing the value in the range of 75%-100%. 965 jitter := rand.Int63n(int64(delay / 4)) 966 delay -= time.Duration(jitter) 967 968 // But never sleep less than the base sleep seconds. 969 if delay < minNetworkRetriesDelay { 970 delay = minNetworkRetriesDelay 971 } 972 973 return delay 974 } 975 976 // Backends are the currently supported endpoints. 977 type Backends struct { 978 API, Connect, Uploads Backend 979 mu sync.RWMutex 980 } 981 982 // LastResponseSetter defines a type that contains an HTTP response from a Stripe 983 // API endpoint. 984 type LastResponseSetter interface { 985 SetLastResponse(response *APIResponse) 986 } 987 988 // StreamingLastResponseSetter defines a type that contains an HTTP response from a Stripe 989 // API endpoint. 990 type StreamingLastResponseSetter interface { 991 SetLastResponse(response *StreamingAPIResponse) 992 } 993 994 // SupportedBackend is an enumeration of supported Stripe endpoints. 995 // Currently supported values are "api" and "uploads". 996 type SupportedBackend string 997 998 // 999 // Public functions 1000 // 1001 1002 // Bool returns a pointer to the bool value passed in. 1003 func Bool(v bool) *bool { 1004 return &v 1005 } 1006 1007 // BoolValue returns the value of the bool pointer passed in or 1008 // false if the pointer is nil. 1009 func BoolValue(v *bool) bool { 1010 if v != nil { 1011 return *v 1012 } 1013 return false 1014 } 1015 1016 // BoolSlice returns a slice of bool pointers given a slice of bools. 1017 func BoolSlice(v []bool) []*bool { 1018 out := make([]*bool, len(v)) 1019 for i := range v { 1020 out[i] = &v[i] 1021 } 1022 return out 1023 } 1024 1025 // Float64 returns a pointer to the float64 value passed in. 1026 func Float64(v float64) *float64 { 1027 return &v 1028 } 1029 1030 // Float64Value returns the value of the float64 pointer passed in or 1031 // 0 if the pointer is nil. 1032 func Float64Value(v *float64) float64 { 1033 if v != nil { 1034 return *v 1035 } 1036 return 0 1037 } 1038 1039 // Float64Slice returns a slice of float64 pointers given a slice of float64s. 1040 func Float64Slice(v []float64) []*float64 { 1041 out := make([]*float64, len(v)) 1042 for i := range v { 1043 out[i] = &v[i] 1044 } 1045 return out 1046 } 1047 1048 // FormatURLPath takes a format string (of the kind used in the fmt package) 1049 // representing a URL path with a number of parameters that belong in the path 1050 // and returns a formatted string. 1051 // 1052 // This is mostly a pass through to Sprintf. It exists to make it 1053 // it impossible to accidentally provide a parameter type that would be 1054 // formatted improperly; for example, a string pointer instead of a string. 1055 // 1056 // It also URL-escapes every given parameter. This usually isn't necessary for 1057 // a standard Stripe ID, but is needed in places where user-provided IDs are 1058 // allowed, like in coupons or plans. We apply it broadly for extra safety. 1059 func FormatURLPath(format string, params ...string) string { 1060 // Convert parameters to interface{} and URL-escape them 1061 untypedParams := make([]interface{}, len(params)) 1062 for i, param := range params { 1063 untypedParams[i] = interface{}(url.QueryEscape(param)) 1064 } 1065 1066 return fmt.Sprintf(format, untypedParams...) 1067 } 1068 1069 // GetBackend returns one of the library's supported backends based off of the 1070 // given argument. 1071 // 1072 // It returns an existing default backend if one's already been created. 1073 func GetBackend(backendType SupportedBackend) Backend { 1074 var backend Backend 1075 1076 backends.mu.RLock() 1077 switch backendType { 1078 case APIBackend: 1079 backend = backends.API 1080 case ConnectBackend: 1081 backend = backends.Connect 1082 case UploadsBackend: 1083 backend = backends.Uploads 1084 } 1085 backends.mu.RUnlock() 1086 if backend != nil { 1087 return backend 1088 } 1089 1090 backend = GetBackendWithConfig( 1091 backendType, 1092 &BackendConfig{ 1093 HTTPClient: httpClient, 1094 LeveledLogger: nil, // Set by GetBackendWithConfiguation when nil 1095 MaxNetworkRetries: nil, // Set by GetBackendWithConfiguation when nil 1096 URL: nil, // Set by GetBackendWithConfiguation when nil 1097 }, 1098 ) 1099 1100 SetBackend(backendType, backend) 1101 1102 return backend 1103 } 1104 1105 // GetBackendWithConfig is the same as GetBackend except that it can be given a 1106 // configuration struct that will configure certain aspects of the backend 1107 // that's return. 1108 func GetBackendWithConfig(backendType SupportedBackend, config *BackendConfig) Backend { 1109 if config.HTTPClient == nil { 1110 config.HTTPClient = httpClient 1111 } 1112 1113 if config.LeveledLogger == nil { 1114 config.LeveledLogger = DefaultLeveledLogger 1115 } 1116 1117 if config.MaxNetworkRetries == nil { 1118 config.MaxNetworkRetries = Int64(DefaultMaxNetworkRetries) 1119 } 1120 1121 switch backendType { 1122 case APIBackend: 1123 if config.URL == nil { 1124 config.URL = String(APIURL) 1125 } 1126 1127 config.URL = String(normalizeURL(*config.URL)) 1128 1129 return newBackendImplementation(backendType, config) 1130 1131 case UploadsBackend: 1132 if config.URL == nil { 1133 config.URL = String(UploadsURL) 1134 } 1135 1136 config.URL = String(normalizeURL(*config.URL)) 1137 1138 return newBackendImplementation(backendType, config) 1139 1140 case ConnectBackend: 1141 if config.URL == nil { 1142 config.URL = String(ConnectURL) 1143 } 1144 1145 config.URL = String(normalizeURL(*config.URL)) 1146 1147 return newBackendImplementation(backendType, config) 1148 } 1149 1150 return nil 1151 } 1152 1153 // Int64 returns a pointer to the int64 value passed in. 1154 func Int64(v int64) *int64 { 1155 return &v 1156 } 1157 1158 // Int64Value returns the value of the int64 pointer passed in or 1159 // 0 if the pointer is nil. 1160 func Int64Value(v *int64) int64 { 1161 if v != nil { 1162 return *v 1163 } 1164 return 0 1165 } 1166 1167 // Int64Slice returns a slice of int64 pointers given a slice of int64s. 1168 func Int64Slice(v []int64) []*int64 { 1169 out := make([]*int64, len(v)) 1170 for i := range v { 1171 out[i] = &v[i] 1172 } 1173 return out 1174 } 1175 1176 // NewBackends creates a new set of backends with the given HTTP client. 1177 func NewBackends(httpClient *http.Client) *Backends { 1178 apiConfig := &BackendConfig{HTTPClient: httpClient} 1179 connectConfig := &BackendConfig{HTTPClient: httpClient} 1180 uploadConfig := &BackendConfig{HTTPClient: httpClient} 1181 return &Backends{ 1182 API: GetBackendWithConfig(APIBackend, apiConfig), 1183 Connect: GetBackendWithConfig(ConnectBackend, connectConfig), 1184 Uploads: GetBackendWithConfig(UploadsBackend, uploadConfig), 1185 } 1186 } 1187 1188 // NewBackendsWithConfig creates a new set of backends with the given config for all backends. 1189 // Useful for setting up client with a custom logger and http client. 1190 func NewBackendsWithConfig(config *BackendConfig) *Backends { 1191 return &Backends{ 1192 API: GetBackendWithConfig(APIBackend, config), 1193 Connect: GetBackendWithConfig(ConnectBackend, config), 1194 Uploads: GetBackendWithConfig(UploadsBackend, config), 1195 } 1196 } 1197 1198 // ParseID attempts to parse a string scalar from a given JSON value which is 1199 // still encoded as []byte. If the value was a string, it returns the string 1200 // along with true as the second return value. If not, false is returned as the 1201 // second return value. 1202 // 1203 // The purpose of this function is to detect whether a given value in a 1204 // response from the Stripe API is a string ID or an expanded object. 1205 func ParseID(data []byte) (string, bool) { 1206 s := string(data) 1207 1208 if !strings.HasPrefix(s, "\"") { 1209 return "", false 1210 } 1211 1212 if !strings.HasSuffix(s, "\"") { 1213 return "", false 1214 } 1215 1216 // Edge case that should never happen; found via fuzzing 1217 if s == "\"" { 1218 return "", false 1219 } 1220 1221 return s[1 : len(s)-1], true 1222 } 1223 1224 // SetAppInfo sets app information. See AppInfo. 1225 func SetAppInfo(info *AppInfo) { 1226 if info != nil && info.Name == "" { 1227 panic(fmt.Errorf("App info name cannot be empty")) 1228 } 1229 appInfo = info 1230 1231 // This is run in init, but we need to reinitialize it now that we have 1232 // some app info. 1233 initUserAgent() 1234 } 1235 1236 // SetBackend sets the backend used in the binding. 1237 func SetBackend(backend SupportedBackend, b Backend) { 1238 backends.mu.Lock() 1239 defer backends.mu.Unlock() 1240 1241 switch backend { 1242 case APIBackend: 1243 backends.API = b 1244 case ConnectBackend: 1245 backends.Connect = b 1246 case UploadsBackend: 1247 backends.Uploads = b 1248 } 1249 } 1250 1251 // SetHTTPClient overrides the default HTTP client. 1252 // This is useful if you're running in a Google AppEngine environment 1253 // where the http.DefaultClient is not available. 1254 func SetHTTPClient(client *http.Client) { 1255 httpClient = client 1256 } 1257 1258 // String returns a pointer to the string value passed in. 1259 func String(v string) *string { 1260 return &v 1261 } 1262 1263 // StringValue returns the value of the string pointer passed in or 1264 // "" if the pointer is nil. 1265 func StringValue(v *string) string { 1266 if v != nil { 1267 return *v 1268 } 1269 return "" 1270 } 1271 1272 // StringSlice returns a slice of string pointers given a slice of strings. 1273 func StringSlice(v []string) []*string { 1274 out := make([]*string, len(v)) 1275 for i := range v { 1276 out[i] = &v[i] 1277 } 1278 return out 1279 } 1280 1281 // 1282 // Private constants 1283 // 1284 1285 // clientversion is the binding version 1286 const clientversion = "76.25.0" 1287 1288 // defaultHTTPTimeout is the default timeout on the http.Client used by the library. 1289 // This is chosen to be consistent with the other Stripe language libraries and 1290 // to coordinate with other timeouts configured in the Stripe infrastructure. 1291 const defaultHTTPTimeout = 80 * time.Second 1292 1293 // maxNetworkRetriesDelay and minNetworkRetriesDelay defines sleep time in milliseconds between 1294 // tries to send HTTP request again after network failure. 1295 const maxNetworkRetriesDelay = 5000 * time.Millisecond 1296 const minNetworkRetriesDelay = 500 * time.Millisecond 1297 1298 // The number of requestMetric objects to buffer for client telemetry. When the 1299 // buffer is full, new requestMetrics are dropped. 1300 const telemetryBufferSize = 16 1301 1302 // 1303 // Private types 1304 // 1305 1306 // nopReadCloser's sole purpose is to give us a way to turn an `io.Reader` into 1307 // an `io.ReadCloser` by adding a no-op implementation of the `Closer` 1308 // interface. We need this because `http.Request`'s `Body` takes an 1309 // `io.ReadCloser` instead of a `io.Reader`. 1310 type nopReadCloser struct { 1311 io.Reader 1312 } 1313 1314 func (nopReadCloser) Close() error { return nil } 1315 1316 // stripeClientUserAgent contains information about the current runtime which 1317 // is serialized and sent in the `X-Stripe-Client-User-Agent` as additional 1318 // debugging information. 1319 type stripeClientUserAgent struct { 1320 Application *AppInfo `json:"application"` 1321 BindingsVersion string `json:"bindings_version"` 1322 Language string `json:"lang"` 1323 LanguageVersion string `json:"lang_version"` 1324 Publisher string `json:"publisher"` 1325 Uname string `json:"uname"` 1326 } 1327 1328 // requestMetrics contains the id and duration of the last request sent 1329 type requestMetrics struct { 1330 RequestDurationMS *int `json:"request_duration_ms"` 1331 RequestID string `json:"request_id"` 1332 Usage []string `json:"usage"` 1333 } 1334 1335 // requestTelemetry contains the payload sent in the 1336 // `X-Stripe-Client-Telemetry` header when BackendConfig.EnableTelemetry = true. 1337 type requestTelemetry struct { 1338 LastRequestMetrics requestMetrics `json:"last_request_metrics"` 1339 } 1340 1341 // 1342 // Private variables 1343 // 1344 1345 var appInfo *AppInfo 1346 var backends Backends 1347 var encodedStripeUserAgent string 1348 var encodedStripeUserAgentReady *sync.Once 1349 var encodedUserAgent string 1350 1351 // The default HTTP client used for communication with any of Stripe's 1352 // backends. 1353 // 1354 // Can be overridden with the function `SetHTTPClient` or by setting the 1355 // `HTTPClient` value when using `BackendConfig`. 1356 // 1357 // When adding something new here, see also `stripe_go115.go` where you'll want 1358 // to add it as well. 1359 var httpClient = &http.Client{ 1360 Timeout: defaultHTTPTimeout, 1361 1362 // There is a bug in Go's HTTP/2 implementation that occasionally causes it 1363 // to send an empty body when it receives a `GOAWAY` message from a server: 1364 // 1365 // https://github.com/golang/go/issues/32441 1366 // 1367 // This is particularly problematic for this library because the empty body 1368 // results in no parameters being sent, which usually results in a 400, 1369 // which is a status code expressly not covered by retry logic. 1370 // 1371 // The bug seems to be somewhat tricky to fix and hasn't seen any traction 1372 // lately, so for now we're mitigating by disabling HTTP/2 in stripe-go by 1373 // default. Users who like to live dangerously can still re-enable it by 1374 // specifying a custom HTTP client. When the bug above is fixed, we can 1375 // turn it back on. 1376 // 1377 // The particular methodology here for disabling HTTP/2 is a little 1378 // confusing at first glance, but is recommended by the `net/http` 1379 // documentation ("Programs that must disable HTTP/2 can do so by setting 1380 // Transport.TLSNextProto (for clients) ... to a non-nil, empty map.") 1381 // 1382 // Note that the test suite still uses HTTP/2 to run as it specifies its 1383 // own HTTP client with it enabled. See `testing/testing.go`. 1384 // 1385 // (Written 2019/07/24.) 1386 // 1387 // UPDATE: With the release of Go 1.15, this bug has been fixed. 1388 // As such, `stripe_go115.go` contains conditionally-compiled code that sets 1389 // a different HTTP client as the default, since Go 1.15+ does not contain 1390 // the aforementioned HTTP/2 bug. 1391 Transport: &http.Transport{ 1392 TLSNextProto: make(map[string]func(string, *tls.Conn) http.RoundTripper), 1393 }, 1394 } 1395 1396 // 1397 // Private functions 1398 // 1399 1400 // getUname tries to get a uname from the system, but not that hard. It tries 1401 // to execute `uname -a`, but swallows any errors in case that didn't work 1402 // (i.e. non-Unix non-Mac system or some other reason). 1403 func getUname() string { 1404 path, err := exec.LookPath("uname") 1405 if err != nil { 1406 return UnknownPlatform 1407 } 1408 1409 cmd := exec.Command(path, "-a") 1410 var out bytes.Buffer 1411 cmd.Stderr = nil // goes to os.DevNull 1412 cmd.Stdout = &out 1413 err = cmd.Run() 1414 if err != nil { 1415 return UnknownPlatform 1416 } 1417 1418 return out.String() 1419 } 1420 1421 func init() { 1422 initUserAgent() 1423 } 1424 1425 func initUserAgent() { 1426 encodedUserAgent = "Stripe/v1 GoBindings/" + clientversion 1427 if appInfo != nil { 1428 encodedUserAgent += " " + appInfo.formatUserAgent() 1429 } 1430 encodedStripeUserAgentReady = &sync.Once{} 1431 } 1432 1433 func getEncodedStripeUserAgent() string { 1434 encodedStripeUserAgentReady.Do(func() { 1435 stripeUserAgent := &stripeClientUserAgent{ 1436 Application: appInfo, 1437 BindingsVersion: clientversion, 1438 Language: "go", 1439 LanguageVersion: runtime.Version(), 1440 Publisher: "stripe", 1441 Uname: getUname(), 1442 } 1443 marshaled, err := json.Marshal(stripeUserAgent) 1444 // Encoding this struct should never be a problem, so we're okay to panic 1445 // in case it is for some reason. 1446 if err != nil { 1447 panic(err) 1448 } 1449 encodedStripeUserAgent = string(marshaled) 1450 }) 1451 return encodedStripeUserAgent 1452 } 1453 1454 func isHTTPWriteMethod(method string) bool { 1455 return method == http.MethodPost || method == http.MethodPut || method == http.MethodPatch || method == http.MethodDelete 1456 } 1457 1458 // newBackendImplementation returns a new Backend based off a given type and 1459 // fully initialized BackendConfig struct. 1460 // 1461 // The vast majority of the time you should be calling GetBackendWithConfig 1462 // instead of this function. 1463 func newBackendImplementation(backendType SupportedBackend, config *BackendConfig) Backend { 1464 enableTelemetry := EnableTelemetry 1465 if config.EnableTelemetry != nil { 1466 enableTelemetry = *config.EnableTelemetry 1467 } 1468 1469 var requestMetricsBuffer chan requestMetrics 1470 1471 // only allocate the requestMetrics buffer if client telemetry is enabled. 1472 if enableTelemetry { 1473 requestMetricsBuffer = make(chan requestMetrics, telemetryBufferSize) 1474 } 1475 1476 return &BackendImplementation{ 1477 HTTPClient: config.HTTPClient, 1478 LeveledLogger: config.LeveledLogger, 1479 MaxNetworkRetries: *config.MaxNetworkRetries, 1480 Type: backendType, 1481 URL: *config.URL, 1482 enableTelemetry: enableTelemetry, 1483 networkRetriesSleep: true, 1484 requestMetricsBuffer: requestMetricsBuffer, 1485 } 1486 } 1487 1488 func normalizeURL(url string) string { 1489 // All paths include a leading slash, so to keep logs pretty, trim a 1490 // trailing slash on the URL. 1491 url = strings.TrimSuffix(url, "/") 1492 1493 // For a long time we had the `/v1` suffix as part of a configured URL 1494 // rather than in the per-package URLs throughout the library. Continue 1495 // to support this for the time being by stripping one that's been 1496 // passed for better backwards compatibility. 1497 url = strings.TrimSuffix(url, "/v1") 1498 1499 return url 1500 }