1package session 2 3import ( 4 "crypto/tls" 5 "crypto/x509" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "net/http" 10 "os" 11 "time" 12 13 "github.com/aws/aws-sdk-go/aws" 14 "github.com/aws/aws-sdk-go/aws/awserr" 15 "github.com/aws/aws-sdk-go/aws/client" 16 "github.com/aws/aws-sdk-go/aws/corehandlers" 17 "github.com/aws/aws-sdk-go/aws/credentials" 18 "github.com/aws/aws-sdk-go/aws/csm" 19 "github.com/aws/aws-sdk-go/aws/defaults" 20 "github.com/aws/aws-sdk-go/aws/endpoints" 21 "github.com/aws/aws-sdk-go/aws/request" 22) 23 24const ( 25 // ErrCodeSharedConfig represents an error that occurs in the shared 26 // configuration logic 27 ErrCodeSharedConfig = "SharedConfigErr" 28) 29 30// ErrSharedConfigSourceCollision will be returned if a section contains both 31// source_profile and credential_source 32var ErrSharedConfigSourceCollision = awserr.New(ErrCodeSharedConfig, "only source profile or credential source can be specified, not both", nil) 33 34// ErrSharedConfigECSContainerEnvVarEmpty will be returned if the environment 35// variables are empty and Environment was set as the credential source 36var ErrSharedConfigECSContainerEnvVarEmpty = awserr.New(ErrCodeSharedConfig, "EcsContainer was specified as the credential_source, but 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI' was not set", nil) 37 38// ErrSharedConfigInvalidCredSource will be returned if an invalid credential source was provided 39var ErrSharedConfigInvalidCredSource = awserr.New(ErrCodeSharedConfig, "credential source values must be EcsContainer, Ec2InstanceMetadata, or Environment", nil) 40 41// A Session provides a central location to create service clients from and 42// store configurations and request handlers for those services. 43// 44// Sessions are safe to create service clients concurrently, but it is not safe 45// to mutate the Session concurrently. 46// 47// The Session satisfies the service client's client.ConfigProvider. 48type Session struct { 49 Config *aws.Config 50 Handlers request.Handlers 51} 52 53// New creates a new instance of the handlers merging in the provided configs 54// on top of the SDK's default configurations. Once the Session is created it 55// can be mutated to modify the Config or Handlers. The Session is safe to be 56// read concurrently, but it should not be written to concurrently. 57// 58// If the AWS_SDK_LOAD_CONFIG environment is set to a truthy value, the New 59// method could now encounter an error when loading the configuration. When 60// The environment variable is set, and an error occurs, New will return a 61// session that will fail all requests reporting the error that occurred while 62// loading the session. Use NewSession to get the error when creating the 63// session. 64// 65// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value 66// the shared config file (~/.aws/config) will also be loaded, in addition to 67// the shared credentials file (~/.aws/credentials). Values set in both the 68// shared config, and shared credentials will be taken from the shared 69// credentials file. 70// 71// Deprecated: Use NewSession functions to create sessions instead. NewSession 72// has the same functionality as New except an error can be returned when the 73// func is called instead of waiting to receive an error until a request is made. 74func New(cfgs ...*aws.Config) *Session { 75 // load initial config from environment 76 envCfg, envErr := loadEnvConfig() 77 78 if envCfg.EnableSharedConfig { 79 var cfg aws.Config 80 cfg.MergeIn(cfgs...) 81 s, err := NewSessionWithOptions(Options{ 82 Config: cfg, 83 SharedConfigState: SharedConfigEnable, 84 }) 85 if err != nil { 86 // Old session.New expected all errors to be discovered when 87 // a request is made, and would report the errors then. This 88 // needs to be replicated if an error occurs while creating 89 // the session. 90 msg := "failed to create session with AWS_SDK_LOAD_CONFIG enabled. " + 91 "Use session.NewSession to handle errors occurring during session creation." 92 93 // Session creation failed, need to report the error and prevent 94 // any requests from succeeding. 95 s = &Session{Config: defaults.Config()} 96 s.logDeprecatedNewSessionError(msg, err, cfgs) 97 } 98 99 return s 100 } 101 102 s := deprecatedNewSession(cfgs...) 103 if envErr != nil { 104 msg := "failed to load env config" 105 s.logDeprecatedNewSessionError(msg, envErr, cfgs) 106 } 107 108 if csmCfg, err := loadCSMConfig(envCfg, []string{}); err != nil { 109 if l := s.Config.Logger; l != nil { 110 l.Log(fmt.Sprintf("ERROR: failed to load CSM configuration, %v", err)) 111 } 112 } else if csmCfg.Enabled { 113 err := enableCSM(&s.Handlers, csmCfg, s.Config.Logger) 114 if err != nil { 115 msg := "failed to enable CSM" 116 s.logDeprecatedNewSessionError(msg, err, cfgs) 117 } 118 } 119 120 return s 121} 122 123// NewSession returns a new Session created from SDK defaults, config files, 124// environment, and user provided config files. Once the Session is created 125// it can be mutated to modify the Config or Handlers. The Session is safe to 126// be read concurrently, but it should not be written to concurrently. 127// 128// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value 129// the shared config file (~/.aws/config) will also be loaded in addition to 130// the shared credentials file (~/.aws/credentials). Values set in both the 131// shared config, and shared credentials will be taken from the shared 132// credentials file. Enabling the Shared Config will also allow the Session 133// to be built with retrieving credentials with AssumeRole set in the config. 134// 135// See the NewSessionWithOptions func for information on how to override or 136// control through code how the Session will be created, such as specifying the 137// config profile, and controlling if shared config is enabled or not. 138func NewSession(cfgs ...*aws.Config) (*Session, error) { 139 opts := Options{} 140 opts.Config.MergeIn(cfgs...) 141 142 return NewSessionWithOptions(opts) 143} 144 145// SharedConfigState provides the ability to optionally override the state 146// of the session's creation based on the shared config being enabled or 147// disabled. 148type SharedConfigState int 149 150const ( 151 // SharedConfigStateFromEnv does not override any state of the 152 // AWS_SDK_LOAD_CONFIG env var. It is the default value of the 153 // SharedConfigState type. 154 SharedConfigStateFromEnv SharedConfigState = iota 155 156 // SharedConfigDisable overrides the AWS_SDK_LOAD_CONFIG env var value 157 // and disables the shared config functionality. 158 SharedConfigDisable 159 160 // SharedConfigEnable overrides the AWS_SDK_LOAD_CONFIG env var value 161 // and enables the shared config functionality. 162 SharedConfigEnable 163) 164 165// Options provides the means to control how a Session is created and what 166// configuration values will be loaded. 167// 168type Options struct { 169 // Provides config values for the SDK to use when creating service clients 170 // and making API requests to services. Any value set in with this field 171 // will override the associated value provided by the SDK defaults, 172 // environment or config files where relevant. 173 // 174 // If not set, configuration values from from SDK defaults, environment, 175 // config will be used. 176 Config aws.Config 177 178 // Overrides the config profile the Session should be created from. If not 179 // set the value of the environment variable will be loaded (AWS_PROFILE, 180 // or AWS_DEFAULT_PROFILE if the Shared Config is enabled). 181 // 182 // If not set and environment variables are not set the "default" 183 // (DefaultSharedConfigProfile) will be used as the profile to load the 184 // session config from. 185 Profile string 186 187 // Instructs how the Session will be created based on the AWS_SDK_LOAD_CONFIG 188 // environment variable. By default a Session will be created using the 189 // value provided by the AWS_SDK_LOAD_CONFIG environment variable. 190 // 191 // Setting this value to SharedConfigEnable or SharedConfigDisable 192 // will allow you to override the AWS_SDK_LOAD_CONFIG environment variable 193 // and enable or disable the shared config functionality. 194 SharedConfigState SharedConfigState 195 196 // Ordered list of files the session will load configuration from. 197 // It will override environment variable AWS_SHARED_CREDENTIALS_FILE, AWS_CONFIG_FILE. 198 SharedConfigFiles []string 199 200 // When the SDK's shared config is configured to assume a role with MFA 201 // this option is required in order to provide the mechanism that will 202 // retrieve the MFA token. There is no default value for this field. If 203 // it is not set an error will be returned when creating the session. 204 // 205 // This token provider will be called when ever the assumed role's 206 // credentials need to be refreshed. Within the context of service clients 207 // all sharing the same session the SDK will ensure calls to the token 208 // provider are atomic. When sharing a token provider across multiple 209 // sessions additional synchronization logic is needed to ensure the 210 // token providers do not introduce race conditions. It is recommend to 211 // share the session where possible. 212 // 213 // stscreds.StdinTokenProvider is a basic implementation that will prompt 214 // from stdin for the MFA token code. 215 // 216 // This field is only used if the shared configuration is enabled, and 217 // the config enables assume role wit MFA via the mfa_serial field. 218 AssumeRoleTokenProvider func() (string, error) 219 220 // When the SDK's shared config is configured to assume a role this option 221 // may be provided to set the expiry duration of the STS credentials. 222 // Defaults to 15 minutes if not set as documented in the 223 // stscreds.AssumeRoleProvider. 224 AssumeRoleDuration time.Duration 225 226 // Reader for a custom Credentials Authority (CA) bundle in PEM format that 227 // the SDK will use instead of the default system's root CA bundle. Use this 228 // only if you want to replace the CA bundle the SDK uses for TLS requests. 229 // 230 // Enabling this option will attempt to merge the Transport into the SDK's HTTP 231 // client. If the client's Transport is not a http.Transport an error will be 232 // returned. If the Transport's TLS config is set this option will cause the SDK 233 // to overwrite the Transport's TLS config's RootCAs value. If the CA 234 // bundle reader contains multiple certificates all of them will be loaded. 235 // 236 // The Session option CustomCABundle is also available when creating sessions 237 // to also enable this feature. CustomCABundle session option field has priority 238 // over the AWS_CA_BUNDLE environment variable, and will be used if both are set. 239 CustomCABundle io.Reader 240 241 // The handlers that the session and all API clients will be created with. 242 // This must be a complete set of handlers. Use the defaults.Handlers() 243 // function to initialize this value before changing the handlers to be 244 // used by the SDK. 245 Handlers request.Handlers 246} 247 248// NewSessionWithOptions returns a new Session created from SDK defaults, config files, 249// environment, and user provided config files. This func uses the Options 250// values to configure how the Session is created. 251// 252// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value 253// the shared config file (~/.aws/config) will also be loaded in addition to 254// the shared credentials file (~/.aws/credentials). Values set in both the 255// shared config, and shared credentials will be taken from the shared 256// credentials file. Enabling the Shared Config will also allow the Session 257// to be built with retrieving credentials with AssumeRole set in the config. 258// 259// // Equivalent to session.New 260// sess := session.Must(session.NewSessionWithOptions(session.Options{})) 261// 262// // Specify profile to load for the session's config 263// sess := session.Must(session.NewSessionWithOptions(session.Options{ 264// Profile: "profile_name", 265// })) 266// 267// // Specify profile for config and region for requests 268// sess := session.Must(session.NewSessionWithOptions(session.Options{ 269// Config: aws.Config{Region: aws.String("us-east-1")}, 270// Profile: "profile_name", 271// })) 272// 273// // Force enable Shared Config support 274// sess := session.Must(session.NewSessionWithOptions(session.Options{ 275// SharedConfigState: session.SharedConfigEnable, 276// })) 277func NewSessionWithOptions(opts Options) (*Session, error) { 278 var envCfg envConfig 279 var err error 280 if opts.SharedConfigState == SharedConfigEnable { 281 envCfg, err = loadSharedEnvConfig() 282 if err != nil { 283 return nil, fmt.Errorf("failed to load shared config, %v", err) 284 } 285 } else { 286 envCfg, err = loadEnvConfig() 287 if err != nil { 288 return nil, fmt.Errorf("failed to load environment config, %v", err) 289 } 290 } 291 292 if len(opts.Profile) != 0 { 293 envCfg.Profile = opts.Profile 294 } 295 296 switch opts.SharedConfigState { 297 case SharedConfigDisable: 298 envCfg.EnableSharedConfig = false 299 case SharedConfigEnable: 300 envCfg.EnableSharedConfig = true 301 } 302 303 // Only use AWS_CA_BUNDLE if session option is not provided. 304 if len(envCfg.CustomCABundle) != 0 && opts.CustomCABundle == nil { 305 f, err := os.Open(envCfg.CustomCABundle) 306 if err != nil { 307 return nil, awserr.New("LoadCustomCABundleError", 308 "failed to open custom CA bundle PEM file", err) 309 } 310 defer f.Close() 311 opts.CustomCABundle = f 312 } 313 314 return newSession(opts, envCfg, &opts.Config) 315} 316 317// Must is a helper function to ensure the Session is valid and there was no 318// error when calling a NewSession function. 319// 320// This helper is intended to be used in variable initialization to load the 321// Session and configuration at startup. Such as: 322// 323// var sess = session.Must(session.NewSession()) 324func Must(sess *Session, err error) *Session { 325 if err != nil { 326 panic(err) 327 } 328 329 return sess 330} 331 332func deprecatedNewSession(cfgs ...*aws.Config) *Session { 333 cfg := defaults.Config() 334 handlers := defaults.Handlers() 335 336 // Apply the passed in configs so the configuration can be applied to the 337 // default credential chain 338 cfg.MergeIn(cfgs...) 339 if cfg.EndpointResolver == nil { 340 // An endpoint resolver is required for a session to be able to provide 341 // endpoints for service client configurations. 342 cfg.EndpointResolver = endpoints.DefaultResolver() 343 } 344 cfg.Credentials = defaults.CredChain(cfg, handlers) 345 346 // Reapply any passed in configs to override credentials if set 347 cfg.MergeIn(cfgs...) 348 349 s := &Session{ 350 Config: cfg, 351 Handlers: handlers, 352 } 353 354 initHandlers(s) 355 return s 356} 357 358func enableCSM(handlers *request.Handlers, cfg csmConfig, logger aws.Logger) error { 359 if logger != nil { 360 logger.Log("Enabling CSM") 361 } 362 363 r, err := csm.Start(cfg.ClientID, csm.AddressWithDefaults(cfg.Host, cfg.Port)) 364 if err != nil { 365 return err 366 } 367 r.InjectHandlers(handlers) 368 369 return nil 370} 371 372func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session, error) { 373 cfg := defaults.Config() 374 375 handlers := opts.Handlers 376 if handlers.IsEmpty() { 377 handlers = defaults.Handlers() 378 } 379 380 // Get a merged version of the user provided config to determine if 381 // credentials were. 382 userCfg := &aws.Config{} 383 userCfg.MergeIn(cfgs...) 384 cfg.MergeIn(userCfg) 385 386 // Ordered config files will be loaded in with later files overwriting 387 // previous config file values. 388 var cfgFiles []string 389 if opts.SharedConfigFiles != nil { 390 cfgFiles = opts.SharedConfigFiles 391 } else { 392 cfgFiles = []string{envCfg.SharedConfigFile, envCfg.SharedCredentialsFile} 393 if !envCfg.EnableSharedConfig { 394 // The shared config file (~/.aws/config) is only loaded if instructed 395 // to load via the envConfig.EnableSharedConfig (AWS_SDK_LOAD_CONFIG). 396 cfgFiles = cfgFiles[1:] 397 } 398 } 399 400 // Load additional config from file(s) 401 sharedCfg, err := loadSharedConfig(envCfg.Profile, cfgFiles, envCfg.EnableSharedConfig) 402 if err != nil { 403 if len(envCfg.Profile) == 0 && !envCfg.EnableSharedConfig && (envCfg.Creds.HasKeys() || userCfg.Credentials != nil) { 404 // Special case where the user has not explicitly specified an AWS_PROFILE, 405 // or session.Options.profile, shared config is not enabled, and the 406 // environment has credentials, allow the shared config file to fail to 407 // load since the user has already provided credentials, and nothing else 408 // is required to be read file. Github(aws/aws-sdk-go#2455) 409 } else if _, ok := err.(SharedConfigProfileNotExistsError); !ok { 410 return nil, err 411 } 412 } 413 414 if err := mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers, opts); err != nil { 415 return nil, err 416 } 417 418 s := &Session{ 419 Config: cfg, 420 Handlers: handlers, 421 } 422 423 initHandlers(s) 424 425 if csmCfg, err := loadCSMConfig(envCfg, cfgFiles); err != nil { 426 if l := s.Config.Logger; l != nil { 427 l.Log(fmt.Sprintf("ERROR: failed to load CSM configuration, %v", err)) 428 } 429 } else if csmCfg.Enabled { 430 err = enableCSM(&s.Handlers, csmCfg, s.Config.Logger) 431 if err != nil { 432 return nil, err 433 } 434 } 435 436 // Setup HTTP client with custom cert bundle if enabled 437 if opts.CustomCABundle != nil { 438 if err := loadCustomCABundle(s, opts.CustomCABundle); err != nil { 439 return nil, err 440 } 441 } 442 443 return s, nil 444} 445 446type csmConfig struct { 447 Enabled bool 448 Host string 449 Port string 450 ClientID string 451} 452 453var csmProfileName = "aws_csm" 454 455func loadCSMConfig(envCfg envConfig, cfgFiles []string) (csmConfig, error) { 456 if envCfg.CSMEnabled != nil { 457 if *envCfg.CSMEnabled { 458 return csmConfig{ 459 Enabled: true, 460 ClientID: envCfg.CSMClientID, 461 Host: envCfg.CSMHost, 462 Port: envCfg.CSMPort, 463 }, nil 464 } 465 return csmConfig{}, nil 466 } 467 468 sharedCfg, err := loadSharedConfig(csmProfileName, cfgFiles, false) 469 if err != nil { 470 if _, ok := err.(SharedConfigProfileNotExistsError); !ok { 471 return csmConfig{}, err 472 } 473 } 474 if sharedCfg.CSMEnabled != nil && *sharedCfg.CSMEnabled == true { 475 return csmConfig{ 476 Enabled: true, 477 ClientID: sharedCfg.CSMClientID, 478 Host: sharedCfg.CSMHost, 479 Port: sharedCfg.CSMPort, 480 }, nil 481 } 482 483 return csmConfig{}, nil 484} 485 486func loadCustomCABundle(s *Session, bundle io.Reader) error { 487 var t *http.Transport 488 switch v := s.Config.HTTPClient.Transport.(type) { 489 case *http.Transport: 490 t = v 491 default: 492 if s.Config.HTTPClient.Transport != nil { 493 return awserr.New("LoadCustomCABundleError", 494 "unable to load custom CA bundle, HTTPClient's transport unsupported type", nil) 495 } 496 } 497 if t == nil { 498 // Nil transport implies `http.DefaultTransport` should be used. Since 499 // the SDK cannot modify, nor copy the `DefaultTransport` specifying 500 // the values the next closest behavior. 501 t = getCABundleTransport() 502 } 503 504 p, err := loadCertPool(bundle) 505 if err != nil { 506 return err 507 } 508 if t.TLSClientConfig == nil { 509 t.TLSClientConfig = &tls.Config{} 510 } 511 t.TLSClientConfig.RootCAs = p 512 513 s.Config.HTTPClient.Transport = t 514 515 return nil 516} 517 518func loadCertPool(r io.Reader) (*x509.CertPool, error) { 519 b, err := ioutil.ReadAll(r) 520 if err != nil { 521 return nil, awserr.New("LoadCustomCABundleError", 522 "failed to read custom CA bundle PEM file", err) 523 } 524 525 p := x509.NewCertPool() 526 if !p.AppendCertsFromPEM(b) { 527 return nil, awserr.New("LoadCustomCABundleError", 528 "failed to load custom CA bundle PEM file", err) 529 } 530 531 return p, nil 532} 533 534func mergeConfigSrcs(cfg, userCfg *aws.Config, 535 envCfg envConfig, sharedCfg sharedConfig, 536 handlers request.Handlers, 537 sessOpts Options, 538) error { 539 540 // Region if not already set by user 541 if len(aws.StringValue(cfg.Region)) == 0 { 542 if len(envCfg.Region) > 0 { 543 cfg.WithRegion(envCfg.Region) 544 } else if envCfg.EnableSharedConfig && len(sharedCfg.Region) > 0 { 545 cfg.WithRegion(sharedCfg.Region) 546 } 547 } 548 549 if cfg.EnableEndpointDiscovery == nil { 550 if envCfg.EnableEndpointDiscovery != nil { 551 cfg.WithEndpointDiscovery(*envCfg.EnableEndpointDiscovery) 552 } else if envCfg.EnableSharedConfig && sharedCfg.EnableEndpointDiscovery != nil { 553 cfg.WithEndpointDiscovery(*sharedCfg.EnableEndpointDiscovery) 554 } 555 } 556 557 // Regional Endpoint flag for STS endpoint resolving 558 mergeSTSRegionalEndpointConfig(cfg, []endpoints.STSRegionalEndpoint{ 559 userCfg.STSRegionalEndpoint, 560 envCfg.STSRegionalEndpoint, 561 sharedCfg.STSRegionalEndpoint, 562 endpoints.LegacySTSEndpoint, 563 }) 564 565 // Regional Endpoint flag for S3 endpoint resolving 566 mergeS3UsEast1RegionalEndpointConfig(cfg, []endpoints.S3UsEast1RegionalEndpoint{ 567 userCfg.S3UsEast1RegionalEndpoint, 568 envCfg.S3UsEast1RegionalEndpoint, 569 sharedCfg.S3UsEast1RegionalEndpoint, 570 endpoints.LegacyS3UsEast1Endpoint, 571 }) 572 573 // Configure credentials if not already set by the user when creating the 574 // Session. 575 if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil { 576 creds, err := resolveCredentials(cfg, envCfg, sharedCfg, handlers, sessOpts) 577 if err != nil { 578 return err 579 } 580 cfg.Credentials = creds 581 } 582 583 cfg.S3UseARNRegion = userCfg.S3UseARNRegion 584 if cfg.S3UseARNRegion == nil { 585 cfg.S3UseARNRegion = &envCfg.S3UseARNRegion 586 } 587 if cfg.S3UseARNRegion == nil { 588 cfg.S3UseARNRegion = &sharedCfg.S3UseARNRegion 589 } 590 591 return nil 592} 593 594func mergeSTSRegionalEndpointConfig(cfg *aws.Config, values []endpoints.STSRegionalEndpoint) { 595 for _, v := range values { 596 if v != endpoints.UnsetSTSEndpoint { 597 cfg.STSRegionalEndpoint = v 598 break 599 } 600 } 601} 602 603func mergeS3UsEast1RegionalEndpointConfig(cfg *aws.Config, values []endpoints.S3UsEast1RegionalEndpoint) { 604 for _, v := range values { 605 if v != endpoints.UnsetS3UsEast1Endpoint { 606 cfg.S3UsEast1RegionalEndpoint = v 607 break 608 } 609 } 610} 611 612func initHandlers(s *Session) { 613 // Add the Validate parameter handler if it is not disabled. 614 s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler) 615 if !aws.BoolValue(s.Config.DisableParamValidation) { 616 s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler) 617 } 618} 619 620// Copy creates and returns a copy of the current Session, copying the config 621// and handlers. If any additional configs are provided they will be merged 622// on top of the Session's copied config. 623// 624// // Create a copy of the current Session, configured for the us-west-2 region. 625// sess.Copy(&aws.Config{Region: aws.String("us-west-2")}) 626func (s *Session) Copy(cfgs ...*aws.Config) *Session { 627 newSession := &Session{ 628 Config: s.Config.Copy(cfgs...), 629 Handlers: s.Handlers.Copy(), 630 } 631 632 initHandlers(newSession) 633 634 return newSession 635} 636 637// ClientConfig satisfies the client.ConfigProvider interface and is used to 638// configure the service client instances. Passing the Session to the service 639// client's constructor (New) will use this method to configure the client. 640func (s *Session) ClientConfig(service string, cfgs ...*aws.Config) client.Config { 641 s = s.Copy(cfgs...) 642 643 region := aws.StringValue(s.Config.Region) 644 resolved, err := s.resolveEndpoint(service, region, s.Config) 645 if err != nil { 646 s.Handlers.Validate.PushBack(func(r *request.Request) { 647 if len(r.ClientInfo.Endpoint) != 0 { 648 // Error occurred while resolving endpoint, but the request 649 // being invoked has had an endpoint specified after the client 650 // was created. 651 return 652 } 653 r.Error = err 654 }) 655 } 656 657 return client.Config{ 658 Config: s.Config, 659 Handlers: s.Handlers, 660 PartitionID: resolved.PartitionID, 661 Endpoint: resolved.URL, 662 SigningRegion: resolved.SigningRegion, 663 SigningNameDerived: resolved.SigningNameDerived, 664 SigningName: resolved.SigningName, 665 } 666} 667 668func (s *Session) resolveEndpoint(service, region string, cfg *aws.Config) (endpoints.ResolvedEndpoint, error) { 669 670 if ep := aws.StringValue(cfg.Endpoint); len(ep) != 0 { 671 return endpoints.ResolvedEndpoint{ 672 URL: endpoints.AddScheme(ep, aws.BoolValue(cfg.DisableSSL)), 673 SigningRegion: region, 674 }, nil 675 } 676 677 resolved, err := cfg.EndpointResolver.EndpointFor(service, region, 678 func(opt *endpoints.Options) { 679 opt.DisableSSL = aws.BoolValue(cfg.DisableSSL) 680 opt.UseDualStack = aws.BoolValue(cfg.UseDualStack) 681 // Support for STSRegionalEndpoint where the STSRegionalEndpoint is 682 // provided in envConfig or sharedConfig with envConfig getting 683 // precedence. 684 opt.STSRegionalEndpoint = cfg.STSRegionalEndpoint 685 686 // Support for S3UsEast1RegionalEndpoint where the S3UsEast1RegionalEndpoint is 687 // provided in envConfig or sharedConfig with envConfig getting 688 // precedence. 689 opt.S3UsEast1RegionalEndpoint = cfg.S3UsEast1RegionalEndpoint 690 691 // Support the condition where the service is modeled but its 692 // endpoint metadata is not available. 693 opt.ResolveUnknownService = true 694 }, 695 ) 696 if err != nil { 697 return endpoints.ResolvedEndpoint{}, err 698 } 699 700 return resolved, nil 701} 702 703// ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception 704// that the EndpointResolver will not be used to resolve the endpoint. The only 705// endpoint set must come from the aws.Config.Endpoint field. 706func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Config { 707 s = s.Copy(cfgs...) 708 709 var resolved endpoints.ResolvedEndpoint 710 if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 { 711 resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL)) 712 resolved.SigningRegion = aws.StringValue(s.Config.Region) 713 } 714 715 return client.Config{ 716 Config: s.Config, 717 Handlers: s.Handlers, 718 Endpoint: resolved.URL, 719 SigningRegion: resolved.SigningRegion, 720 SigningNameDerived: resolved.SigningNameDerived, 721 SigningName: resolved.SigningName, 722 } 723} 724 725// logDeprecatedNewSessionError function enables error handling for session 726func (s *Session) logDeprecatedNewSessionError(msg string, err error, cfgs []*aws.Config) { 727 // Session creation failed, need to report the error and prevent 728 // any requests from succeeding. 729 s.Config.MergeIn(cfgs...) 730 s.Config.Logger.Log("ERROR:", msg, "Error:", err) 731 s.Handlers.Validate.PushBack(func(r *request.Request) { 732 r.Error = err 733 }) 734} 735