vendor: update buildkit to 41c29fffe299

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi
2026-06-09 19:44:00 -07:00
parent 76703de985
commit 58a5a2cd60
211 changed files with 8218 additions and 23082 deletions
+4
View File
@@ -204,6 +204,10 @@ type Config struct {
// when constructing clients for specific services. Each callback function receives the service ID
// and the service's Options struct, allowing for dynamic configuration based on the service.
ServiceOptions []func(string, any)
// Controls whether the SDK restricts file permissions on credential
// cache files it creates.
RestrictFilePermissions RestrictFilePermissions
}
// NewConfig returns a new Config pointer that can be chained with builder
+1 -1
View File
@@ -3,4 +3,4 @@
package aws
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.41.7"
const goModuleVersion = "1.42.0"
+21
View File
@@ -0,0 +1,21 @@
package aws
// RestrictFilePermissions controls whether the SDK restricts file permissions
// on credential cache files it creates.
type RestrictFilePermissions string
const (
// RestrictFilePermissionsUnset indicates the setting has not been
// configured.
RestrictFilePermissionsUnset RestrictFilePermissions = ""
// RestrictFilePermissionsUserReadWrite sets file permissions to owner
// read/write only (0600) and directory permissions to owner only (0700)
// when creating new cache files and directories on Unix. This is the
// default behavior.
RestrictFilePermissionsUserReadWrite RestrictFilePermissions = "user_read_write"
// RestrictFilePermissionsUnrestricted does not set any file or directory
// permissions, relying on the system's default umask.
RestrictFilePermissionsUnrestricted RestrictFilePermissions = "unrestricted"
)
+76 -1
View File
@@ -4,6 +4,7 @@ import (
"math"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/internal/rand"
"github.com/aws/aws-sdk-go-v2/internal/timeconv"
)
@@ -12,9 +13,20 @@ import (
// number of attempts.
type ExponentialJitterBackoff struct {
maxBackoff time.Duration
// precomputed number of attempts needed to reach max backoff.
// precomputed number of attempts needed to reach max backoff (legacy mode).
maxBackoffAttempts float64
// Base delay for non-throttle errors (x in the formula t_i = b * min(x * r^i, MAX_BACKOFF)).
baseDelay time.Duration
// Throttle error checker. When set and the error is a throttle, the base
// delay is 1s regardless of the configured baseDelay.
throttle IsErrorThrottle
// When true, applies MAX_BACKOFF before jitter and uses throttle-aware
// base delay.
retries2026 bool
randFloat64 func() (float64, error)
}
@@ -25,13 +37,53 @@ func NewExponentialJitterBackoff(maxBackoff time.Duration) *ExponentialJitterBac
maxBackoff: maxBackoff,
maxBackoffAttempts: math.Log2(
float64(maxBackoff) / float64(time.Second)),
baseDelay: time.Second,
randFloat64: rand.CryptoRandFloat64,
}
}
// exponentialJitterBackoffOption is a functional option for ExponentialJitterBackoff.
type exponentialJitterBackoffOption func(*ExponentialJitterBackoff)
// withBaseDelay sets the base delay for non-throttle errors.
func withBaseDelay(d time.Duration) exponentialJitterBackoffOption {
return func(j *ExponentialJitterBackoff) {
j.baseDelay = d
}
}
// withThrottleCheck sets the throttle error checker used to determine if the
// backoff should use the throttle base delay (1s) instead of the configured
// base delay.
func withThrottleCheck(t IsErrorThrottle) exponentialJitterBackoffOption {
return func(j *ExponentialJitterBackoff) {
j.throttle = t
}
}
// newExponentialJitterBackoffWithOptions returns an ExponentialJitterBackoff
// with the given options applied.
func newExponentialJitterBackoffWithOptions(maxBackoff time.Duration, optFns ...exponentialJitterBackoffOption) *ExponentialJitterBackoff {
j := NewExponentialJitterBackoff(maxBackoff)
j.retries2026 = true
for _, fn := range optFns {
fn(j)
}
return j
}
// BackoffDelay returns the duration to wait before the next attempt should be
// made. Returns an error if unable get a duration.
func (j *ExponentialJitterBackoff) BackoffDelay(attempt int, err error) (time.Duration, error) {
if j.retries2026 {
return j.backoffDelay2026(attempt, err)
}
return j.backoffDelayLegacy(attempt, err)
}
// backoffDelayLegacy preserves the original backoff formula: b * 2^i, capped
// at maxBackoff.
func (j *ExponentialJitterBackoff) backoffDelayLegacy(attempt int, err error) (time.Duration, error) {
if attempt > int(j.maxBackoffAttempts) {
return j.maxBackoff, nil
}
@@ -47,3 +99,26 @@ func (j *ExponentialJitterBackoff) BackoffDelay(attempt int, err error) (time.Du
return timeconv.FloatSecondsDur(delaySeconds), nil
}
// backoffDelay2026 uses throttle-aware base delay and applies MAX_BACKOFF
// before jitter: t_i = b * min(x * 2^i, MAX_BACKOFF).
func (j *ExponentialJitterBackoff) backoffDelay2026(attempt int, err error) (time.Duration, error) {
x := j.baseDelay
if j.throttle != nil && j.throttle.IsErrorThrottle(err) == aws.TrueTernary {
x = time.Second
}
b, randErr := j.randFloat64()
if randErr != nil {
return 0, randErr
}
ri := math.Pow(2, float64(attempt))
delaySeconds := float64(x) / float64(time.Second) * ri
maxBackoffSeconds := float64(j.maxBackoff) / float64(time.Second)
if delaySeconds > maxBackoffSeconds {
delaySeconds = maxBackoffSeconds
}
return timeconv.FloatSecondsDur(b * delaySeconds), nil
}
+57 -4
View File
@@ -233,9 +233,11 @@ func (r *Attempt) handleAttempt(
"failed to release retry token after request error, %w", err)
}
// Release the attempt token based on the state of the attempt's error (if any).
if releaseError := releaseAttemptToken(err); releaseError != nil && err != nil {
return out, attemptResult, nopRelease, fmt.Errorf(
"failed to release initial token after request error, %w", err)
if !newRetries2026() || attemptNum == 1 {
if releaseError := releaseAttemptToken(err); releaseError != nil && err != nil {
return out, attemptResult, nopRelease, fmt.Errorf(
"failed to release initial token after request error, %w", err)
}
}
// If there was no error making the attempt, nothing further to do. There
// will be nothing to retry.
@@ -276,6 +278,13 @@ func (r *Attempt) handleAttempt(
// Get a retry token that will be released after the
releaseRetryToken, retryTokenErr := r.retryer.GetRetryToken(ctx, err)
if retryTokenErr != nil {
// Long-polling operations must still back off when quota is exceeded.
if newRetries2026() && internalcontext.GetIsLongPolling(ctx) {
if retryDelay, delayErr := r.retryer.RetryDelay(attemptNum-1, err); delayErr == nil {
retryDelay = adjustForRetryAfterHeader(retryDelay, err, logger, r.LogAttempts)
_ = sdk.SleepWithContext(ctx, retryDelay)
}
}
return out, attemptResult, nopRelease, errors.Join(err, retryTokenErr)
}
@@ -285,10 +294,17 @@ func (r *Attempt) handleAttempt(
// Get the retry delay before another attempt can be made, and sleep for
// that time. Potentially early exist if the sleep is canceled via the
// context.
retryDelay, reqErr := r.retryer.RetryDelay(attemptNum, err)
attempt := attemptNum
if newRetries2026() {
attempt = attemptNum - 1
}
retryDelay, reqErr := r.retryer.RetryDelay(attempt, err)
if reqErr != nil {
return out, attemptResult, releaseRetryToken, reqErr
}
if newRetries2026() {
retryDelay = adjustForRetryAfterHeader(retryDelay, err, logger, r.LogAttempts)
}
if reqErr = sdk.SleepWithContext(ctx, retryDelay); reqErr != nil {
err = &aws.RequestCanceledError{Err: reqErr}
return out, attemptResult, releaseRetryToken, err
@@ -423,6 +439,43 @@ func AddRetryMiddlewares(stack *smithymiddle.Stack, options AddRetryMiddlewaresO
return nil
}
// adjustForRetryAfterHeader checks for the x-amz-retry-after response header
// and clamps the backoff duration accordingly. The header value is an integer
// representing milliseconds. The result is clamped to [t_i, 5s + t_i] where
// t_i is the jittered exponential backoff duration. Invalid header values are
// ignored.
func adjustForRetryAfterHeader(backoff time.Duration, err error, logger logging.Logger, logAttempts bool) time.Duration {
var re *http.ResponseError
if !errors.As(err, &re) || re.Response == nil || re.Response.Response == nil {
return backoff
}
headerVal := re.Response.Header.Get("X-Amz-Retry-After")
if headerVal == "" {
return backoff
}
ms, parseErr := strconv.ParseInt(headerVal, 10, 64)
if parseErr != nil || ms < 0 {
if logAttempts {
logger.Logf(logging.Debug, "ignoring invalid x-amz-retry-after header value %q", headerVal)
}
return backoff
}
retryAfter := time.Duration(ms) * time.Millisecond
minDuration := backoff
maxDuration := 5*time.Second + backoff
if retryAfter < minDuration {
return minDuration
}
if retryAfter > maxDuration {
return maxDuration
}
return retryAfter
}
// Determines the value of exception.type for metrics purposes. We prefer an
// API-specific error code, otherwise it's just the Go type for the value.
func errorType(err error) string {
+13
View File
@@ -72,6 +72,19 @@ func (r *withMaxBackoffDelay) RetryDelay(attempt int, err error) (time.Duration,
return r.backoff.BackoffDelay(attempt, err)
}
// AddWithLongPolling returns a retryer that is marked as long-polling.
// Long-polling operations will back off even when the retry quota is
// exhausted.
func AddWithLongPolling(r aws.Retryer) aws.Retryer {
return &withLongPolling{RetryerV2: wrapAsRetryerV2(r)}
}
type withLongPolling struct {
aws.RetryerV2
}
func (w *withLongPolling) IsLongPolling() bool { return true }
type wrappedAsRetryerV2 struct {
aws.Retryer
}
+91 -17
View File
@@ -3,6 +3,7 @@ package retry
import (
"context"
"fmt"
"os"
"time"
"github.com/aws/aws-sdk-go-v2/aws/ratelimit"
@@ -35,8 +36,16 @@ const (
const (
DefaultRetryRateTokens uint = 500
DefaultRetryCost uint = 5
DefaultRetryTimeoutCost uint = 10
DefaultNoRetryIncrement uint = 1
// DefaultRetryTimeoutCost is the cost to deduct from the RateLimiter's
// token bucket per retry caused by timeout error.
//
// When AWS_NEW_RETRIES_2026 is set to "true", timeouts are no longer
// treated differently than other transient errors. The discounted cost
// is instead applied to throttling errors via DefaultThrottlingRetryCost.
DefaultRetryTimeoutCost uint = 10
DefaultThrottlingRetryCost uint = 5
)
// DefaultRetryableHTTPStatusCodes is the default set of HTTP status codes the SDK
@@ -121,6 +130,12 @@ type StandardOptions struct {
// It is safe to append to this list in NewStandard's functional options.
Timeouts []IsErrorTimeout
// Set of strategies to determine if the attempt failed due to a throttle
// error. Used to determine the retry token cost.
//
// It is safe to append to this list in NewStandard's functional options.
Throttles []IsErrorThrottle
// Provides the rate limiting strategy for rate limiting attempt retries
// across all attempts the retryer is being used with.
//
@@ -129,10 +144,14 @@ type StandardOptions struct {
// consume more tokens than what's available results in operation failure.
// The default implementation is parameterized as follows:
// - a capacity of 500 (DefaultRetryRateTokens)
// - a retry caused by a timeout costs 10 tokens (DefaultRetryCost)
// - a retry caused by other errors costs 5 tokens (DefaultRetryTimeoutCost)
// - a retry caused by a timeout costs 10 tokens (DefaultRetryTimeoutCost)
// - a retry caused by other errors costs 5 tokens (DefaultRetryCost)
// - an operation that succeeds on the 1st attempt adds 1 token (DefaultNoRetryIncrement)
//
// When AWS_NEW_RETRIES_2026 is set to "true", the costs change:
// - a retry costs 14 tokens
// - a retry caused by a throttling error costs 5 tokens (DefaultThrottlingRetryCost)
//
// You can disable rate limiting by setting this field to ratelimit.None.
RateLimiter RateLimiter
@@ -141,11 +160,23 @@ type StandardOptions struct {
// The cost to deduct from the RateLimiter's token bucket per retry caused
// by timeout error.
//
// When AWS_NEW_RETRIES_2026 is set to "true", this field is unused.
// Throttling errors use ThrottlingRetryCost instead.
RetryTimeoutCost uint
// The cost to deduct from the RateLimiter's token bucket per retry caused
// by a throttling error. Only used when AWS_NEW_RETRIES_2026 is "true".
ThrottlingRetryCost uint
// The cost to payback to the RateLimiter's token bucket for successful
// attempts.
NoRetryIncrement uint
// BaseDelay is the base backoff delay for non-throttle retryable errors.
// Throttling errors always use 1s. Defaults to 50ms if zero.
// Only used when AWS_NEW_RETRIES_2026 is "true"; ignored in legacy mode.
BaseDelay time.Duration
}
// RateLimiter provides the interface for limiting the rate of attempt retries
@@ -161,6 +192,7 @@ type RateLimiter interface {
type Standard struct {
options StandardOptions
throttle IsErrorThrottle
timeout IsErrorTimeout
retryable IsErrorRetryable
backoff BackoffDelayer
@@ -169,17 +201,7 @@ type Standard struct {
// NewStandard initializes a standard retry behavior with defaults that can be
// overridden via functional options.
func NewStandard(fnOpts ...func(*StandardOptions)) *Standard {
o := StandardOptions{
MaxAttempts: DefaultMaxAttempts,
MaxBackoff: DefaultMaxBackoff,
Retryables: append([]IsErrorRetryable{}, DefaultRetryables...),
Timeouts: append([]IsErrorTimeout{}, DefaultTimeouts...),
RateLimiter: ratelimit.NewTokenRateLimit(DefaultRetryRateTokens),
RetryCost: DefaultRetryCost,
RetryTimeoutCost: DefaultRetryTimeoutCost,
NoRetryIncrement: DefaultNoRetryIncrement,
}
o := standardDefaults()
for _, fn := range fnOpts {
fn(&o)
}
@@ -189,13 +211,25 @@ func NewStandard(fnOpts ...func(*StandardOptions)) *Standard {
backoff := o.Backoff
if backoff == nil {
backoff = NewExponentialJitterBackoff(o.MaxBackoff)
if newRetries2026() {
baseDelay := o.BaseDelay
if baseDelay == 0 {
baseDelay = 50 * time.Millisecond
}
backoff = newExponentialJitterBackoffWithOptions(o.MaxBackoff,
withBaseDelay(baseDelay),
withThrottleCheck(IsErrorThrottles(o.Throttles)),
)
} else {
backoff = NewExponentialJitterBackoff(o.MaxBackoff)
}
}
return &Standard{
options: o,
backoff: backoff,
retryable: IsErrorRetryables(o.Retryables),
throttle: IsErrorThrottles(o.Throttles),
timeout: IsErrorTimeouts(o.Timeouts),
}
}
@@ -244,8 +278,14 @@ func (s *Standard) noRetryIncrement() error {
func (s *Standard) GetRetryToken(ctx context.Context, opErr error) (func(error) error, error) {
cost := s.options.RetryCost
if s.timeout.IsErrorTimeout(opErr).Bool() {
cost = s.options.RetryTimeoutCost
if newRetries2026() {
if s.throttle.IsErrorThrottle(opErr).Bool() {
cost = s.options.ThrottlingRetryCost
}
} else {
if s.timeout.IsErrorTimeout(opErr).Bool() {
cost = s.options.RetryTimeoutCost
}
}
fn, err := s.options.RateLimiter.GetToken(ctx, cost)
@@ -267,3 +307,37 @@ func (f releaseToken) release(err error) error {
return f()
}
func newRetries2026() bool {
return os.Getenv("AWS_NEW_RETRIES_2026") == "true"
}
func standardDefaults() StandardOptions {
if newRetries2026() {
return StandardOptions{
MaxAttempts: DefaultMaxAttempts,
MaxBackoff: DefaultMaxBackoff,
Retryables: append([]IsErrorRetryable{}, DefaultRetryables...),
Timeouts: append([]IsErrorTimeout{}, DefaultTimeouts...),
Throttles: append([]IsErrorThrottle{}, DefaultThrottles...),
RateLimiter: ratelimit.NewTokenRateLimit(DefaultRetryRateTokens),
RetryCost: 14,
RetryTimeoutCost: DefaultRetryTimeoutCost,
ThrottlingRetryCost: DefaultThrottlingRetryCost,
NoRetryIncrement: DefaultNoRetryIncrement,
}
}
return StandardOptions{
MaxAttempts: DefaultMaxAttempts,
MaxBackoff: DefaultMaxBackoff,
Retryables: append([]IsErrorRetryable{}, DefaultRetryables...),
Timeouts: append([]IsErrorTimeout{}, DefaultTimeouts...),
Throttles: append([]IsErrorThrottle{}, DefaultThrottles...),
RateLimiter: ratelimit.NewTokenRateLimit(DefaultRetryRateTokens),
RetryCost: DefaultRetryCost,
RetryTimeoutCost: DefaultRetryTimeoutCost,
NoRetryIncrement: DefaultNoRetryIncrement,
}
}
+31
View File
@@ -1,3 +1,34 @@
# v1.32.24 (2026-06-08)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.32.23 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.32.22 (2026-06-03)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.32.21 (2026-06-02)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.32.20 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.32.19 (2026-05-28)
* **Bug Fix**: Adds support for AWS_RESTRICT_FILE_PERMISSIONS for env and in-code config.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.32.18 (2026-05-22)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.32.17 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
+2
View File
@@ -96,6 +96,8 @@ var defaultAWSConfigResolvers = []awsConfigResolver{
// Sets the ServiceOptions if present in LoadOptions
resolveServiceOptions,
resolveRestrictFilePermissions,
}
// A Config represents a generic configuration value or set of values. This type
+34
View File
@@ -87,6 +87,8 @@ const (
awsResponseChecksumValidation = "AWS_RESPONSE_CHECKSUM_VALIDATION"
awsAuthSchemePreferenceEnv = "AWS_AUTH_SCHEME_PREFERENCE"
awsRestrictFilePermissionsEnv = "AWS_RESTRICT_FILE_PERMISSIONS"
)
var (
@@ -309,6 +311,10 @@ type EnvConfig struct {
// Priority list of preferred auth scheme names (e.g. sigv4a).
AuthSchemePreference []string
// Controls whether the SDK restricts file permissions on credential
// cache files it creates.
RestrictFilePermissions aws.RestrictFilePermissions
}
// loadEnvConfig reads configuration values from the OS's environment variables.
@@ -422,6 +428,10 @@ func NewEnvConfig() (EnvConfig, error) {
cfg.AuthSchemePreference = toAuthSchemePreferenceList(os.Getenv(awsAuthSchemePreferenceEnv))
if err := setRestrictFilePermissionsFromEnvVal(&cfg.RestrictFilePermissions, []string{awsRestrictFilePermissionsEnv}); err != nil {
return cfg, err
}
return cfg, nil
}
@@ -930,3 +940,27 @@ func (c EnvConfig) getAuthSchemePreference() ([]string, bool) {
}
return nil, false
}
func (c EnvConfig) getRestrictFilePermissions(context.Context) (aws.RestrictFilePermissions, bool, error) {
return c.RestrictFilePermissions, len(c.RestrictFilePermissions) > 0, nil
}
func setRestrictFilePermissionsFromEnvVal(m *aws.RestrictFilePermissions, keys []string) error {
for _, k := range keys {
value := os.Getenv(k)
if len(value) == 0 {
continue
}
switch strings.ToLower(value) {
case "user_read_write":
*m = aws.RestrictFilePermissionsUserReadWrite
case "unrestricted":
*m = aws.RestrictFilePermissionsUnrestricted
default:
return fmt.Errorf("invalid value for environment variable, %s=%s, must be user_read_write/unrestricted", k, value)
}
break
}
return nil
}
+1 -1
View File
@@ -3,4 +3,4 @@
package config
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.32.17"
const goModuleVersion = "1.32.24"
+16
View File
@@ -240,6 +240,10 @@ type LoadOptions struct {
// when constructing clients for specific services. Each callback function receives the service ID
// and the service's Options struct, allowing for dynamic configuration based on the service.
ServiceOptions []func(string, any)
// Controls whether the SDK restricts file permissions on credential
// cache files it creates.
RestrictFilePermissions aws.RestrictFilePermissions
}
func (o LoadOptions) getDefaultsMode(ctx context.Context) (aws.DefaultsMode, bool, error) {
@@ -1353,3 +1357,15 @@ func (o LoadOptions) getAuthSchemePreference() ([]string, bool) {
}
return nil, false
}
func (o LoadOptions) getRestrictFilePermissions(context.Context) (aws.RestrictFilePermissions, bool, error) {
return o.RestrictFilePermissions, len(o.RestrictFilePermissions) > 0, nil
}
// WithRestrictFilePermissions sets the RestrictFilePermissions mode on config.
func WithRestrictFilePermissions(m aws.RestrictFilePermissions) LoadOptionsFunc {
return func(o *LoadOptions) error {
o.RestrictFilePermissions = m
return nil
}
}
+16
View File
@@ -784,3 +784,19 @@ func getServiceOptions(ctx context.Context, configs configs) (v []func(string, a
}
return v, found, err
}
type restrictFilePermissionsProvider interface {
getRestrictFilePermissions(context.Context) (aws.RestrictFilePermissions, bool, error)
}
func getRestrictFilePermissions(ctx context.Context, configs configs) (value aws.RestrictFilePermissions, found bool, err error) {
for _, cfg := range configs {
if p, ok := cfg.(restrictFilePermissionsProvider); ok {
value, found, err = p.getRestrictFilePermissions(ctx)
if err != nil || found {
break
}
}
}
return
}
+14
View File
@@ -442,3 +442,17 @@ func resolveServiceOptions(ctx context.Context, cfg *aws.Config, configs configs
cfg.ServiceOptions = serviceOptions
return nil
}
func resolveRestrictFilePermissions(ctx context.Context, cfg *aws.Config, configs configs) error {
m, found, err := getRestrictFilePermissions(ctx, configs)
if err != nil {
return err
}
if !found {
m = aws.RestrictFilePermissionsUserReadWrite
}
cfg.RestrictFilePermissions = m
return nil
}
+1
View File
@@ -640,6 +640,7 @@ func resolveLoginCredentials(ctx context.Context, cfg *aws.Config, sharedCfg *Sh
svc := signin.NewFromConfig(*cfg)
provider := logincreds.New(svc, tokenPath, func(o *logincreds.Options) {
o.CredentialSources = getCredentialSources(ctx)
o.RestrictPermissions = cfg.RestrictFilePermissions != aws.RestrictFilePermissionsUnrestricted
})
cfg.Credentials, err = wrapWithCredentialsCache(ctx, configs, provider)
if err != nil {
+31
View File
@@ -1,3 +1,34 @@
# v1.19.23 (2026-06-08)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.19.22 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.19.21 (2026-06-03)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.19.20 (2026-06-02)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.19.19 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.19.18 (2026-05-28)
* **Bug Fix**: Create new login cache files with 0600 on Unix platforms.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.19.17 (2026-05-22)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.19.16 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
+1 -1
View File
@@ -3,4 +3,4 @@
package credentials
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.19.16"
const goModuleVersion = "1.19.23"
+2 -2
View File
@@ -9,6 +9,6 @@ var openFile func(string) (io.ReadCloser, error) = func(name string) (io.ReadClo
return os.Open(name)
}
var createFile func(string) (io.WriteCloser, error) = func(name string) (io.WriteCloser, error) {
return os.Create(name)
var createFile func(string, os.FileMode) (io.WriteCloser, error) = func(name string, mode os.FileMode) (io.WriteCloser, error) {
return os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode)
}
+13 -1
View File
@@ -42,6 +42,10 @@ type Options struct {
// The path to the cached login token.
CachedTokenFilepath string
// Whether to restrict file permissions on newly-written cache files.
// When true, files are created with 0600 on Unix.
RestrictPermissions bool
// The chain of providers that was used to create this provider.
//
// These values are for reporting purposes and are not meant to be set up
@@ -145,7 +149,15 @@ func (p *Provider) saveToken(token *loginToken) error {
return err
}
f, err := createFile(p.options.CachedTokenFilepath)
mode := os.FileMode(0666) // matches that used by os.Create
if p.options.RestrictPermissions {
mode = 0600
}
// createFile DOES NOT re-create the file with new permissions if it
// already exists, so in that scenario any existing permissions are
// preserved
f, err := createFile(p.options.CachedTokenFilepath, mode)
if err != nil {
return err
}
+26
View File
@@ -1,3 +1,29 @@
# v1.18.29 (2026-06-08)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.18.28 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.18.27 (2026-06-03)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.18.26 (2026-06-02)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.18.25 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.18.24 (2026-05-28)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.18.23 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
@@ -3,4 +3,4 @@
package imds
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.18.23"
const goModuleVersion = "1.18.29"
@@ -0,0 +1,51 @@
package smithy
import (
"context"
"fmt"
"time"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
smithygo "github.com/aws/smithy-go"
"github.com/aws/smithy-go/auth"
"github.com/aws/smithy-go/eventstream"
smithyhttp "github.com/aws/smithy-go/transport/http"
)
var _ smithyhttp.EventStreamSigner = (*V4SignerAdapter)(nil)
// NewMessageSigner implements [smithyhttp.EventStreamSigner].
func (v *V4SignerAdapter) NewMessageSigner(ctx context.Context, r *smithyhttp.Request, identity auth.Identity, props smithygo.Properties) (eventstream.MessageSigner, error) {
ca, ok := identity.(*CredentialsAdapter)
if !ok {
return nil, fmt.Errorf("unexpected identity type: %T", identity)
}
name, ok := smithyhttp.GetSigV4SigningName(&props)
if !ok {
return nil, fmt.Errorf("sigv4 signing name is required")
}
region, ok := smithyhttp.GetSigV4SigningRegion(&props)
if !ok {
return nil, fmt.Errorf("sigv4 signing region is required")
}
seed, err := v4.GetSignedRequestSignature(r.Request)
if err != nil {
return nil, fmt.Errorf("get seed signature: %w", err)
}
return &streamSignerAdapter{
signer: v4.NewStreamSigner(ca.Credentials, name, region, seed),
}, nil
}
// streamSignerAdapter adapts v4.StreamSigner to eventstream.MessageSigner.
type streamSignerAdapter struct {
signer *v4.StreamSigner
}
func (s *streamSignerAdapter) SignMessage(headers, payload []byte, signingTime time.Time) ([]byte, error) {
return s.signer.GetSignature(context.Background(), headers, payload, signingTime)
}
@@ -1,3 +1,29 @@
# v1.4.29 (2026-06-08)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.28 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.27 (2026-06-03)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.26 (2026-06-02)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.25 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.24 (2026-05-28)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.23 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
@@ -3,4 +3,4 @@
package configsources
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.4.23"
const goModuleVersion = "1.4.29"
+13
View File
@@ -50,3 +50,16 @@ func GetAttemptSkewContext(ctx context.Context) time.Duration {
x, _ := middleware.GetStackValue(ctx, clockSkew{}).(time.Duration)
return x
}
type longPollingKey struct{}
// SetIsLongPolling marks the operation as long-polling on the context.
func SetIsLongPolling(ctx context.Context, v bool) context.Context {
return middleware.WithStackValue(ctx, longPollingKey{}, v)
}
// GetIsLongPolling returns whether the operation is long-polling.
func GetIsLongPolling(ctx context.Context) bool {
v, _ := middleware.GetStackValue(ctx, longPollingKey{}).(bool)
return v
}
+26
View File
@@ -1,3 +1,29 @@
# v2.7.29 (2026-06-08)
* **Dependency Update**: Updated to the latest SDK module versions
# v2.7.28 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
* **Dependency Update**: Updated to the latest SDK module versions
# v2.7.27 (2026-06-03)
* **Dependency Update**: Updated to the latest SDK module versions
# v2.7.26 (2026-06-02)
* **Dependency Update**: Updated to the latest SDK module versions
# v2.7.25 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
* **Dependency Update**: Updated to the latest SDK module versions
# v2.7.24 (2026-05-28)
* **Dependency Update**: Updated to the latest SDK module versions
# v2.7.23 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
@@ -3,4 +3,4 @@
package endpoints
// goModuleVersion is the tagged release for this module
const goModuleVersion = "2.7.23"
const goModuleVersion = "2.7.29"
+26
View File
@@ -1,3 +1,29 @@
# v1.4.30 (2026-06-08)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.29 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.28 (2026-06-03)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.27 (2026-06-02)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.26 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.25 (2026-05-28)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.4.24 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
+1 -1
View File
@@ -3,4 +3,4 @@
package v4a
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.4.24"
const goModuleVersion = "1.4.30"
@@ -1,3 +1,15 @@
# v1.13.12 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
# v1.13.11 (2026-06-03)
* No change notes available for this release.
# v1.13.10 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
# v1.13.9 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
@@ -3,4 +3,4 @@
package acceptencoding
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.13.9"
const goModuleVersion = "1.13.12"
@@ -1,3 +1,29 @@
# v1.13.29 (2026-06-08)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.13.28 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.13.27 (2026-06-03)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.13.26 (2026-06-02)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.13.25 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.13.24 (2026-05-28)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.13.23 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
@@ -3,4 +3,4 @@
package presignedurl
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.13.23"
const goModuleVersion = "1.13.29"
+27
View File
@@ -1,3 +1,30 @@
# v1.1.5 (2026-06-08)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.1.4 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.1.3 (2026-06-03)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.1.2 (2026-06-02)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.1.1 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.1.0 (2026-05-28)
* **Feature**: Adding new BDD representation of endpoint ruleset
* **Dependency Update**: Updated to the latest SDK module versions
# v1.0.11 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
+11 -1
View File
@@ -190,7 +190,7 @@ func (m *resolveAuthSchemeMiddleware) selectScheme(options []*smithyauth.Option)
}
for _, scheme := range m.options.AuthSchemes {
if scheme.SchemeID() != option.SchemeID {
if !matchSchemeID(scheme.SchemeID(), option.SchemeID) {
continue
}
@@ -203,6 +203,16 @@ func (m *resolveAuthSchemeMiddleware) selectScheme(options []*smithyauth.Option)
return nil, false
}
func matchSchemeID(registered, option string) bool {
if registered == option {
return true
}
if i := strings.LastIndex(registered, "#"); i != -1 {
return registered[i+1:] == option
}
return false
}
func sortAuthOptions(options []*smithyauth.Option, preferred []string) []*smithyauth.Option {
byPriority := make([]*smithyauth.Option, 0, len(options))
for _, prefName := range preferred {
+188 -207
View File
@@ -14,6 +14,7 @@ import (
internalendpoints "github.com/aws/aws-sdk-go-v2/service/signin/internal/endpoints"
smithyauth "github.com/aws/smithy-go/auth"
smithyendpoints "github.com/aws/smithy-go/endpoints"
"github.com/aws/smithy-go/endpoints/private/bdd"
"github.com/aws/smithy-go/endpoints/private/rulesfn"
"github.com/aws/smithy-go/middleware"
"github.com/aws/smithy-go/ptr"
@@ -229,6 +230,8 @@ func bindRegion(region string) (*string, error) {
return aws.String(endpoints.MapFIPSRegion(region)), nil
}
var _ = rulesfn.StringSlice(nil)
// EndpointParameters provides the parameters that influence how endpoints are
// resolved.
type EndpointParameters struct {
@@ -294,21 +297,193 @@ func (p EndpointParameters) WithDefaults() EndpointParameters {
return p
}
type stringSlice []string
const bddRoot int32 = 2
func (s stringSlice) Get(i int) *string {
if i < 0 || i >= len(s) {
return nil
var bddNodes = [48]int32{
-1, 1, -1, 0, 15, 3, 1, 4, 100000014, 2, 5, 100000014, 3, 11, 6, 4, 10, 7, 7, 100000004, 8, 8, 100000005, 9, 9, 100000006, 100000013, 5, 100000011, 100000012, 4, 13, 12, 6, 100000009, 100000010, 5, 14, 100000008, 6, 100000007, 100000008, 3, 100000001, 16, 4, 100000002, 100000003}
type conditionContext struct {
PartitionResult *awsrulesfn.PartitionConfig
}
func evalCondition(idx int, params *EndpointParameters, c *conditionContext) bool {
switch idx {
case 0:
return params.Endpoint != nil
case 1:
return params.Region != nil
case 2:
if v := awsrulesfn.GetPartition(*params.Region); v != nil {
c.PartitionResult = v
return true
}
return false
case 3:
return *params.UseFIPS == true
case 4:
return *params.UseDualStack == true
case 5:
return c.PartitionResult.SupportsDualStack == true
case 6:
return c.PartitionResult.SupportsFIPS == true
case 7:
return c.PartitionResult.Name == "aws"
case 8:
return c.PartitionResult.Name == "aws-cn"
case 9:
return c.PartitionResult.Name == "aws-us-gov"
}
return false
}
v := s[i]
return &v
func resolveResult(idx int32, params *EndpointParameters, c *conditionContext) (smithyendpoints.Endpoint, error) {
switch idx {
case 0:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint resolution failed: no matching rule")
case 1:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
case 2:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
case 3:
uriString := *params.Endpoint
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 4:
uriString := func() string {
var out strings.Builder
out.WriteString("https://")
out.WriteString(*params.Region)
out.WriteString(".signin.aws.amazon.com")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 5:
uriString := func() string {
var out strings.Builder
out.WriteString("https://")
out.WriteString(*params.Region)
out.WriteString(".signin.amazonaws.cn")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 6:
uriString := func() string {
var out strings.Builder
out.WriteString("https://")
out.WriteString(*params.Region)
out.WriteString(".signin.amazonaws-us-gov.com")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 7:
uriString := func() string {
var out strings.Builder
out.WriteString("https://signin-fips.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 8:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
case 9:
uriString := func() string {
var out strings.Builder
out.WriteString("https://signin-fips.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 10:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
case 11:
uriString := func() string {
var out strings.Builder
out.WriteString("https://signin.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 12:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
case 13:
uriString := func() string {
var out strings.Builder
out.WriteString("https://signin.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 14:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
}
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, invalid result index: %d", idx)
}
// EndpointResolverV2 provides the interface for resolving service endpoints.
type EndpointResolverV2 interface {
// ResolveEndpoint attempts to resolve the endpoint with the provided options,
// returning the endpoint if found. Otherwise an error is returned.
ResolveEndpoint(ctx context.Context, params EndpointParameters) (
smithyendpoints.Endpoint, error,
)
@@ -332,206 +507,12 @@ func (r *resolver) ResolveEndpoint(
if err = params.ValidateRequired(); err != nil {
return endpoint, fmt.Errorf("endpoint parameters are not valid, %w", err)
}
_UseDualStack := *params.UseDualStack
_ = _UseDualStack
_UseFIPS := *params.UseFIPS
_ = _UseFIPS
if exprVal := params.Endpoint; exprVal != nil {
_Endpoint := *exprVal
_ = _Endpoint
if _UseFIPS == true {
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
}
if _UseDualStack == true {
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
}
uriString := _Endpoint
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
if exprVal := params.Region; exprVal != nil {
_Region := *exprVal
_ = _Region
if exprVal := awsrulesfn.GetPartition(_Region); exprVal != nil {
_PartitionResult := *exprVal
_ = _PartitionResult
if _PartitionResult.Name == "aws" {
if _UseFIPS == false {
if _UseDualStack == false {
uriString := func() string {
var out strings.Builder
out.WriteString("https://")
out.WriteString(_Region)
out.WriteString(".signin.aws.amazon.com")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
}
}
if _PartitionResult.Name == "aws-cn" {
if _UseFIPS == false {
if _UseDualStack == false {
uriString := func() string {
var out strings.Builder
out.WriteString("https://")
out.WriteString(_Region)
out.WriteString(".signin.amazonaws.cn")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
}
}
if _PartitionResult.Name == "aws-us-gov" {
if _UseFIPS == false {
if _UseDualStack == false {
uriString := func() string {
var out strings.Builder
out.WriteString("https://")
out.WriteString(_Region)
out.WriteString(".signin.amazonaws-us-gov.com")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
}
}
if _UseFIPS == true {
if _UseDualStack == true {
if true == _PartitionResult.SupportsFIPS {
if true == _PartitionResult.SupportsDualStack {
uriString := func() string {
var out strings.Builder
out.WriteString("https://signin-fips.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
}
}
if _UseFIPS == true {
if _UseDualStack == false {
if _PartitionResult.SupportsFIPS == true {
uriString := func() string {
var out strings.Builder
out.WriteString("https://signin-fips.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
}
}
if _UseFIPS == false {
if _UseDualStack == true {
if true == _PartitionResult.SupportsDualStack {
uriString := func() string {
var out strings.Builder
out.WriteString("https://signin.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
}
}
uriString := func() string {
var out strings.Builder
out.WriteString("https://signin.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("Endpoint resolution failed. Invalid operation or environment input.")
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
c := &conditionContext{}
ref := bdd.Evaluate(bddNodes[:], bddRoot, func(idx int) bool {
return evalCondition(idx, &params, c)
})
return resolveResult(ref, &params, c)
}
type endpointParamsBinder interface {
+1 -1
View File
@@ -3,4 +3,4 @@
package signin
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.0.11"
const goModuleVersion = "1.1.5"
+27
View File
@@ -1,3 +1,30 @@
# v1.31.3 (2026-06-08)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.31.2 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.31.1 (2026-06-03)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.31.0 (2026-06-02)
* **Feature**: Adding new BDD representation of endpoint ruleset
* **Dependency Update**: Updated to the latest SDK module versions
# v1.30.19 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.30.18 (2026-05-28)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.30.17 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
+11 -1
View File
@@ -208,7 +208,7 @@ func (m *resolveAuthSchemeMiddleware) selectScheme(options []*smithyauth.Option)
}
for _, scheme := range m.options.AuthSchemes {
if scheme.SchemeID() != option.SchemeID {
if !matchSchemeID(scheme.SchemeID(), option.SchemeID) {
continue
}
@@ -221,6 +221,16 @@ func (m *resolveAuthSchemeMiddleware) selectScheme(options []*smithyauth.Option)
return nil, false
}
func matchSchemeID(registered, option string) bool {
if registered == option {
return true
}
if i := strings.LastIndex(registered, "#"); i != -1 {
return registered[i+1:] == option
}
return false
}
func sortAuthOptions(options []*smithyauth.Option, preferred []string) []*smithyauth.Option {
byPriority := make([]*smithyauth.Option, 0, len(options))
for _, prefName := range preferred {
+1 -2
View File
@@ -16,7 +16,6 @@ import (
"github.com/aws/smithy-go/tracing"
smithyhttp "github.com/aws/smithy-go/transport/http"
"io"
"io/ioutil"
"strings"
)
@@ -551,7 +550,7 @@ func (m *awsRestjson1_deserializeOpLogout) HandleDeserialize(ctx context.Context
output := &LogoutOutput{}
out.Result = output
if _, err = io.Copy(ioutil.Discard, response.Body); err != nil {
if _, err = io.Copy(io.Discard, response.Body); err != nil {
return out, metadata, &smithy.DeserializationError{
Err: fmt.Errorf("failed to discard response body, %w", err),
}
+152 -153
View File
@@ -14,6 +14,7 @@ import (
internalendpoints "github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints"
smithyauth "github.com/aws/smithy-go/auth"
smithyendpoints "github.com/aws/smithy-go/endpoints"
"github.com/aws/smithy-go/endpoints/private/bdd"
"github.com/aws/smithy-go/endpoints/private/rulesfn"
"github.com/aws/smithy-go/middleware"
"github.com/aws/smithy-go/ptr"
@@ -229,6 +230,8 @@ func bindRegion(region string) (*string, error) {
return aws.String(endpoints.MapFIPSRegion(region)), nil
}
var _ = rulesfn.StringSlice(nil)
// EndpointParameters provides the parameters that influence how endpoints are
// resolved.
type EndpointParameters struct {
@@ -294,21 +297,157 @@ func (p EndpointParameters) WithDefaults() EndpointParameters {
return p
}
type stringSlice []string
const bddRoot int32 = 2
func (s stringSlice) Get(i int) *string {
if i < 0 || i >= len(s) {
return nil
var bddNodes = [42]int32{
-1, 1, -1, 0, 13, 3, 1, 4, 100000012, 2, 5, 100000012, 3, 8, 6, 4, 7, 100000011, 5, 100000009, 100000010, 4, 11, 9, 6, 10, 100000008, 7, 100000006, 100000007, 5, 12, 100000005, 6, 100000004, 100000005, 3, 100000001, 14, 4, 100000002, 100000003}
type conditionContext struct {
PartitionResult *awsrulesfn.PartitionConfig
}
func evalCondition(idx int, params *EndpointParameters, c *conditionContext) bool {
switch idx {
case 0:
return params.Endpoint != nil
case 1:
return params.Region != nil
case 2:
if v := awsrulesfn.GetPartition(*params.Region); v != nil {
c.PartitionResult = v
return true
}
return false
case 3:
return *params.UseFIPS == true
case 4:
return *params.UseDualStack == true
case 5:
return c.PartitionResult.SupportsDualStack == true
case 6:
return c.PartitionResult.SupportsFIPS == true
case 7:
return c.PartitionResult.Name == "aws-us-gov"
}
return false
}
v := s[i]
return &v
func resolveResult(idx int32, params *EndpointParameters, c *conditionContext) (smithyendpoints.Endpoint, error) {
switch idx {
case 0:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint resolution failed: no matching rule")
case 1:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
case 2:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
case 3:
uriString := *params.Endpoint
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 4:
uriString := func() string {
var out strings.Builder
out.WriteString("https://portal.sso-fips.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 5:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
case 6:
uriString := func() string {
var out strings.Builder
out.WriteString("https://portal.sso.")
out.WriteString(*params.Region)
out.WriteString(".amazonaws.com")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 7:
uriString := func() string {
var out strings.Builder
out.WriteString("https://portal.sso-fips.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 8:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
case 9:
uriString := func() string {
var out strings.Builder
out.WriteString("https://portal.sso.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 10:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
case 11:
uriString := func() string {
var out strings.Builder
out.WriteString("https://portal.sso.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 12:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
}
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, invalid result index: %d", idx)
}
// EndpointResolverV2 provides the interface for resolving service endpoints.
type EndpointResolverV2 interface {
// ResolveEndpoint attempts to resolve the endpoint with the provided options,
// returning the endpoint if found. Otherwise an error is returned.
ResolveEndpoint(ctx context.Context, params EndpointParameters) (
smithyendpoints.Endpoint, error,
)
@@ -332,152 +471,12 @@ func (r *resolver) ResolveEndpoint(
if err = params.ValidateRequired(); err != nil {
return endpoint, fmt.Errorf("endpoint parameters are not valid, %w", err)
}
_UseDualStack := *params.UseDualStack
_ = _UseDualStack
_UseFIPS := *params.UseFIPS
_ = _UseFIPS
if exprVal := params.Endpoint; exprVal != nil {
_Endpoint := *exprVal
_ = _Endpoint
if _UseFIPS == true {
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
}
if _UseDualStack == true {
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
}
uriString := _Endpoint
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
if exprVal := params.Region; exprVal != nil {
_Region := *exprVal
_ = _Region
if exprVal := awsrulesfn.GetPartition(_Region); exprVal != nil {
_PartitionResult := *exprVal
_ = _PartitionResult
if _UseFIPS == true {
if _UseDualStack == true {
if true == _PartitionResult.SupportsFIPS {
if true == _PartitionResult.SupportsDualStack {
uriString := func() string {
var out strings.Builder
out.WriteString("https://portal.sso-fips.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
}
}
if _UseFIPS == true {
if _PartitionResult.SupportsFIPS == true {
if _PartitionResult.Name == "aws-us-gov" {
uriString := func() string {
var out strings.Builder
out.WriteString("https://portal.sso.")
out.WriteString(_Region)
out.WriteString(".amazonaws.com")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
uriString := func() string {
var out strings.Builder
out.WriteString("https://portal.sso-fips.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
}
if _UseDualStack == true {
if true == _PartitionResult.SupportsDualStack {
uriString := func() string {
var out strings.Builder
out.WriteString("https://portal.sso.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
}
uriString := func() string {
var out strings.Builder
out.WriteString("https://portal.sso.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("Endpoint resolution failed. Invalid operation or environment input.")
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
c := &conditionContext{}
ref := bdd.Evaluate(bddNodes[:], bddRoot, func(idx int) bool {
return evalCondition(idx, &params, c)
})
return resolveResult(ref, &params, c)
}
type endpointParamsBinder interface {
+1 -1
View File
@@ -3,4 +3,4 @@
package sso
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.30.17"
const goModuleVersion = "1.31.3"
+30
View File
@@ -1,3 +1,33 @@
# v1.36.6 (2026-06-08)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.36.5 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.36.4 (2026-06-03)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.36.3 (2026-06-02)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.36.2 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.36.1 (2026-05-28)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.36.0 (2026-05-22)
* **Feature**: Adding new BDD representation of endpoint ruleset
# v1.35.21 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
+11 -1
View File
@@ -202,7 +202,7 @@ func (m *resolveAuthSchemeMiddleware) selectScheme(options []*smithyauth.Option)
}
for _, scheme := range m.options.AuthSchemes {
if scheme.SchemeID() != option.SchemeID {
if !matchSchemeID(scheme.SchemeID(), option.SchemeID) {
continue
}
@@ -215,6 +215,16 @@ func (m *resolveAuthSchemeMiddleware) selectScheme(options []*smithyauth.Option)
return nil, false
}
func matchSchemeID(registered, option string) bool {
if registered == option {
return true
}
if i := strings.LastIndex(registered, "#"); i != -1 {
return registered[i+1:] == option
}
return false
}
func sortAuthOptions(options []*smithyauth.Option, preferred []string) []*smithyauth.Option {
byPriority := make([]*smithyauth.Option, 0, len(options))
for _, prefName := range preferred {
+152 -153
View File
@@ -14,6 +14,7 @@ import (
internalendpoints "github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints"
smithyauth "github.com/aws/smithy-go/auth"
smithyendpoints "github.com/aws/smithy-go/endpoints"
"github.com/aws/smithy-go/endpoints/private/bdd"
"github.com/aws/smithy-go/endpoints/private/rulesfn"
"github.com/aws/smithy-go/middleware"
"github.com/aws/smithy-go/ptr"
@@ -229,6 +230,8 @@ func bindRegion(region string) (*string, error) {
return aws.String(endpoints.MapFIPSRegion(region)), nil
}
var _ = rulesfn.StringSlice(nil)
// EndpointParameters provides the parameters that influence how endpoints are
// resolved.
type EndpointParameters struct {
@@ -294,21 +297,157 @@ func (p EndpointParameters) WithDefaults() EndpointParameters {
return p
}
type stringSlice []string
const bddRoot int32 = 2
func (s stringSlice) Get(i int) *string {
if i < 0 || i >= len(s) {
return nil
var bddNodes = [42]int32{
-1, 1, -1, 0, 13, 3, 1, 4, 100000012, 2, 5, 100000012, 3, 8, 6, 4, 7, 100000011, 5, 100000009, 100000010, 4, 11, 9, 6, 10, 100000008, 7, 100000006, 100000007, 5, 12, 100000005, 6, 100000004, 100000005, 3, 100000001, 14, 4, 100000002, 100000003}
type conditionContext struct {
PartitionResult *awsrulesfn.PartitionConfig
}
func evalCondition(idx int, params *EndpointParameters, c *conditionContext) bool {
switch idx {
case 0:
return params.Endpoint != nil
case 1:
return params.Region != nil
case 2:
if v := awsrulesfn.GetPartition(*params.Region); v != nil {
c.PartitionResult = v
return true
}
return false
case 3:
return *params.UseFIPS == true
case 4:
return *params.UseDualStack == true
case 5:
return c.PartitionResult.SupportsDualStack == true
case 6:
return c.PartitionResult.SupportsFIPS == true
case 7:
return c.PartitionResult.Name == "aws-us-gov"
}
return false
}
v := s[i]
return &v
func resolveResult(idx int32, params *EndpointParameters, c *conditionContext) (smithyendpoints.Endpoint, error) {
switch idx {
case 0:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint resolution failed: no matching rule")
case 1:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
case 2:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
case 3:
uriString := *params.Endpoint
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 4:
uriString := func() string {
var out strings.Builder
out.WriteString("https://oidc-fips.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 5:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
case 6:
uriString := func() string {
var out strings.Builder
out.WriteString("https://oidc.")
out.WriteString(*params.Region)
out.WriteString(".amazonaws.com")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 7:
uriString := func() string {
var out strings.Builder
out.WriteString("https://oidc-fips.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 8:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
case 9:
uriString := func() string {
var out strings.Builder
out.WriteString("https://oidc.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 10:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
case 11:
uriString := func() string {
var out strings.Builder
out.WriteString("https://oidc.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 12:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
}
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, invalid result index: %d", idx)
}
// EndpointResolverV2 provides the interface for resolving service endpoints.
type EndpointResolverV2 interface {
// ResolveEndpoint attempts to resolve the endpoint with the provided options,
// returning the endpoint if found. Otherwise an error is returned.
ResolveEndpoint(ctx context.Context, params EndpointParameters) (
smithyendpoints.Endpoint, error,
)
@@ -332,152 +471,12 @@ func (r *resolver) ResolveEndpoint(
if err = params.ValidateRequired(); err != nil {
return endpoint, fmt.Errorf("endpoint parameters are not valid, %w", err)
}
_UseDualStack := *params.UseDualStack
_ = _UseDualStack
_UseFIPS := *params.UseFIPS
_ = _UseFIPS
if exprVal := params.Endpoint; exprVal != nil {
_Endpoint := *exprVal
_ = _Endpoint
if _UseFIPS == true {
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
}
if _UseDualStack == true {
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
}
uriString := _Endpoint
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
if exprVal := params.Region; exprVal != nil {
_Region := *exprVal
_ = _Region
if exprVal := awsrulesfn.GetPartition(_Region); exprVal != nil {
_PartitionResult := *exprVal
_ = _PartitionResult
if _UseFIPS == true {
if _UseDualStack == true {
if true == _PartitionResult.SupportsFIPS {
if true == _PartitionResult.SupportsDualStack {
uriString := func() string {
var out strings.Builder
out.WriteString("https://oidc-fips.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
}
}
if _UseFIPS == true {
if _PartitionResult.SupportsFIPS == true {
if _PartitionResult.Name == "aws-us-gov" {
uriString := func() string {
var out strings.Builder
out.WriteString("https://oidc.")
out.WriteString(_Region)
out.WriteString(".amazonaws.com")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
uriString := func() string {
var out strings.Builder
out.WriteString("https://oidc-fips.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
}
if _UseDualStack == true {
if true == _PartitionResult.SupportsDualStack {
uriString := func() string {
var out strings.Builder
out.WriteString("https://oidc.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
}
uriString := func() string {
var out strings.Builder
out.WriteString("https://oidc.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("Endpoint resolution failed. Invalid operation or environment input.")
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
c := &conditionContext{}
ref := bdd.Evaluate(bddNodes[:], bddRoot, func(idx int) bool {
return evalCondition(idx, &params, c)
})
return resolveResult(ref, &params, c)
}
type endpointParamsBinder interface {
+1 -1
View File
@@ -3,4 +3,4 @@
package ssooidc
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.35.21"
const goModuleVersion = "1.36.6"
+27
View File
@@ -1,3 +1,30 @@
# v1.43.3 (2026-06-08)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.43.2 (2026-06-04)
* **Dependency Update**: Update to smithy-go v1.27.1 to fix several union-related deserialization bugs in schema-serde-enabled services.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.43.1 (2026-06-03)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.43.0 (2026-06-02)
* **Feature**: Adding new BDD representation of endpoint ruleset
* **Dependency Update**: Updated to the latest SDK module versions
# v1.42.3 (2026-05-29)
* **Dependency Update**: Update to smithy-go v1.26.0.
* **Dependency Update**: Updated to the latest SDK module versions
# v1.42.2 (2026-05-28)
* **Dependency Update**: Updated to the latest SDK module versions
# v1.42.1 (2026-04-29)
* **Dependency Update**: Update to smithy-go v1.25.1.
+6
View File
@@ -224,6 +224,8 @@ func New(options Options, optFns ...func(*Options)) *Client {
ignoreAnonymousAuth(&options)
finalizeSTSRetryableErrors(&options)
wrapWithAnonymousAuth(&options)
resolveAuthSchemes(&options)
@@ -836,6 +838,10 @@ func addCredentialSource(stack *middleware.Stack, options Options) error {
return stack.Build.Insert(&mw, "UserAgent", middleware.Before)
}
func finalizeSTSRetryableErrors(o *Options) {
o.Retryer = retry.AddWithErrorCodes(o.Retryer, "IDPCommunicationError")
}
func resolveTracerProvider(options *Options) {
if options.TracerProvider == nil {
options.TracerProvider = &tracing.NopTracerProvider{}
+11 -1
View File
@@ -206,7 +206,7 @@ func (m *resolveAuthSchemeMiddleware) selectScheme(options []*smithyauth.Option)
}
for _, scheme := range m.options.AuthSchemes {
if scheme.SchemeID() != option.SchemeID {
if !matchSchemeID(scheme.SchemeID(), option.SchemeID) {
continue
}
@@ -219,6 +219,16 @@ func (m *resolveAuthSchemeMiddleware) selectScheme(options []*smithyauth.Option)
return nil, false
}
func matchSchemeID(registered, option string) bool {
if registered == option {
return true
}
if i := strings.LastIndex(registered, "#"); i != -1 {
return registered[i+1:] == option
}
return false
}
func sortAuthOptions(options []*smithyauth.Option, preferred []string) []*smithyauth.Option {
byPriority := make([]*smithyauth.Option, 0, len(options))
for _, prefName := range preferred {
+247 -716
View File
@@ -15,6 +15,7 @@ import (
smithy "github.com/aws/smithy-go"
smithyauth "github.com/aws/smithy-go/auth"
smithyendpoints "github.com/aws/smithy-go/endpoints"
"github.com/aws/smithy-go/endpoints/private/bdd"
"github.com/aws/smithy-go/endpoints/private/rulesfn"
"github.com/aws/smithy-go/middleware"
"github.com/aws/smithy-go/ptr"
@@ -230,6 +231,8 @@ func bindRegion(region string) (*string, error) {
return aws.String(endpoints.MapFIPSRegion(region)), nil
}
var _ = rulesfn.StringSlice(nil)
// EndpointParameters provides the parameters that influence how endpoints are
// resolved.
type EndpointParameters struct {
@@ -312,21 +315,252 @@ func (p EndpointParameters) WithDefaults() EndpointParameters {
return p
}
type stringSlice []string
const bddRoot int32 = 2
func (s stringSlice) Get(i int) *string {
if i < 0 || i >= len(s) {
return nil
var bddNodes = [93]int32{
-1, 1, -1, 0, 30, 3, 1, 4, 100000014, 2, 5, 100000014, 3, 25, 6, 4, 24, 7, 5, 100000001, 8, 6, 9, 100000013, 7, 100000001, 10, 10, 100000001, 11, 11, 100000001, 12, 12, 100000001, 13, 13, 100000001, 14, 14, 100000001, 15, 15, 100000001, 16, 16, 100000001, 17, 17, 100000001, 18, 18, 100000001, 19, 19, 100000001, 20, 20, 100000001, 21, 21, 100000001, 22, 22, 100000001, 23, 23, 100000001, 100000002, 8, 100000011, 100000012, 4, 28, 26, 9, 27, 100000010, 24, 100000008, 100000009, 8, 29, 100000007, 9, 100000006, 100000007, 3, 100000003, 31, 4, 100000004, 100000005}
type conditionContext struct {
PartitionResult *awsrulesfn.PartitionConfig
}
func evalCondition(idx int, params *EndpointParameters, c *conditionContext) bool {
switch idx {
case 0:
return params.Endpoint != nil
case 1:
return params.Region != nil
case 2:
if v := awsrulesfn.GetPartition(*params.Region); v != nil {
c.PartitionResult = v
return true
}
return false
case 3:
return *params.UseFIPS == true
case 4:
return *params.UseDualStack == true
case 5:
return *params.Region == "aws-global"
case 6:
return *params.UseGlobalEndpoint == true
case 7:
return *params.Region == "eu-central-1"
case 8:
return c.PartitionResult.SupportsDualStack == true
case 9:
return c.PartitionResult.SupportsFIPS == true
case 10:
return *params.Region == "ap-south-1"
case 11:
return *params.Region == "eu-north-1"
case 12:
return *params.Region == "eu-west-1"
case 13:
return *params.Region == "eu-west-2"
case 14:
return *params.Region == "eu-west-3"
case 15:
return *params.Region == "sa-east-1"
case 16:
return *params.Region == "us-east-1"
case 17:
return *params.Region == "us-east-2"
case 18:
return *params.Region == "us-west-2"
case 19:
return *params.Region == "us-west-1"
case 20:
return *params.Region == "ca-central-1"
case 21:
return *params.Region == "ap-southeast-1"
case 22:
return *params.Region == "ap-northeast-1"
case 23:
return *params.Region == "ap-southeast-2"
case 24:
return c.PartitionResult.Name == "aws-us-gov"
}
return false
}
v := s[i]
return &v
func resolveResult(idx int32, params *EndpointParameters, c *conditionContext) (smithyendpoints.Endpoint, error) {
switch idx {
case 0:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint resolution failed: no matching rule")
case 1:
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
case 2:
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, *params.Region)
return sp
}(),
},
})
return out
}(),
}, nil
case 3:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
case 4:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
case 5:
uriString := *params.Endpoint
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 6:
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts-fips.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 7:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
case 8:
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts.")
out.WriteString(*params.Region)
out.WriteString(".amazonaws.com")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 9:
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts-fips.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 10:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
case 11:
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 12:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
case 13:
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts.")
out.WriteString(*params.Region)
out.WriteString(".")
out.WriteString(c.PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return smithyendpoints.Endpoint{}, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
case 14:
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
}
return smithyendpoints.Endpoint{}, fmt.Errorf("endpoint rule error, invalid result index: %d", idx)
}
// EndpointResolverV2 provides the interface for resolving service endpoints.
type EndpointResolverV2 interface {
// ResolveEndpoint attempts to resolve the endpoint with the provided options,
// returning the endpoint if found. Otherwise an error is returned.
ResolveEndpoint(ctx context.Context, params EndpointParameters) (
smithyendpoints.Endpoint, error,
)
@@ -350,715 +584,12 @@ func (r *resolver) ResolveEndpoint(
if err = params.ValidateRequired(); err != nil {
return endpoint, fmt.Errorf("endpoint parameters are not valid, %w", err)
}
_UseDualStack := *params.UseDualStack
_ = _UseDualStack
_UseFIPS := *params.UseFIPS
_ = _UseFIPS
_UseGlobalEndpoint := *params.UseGlobalEndpoint
_ = _UseGlobalEndpoint
if _UseGlobalEndpoint == true {
if !(params.Endpoint != nil) {
if exprVal := params.Region; exprVal != nil {
_Region := *exprVal
_ = _Region
if exprVal := awsrulesfn.GetPartition(_Region); exprVal != nil {
_PartitionResult := *exprVal
_ = _PartitionResult
if _UseFIPS == false {
if _UseDualStack == false {
if _Region == "ap-northeast-1" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "ap-south-1" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "ap-southeast-1" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "ap-southeast-2" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "aws-global" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "ca-central-1" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "eu-central-1" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "eu-north-1" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "eu-west-1" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "eu-west-2" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "eu-west-3" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "sa-east-1" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "us-east-1" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "us-east-2" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "us-west-1" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
if _Region == "us-west-2" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, _Region)
return sp
}(),
},
})
return out
}(),
}, nil
}
}
}
}
}
}
if exprVal := params.Endpoint; exprVal != nil {
_Endpoint := *exprVal
_ = _Endpoint
if _UseFIPS == true {
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
}
if _UseDualStack == true {
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
}
uriString := _Endpoint
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
if exprVal := params.Region; exprVal != nil {
_Region := *exprVal
_ = _Region
if exprVal := awsrulesfn.GetPartition(_Region); exprVal != nil {
_PartitionResult := *exprVal
_ = _PartitionResult
if _UseFIPS == true {
if _UseDualStack == true {
if true == _PartitionResult.SupportsFIPS {
if true == _PartitionResult.SupportsDualStack {
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts-fips.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
}
}
if _UseFIPS == true {
if _PartitionResult.SupportsFIPS == true {
if _PartitionResult.Name == "aws-us-gov" {
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts.")
out.WriteString(_Region)
out.WriteString(".amazonaws.com")
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts-fips.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
}
if _UseDualStack == true {
if true == _PartitionResult.SupportsDualStack {
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DualStackDnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
}
if _Region == "aws-global" {
uriString := "https://sts.amazonaws.com"
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
Properties: func() smithy.Properties {
var out smithy.Properties
smithyauth.SetAuthOptions(&out, []*smithyauth.Option{
{
SchemeID: "aws.auth#sigv4",
SignerProperties: func() smithy.Properties {
var sp smithy.Properties
smithyhttp.SetSigV4SigningName(&sp, "sts")
smithyhttp.SetSigV4ASigningName(&sp, "sts")
smithyhttp.SetSigV4SigningRegion(&sp, "us-east-1")
return sp
}(),
},
})
return out
}(),
}, nil
}
uriString := func() string {
var out strings.Builder
out.WriteString("https://sts.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DnsSuffix)
return out.String()
}()
uri, err := url.Parse(uriString)
if err != nil {
return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}
return smithyendpoints.Endpoint{
URI: *uri,
Headers: http.Header{},
}, nil
}
return endpoint, fmt.Errorf("Endpoint resolution failed. Invalid operation or environment input.")
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
c := &conditionContext{}
ref := bdd.Evaluate(bddNodes[:], bddRoot, func(idx int) bool {
return evalCondition(idx, &params, c)
})
return resolveResult(ref, &params, c)
}
type endpointParamsBinder interface {
+1 -1
View File
@@ -3,4 +3,4 @@
package sts
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.42.1"
const goModuleVersion = "1.43.3"
+41
View File
@@ -1,3 +1,44 @@
# Release (2026-06-05)
## General Highlights
* **Dependency Update**: Updated to the latest SDK module versions
## Module Highlights
* `github.com/aws/smithy-go`: v1.27.2
* **Bug Fix**: Fix incorrect serialization of unions in CBOR-based protocols.
# Release (2026-06-04)
## General Highlights
* **Dependency Update**: Updated to the latest SDK module versions
## Module Highlights
* `github.com/aws/smithy-go`: v1.27.1
* **Bug Fix**: Fixed a deserialization failure in all protocols when encountering a union with explicit null members.
* **Bug Fix**: Fixed a panic when deserializing nested unions in JSON- and CBOR-based protocols.
# Release (2026-06-02)
## General Highlights
* **Dependency Update**: Updated to the latest SDK module versions
## Module Highlights
* `github.com/aws/smithy-go`: v1.27.0
* **Feature**: Add APIs for schema-based serialization.
* **Feature**: Add support for all current AWS and Smithy protocols.
* **Bug Fix**: Enforce max nesting depth of 128 on CBOR payloads.
* `github.com/aws/smithy-go/aws-http-auth`: [v1.2.0](aws-http-auth/CHANGELOG.md#v120-2026-06-02)
* **Feature**: Add event stream signer.
# Release (2026-05-27)
## General Highlights
* **Dependency Update**: Updated to the latest SDK module versions
## Module Highlights
* `github.com/aws/smithy-go`: v1.26.0
* **Feature**: Add StringSlice to endpoint rulesfn.
# Release (2026-04-23)
## General Highlights
+21 -14
View File
@@ -8,22 +8,19 @@ The smithy-go runtime requires a minimum version of Go 1.24.
**WARNING: All interfaces are subject to change.**
## :no_entry_sign: DO NOT use the code generators in this repository
## :warning: Client codegen is unstable
**The code generators in this repository do not generate working clients at
this time.**
The client code generator in this repository powers the aws-sdk-go-v2.
Arbitrary client generation, while technically possible, is in an early stage
of development:
In order to generate a usable smithy client you must provide a [protocol definition](https://github.com/aws/smithy-go/blob/main/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/ProtocolGenerator.java),
such as [AWS restJson1](https://smithy.io/2.0/aws/protocols/aws-restjson1-protocol.html),
in order to generate transport mechanisms and serialization/deserialization
code ("serde") accordingly.
* Generated clients are missing certain features that were originally
implemented SDK-side (e.g. retries)
* There may be bugs
* The public APIs of generated clients may be unstable
The code generator does not currently support any protocols out of the box.
Support for all [AWS protocols](https://smithy.io/2.0/aws/protocols/index.html)
exists in [aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2). We are
tracking the movement of those out of the SDK into smithy-go in
[#458](https://github.com/aws/smithy-go/issues/458), but there's currently no
timeline for doing so.
If you are interested in using the client code generators, we encourage you to
experiment and share any feedback with us in an issue.
## Plugins
@@ -55,9 +52,19 @@ methods and types. The up-to-date list of top-level properties enabled for
### Supported protocols
The protocol a client uses is configured by the `Protocol` field on a client's
`Options`. The SDK will configure a default based on the protocol traits
applied to the modeled service.
| Protocol | Notes |
|----------|-------|
| [`smithy.protocols#rpcv2Cbor`](https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html) | Event streaming not yet implemented. |
| [`smithy.protocols#rpcv2Cbor`](https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html) | |
| [`aws.protocols#restJson1`](https://smithy.io/2.0/aws/protocols/aws-restjson1-protocol.html) | |
| [`aws.protocols#restXml`](https://smithy.io/2.0/aws/protocols/aws-restxml-protocol.html) | |
| [`aws.protocols#awsJson1_0`](https://smithy.io/2.0/aws/protocols/aws-json-1_0-protocol.html) | |
| [`aws.protocols#awsJson1_1`](https://smithy.io/2.0/aws/protocols/aws-json-1_1-protocol.html) | |
| [`aws.protocols#awsQuery`](https://smithy.io/2.0/aws/protocols/aws-query-protocol.html) | |
| [`aws.protocols#ec2Query`](https://smithy.io/2.0/aws/protocols/aws-ec2-query-protocol.html) | |
### Example
+105 -19
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"math/big"
"strconv"
"time"
)
// Marshaler is an interface for a type that marshals a document to its protocol-specific byte representation and
@@ -15,26 +16,26 @@ import (
// When defining struct types. the `document` struct tag can be used to control how the value will be
// marshaled into the resulting protocol document.
//
// // Field is ignored
// Field int `document:"-"`
// // Field is ignored
// Field int `document:"-"`
//
// // Field object of key "myName"
// Field int `document:"myName"`
// // Field object of key "myName"
// Field int `document:"myName"`
//
// // Field object key of key "myName", and
// // Field is omitted if the field is a zero value for the type.
// Field int `document:"myName,omitempty"`
// // Field object key of key "myName", and
// // Field is omitted if the field is a zero value for the type.
// Field int `document:"myName,omitempty"`
//
// // Field object key of "Field", and
// // Field is omitted if the field is a zero value for the type.
// Field int `document:",omitempty"`
// // Field object key of "Field", and
// // Field is omitted if the field is a zero value for the type.
// Field int `document:",omitempty"`
//
// All struct fields, including anonymous fields, are marshaled unless the
// any of the following conditions are meet.
//
// - the field is not exported
// - document field tag is "-"
// - document field tag specifies "omitempty", and is a zero value.
// - the field is not exported
// - document field tag is "-"
// - document field tag specifies "omitempty", and is a zero value.
//
// Pointer and interface values are encoded as the value pointed to or
// contained in the interface. A nil value encodes as a null
@@ -50,6 +51,13 @@ import (
//
// Marshal cannot represent cyclic data structures and will not handle them.
// Passing cyclic structures to Marshal will result in an infinite recursion.
//
// Marshaler is not used in schema-serde based services (which are currently
// being rolled out) since having an implementation of Marshaler locks a
// document into support for a specific serial format. Existing implementations
// of Marshaler will continue to encode to JSON as that is effectively the only
// serial format supported for Document prior to the introduction of
// schema-serde. In schema-serde services it is replaced by [Value].
type Marshaler interface {
MarshalSmithyDocument() ([]byte, error)
}
@@ -63,18 +71,94 @@ type Marshaler interface {
//
// Both generic interface{} and concrete types are valid unmarshal destination types. When unmarshaling a document
// into an empty interface the Unmarshaler will store one of these values:
// bool, for boolean values
// document.Number, for arbitrary-precision numbers (int64, float64, big.Int, big.Float)
// string, for string values
// []interface{}, for array values
// map[string]interface{}, for objects
// nil, for null values
//
// bool, for boolean values
// document.Number, for arbitrary-precision numbers (int64, float64, big.Int, big.Float)
// string, for string values
// []interface{}, for array values
// map[string]interface{}, for objects
// nil, for null values
//
// When unmarshaling, any error that occurs will halt the unmarshal and return the error.
type Unmarshaler interface {
UnmarshalSmithyDocument(v interface{}) error
}
// Value is a sealed type representing a Smithy document value. It covers the
// full Smithy data model including blob and timestamp.
//
// The following types implement Value:
// - [Null]
// - [Boolean]
// - [Number]
// - [String]
// - [Blob]
// - [Timestamp]
// - [List]
// - [Map]
// - [Structure]
// - [Opaque]
type Value interface {
isValue()
}
// Null is a document null value.
type Null struct{}
func (Null) isValue() {}
// Boolean is a document boolean value.
type Boolean bool
func (Boolean) isValue() {}
// String is a document string value.
type String string
func (String) isValue() {}
// Blob is a document blob value.
type Blob []byte
func (Blob) isValue() {}
// Timestamp is a document timestamp value.
type Timestamp time.Time
func (Timestamp) isValue() {}
// List is a document list value.
type List []Value
func (List) isValue() {}
// Map is a document map value with string keys.
type Map map[string]Value
func (Map) isValue() {}
// Structure is a document structure value with an optional discriminator
// identifying the shape it represents.
type Structure struct {
// Discriminator is the absolute shape ID (e.g.
// "com.example#MyShape") of the concrete type this structure
// represents. It may be empty if the type is unknown.
Discriminator string
// Members maps member names to their document values.
Members map[string]Value
}
func (Structure) isValue() {}
// Opaque wraps an arbitrary Go value for backward compatibility with the
// legacy reflection-based document serialization path.
type Opaque struct {
Value any
}
func (Opaque) isValue() {}
type noSerde interface {
noSmithyDocumentSerde()
}
@@ -96,6 +180,8 @@ func IsNoSerde(x interface{}) bool {
// Number is an arbitrary precision numerical value
type Number string
func (Number) isValue() {}
// Int64 returns the number as a string.
func (n Number) String() string {
return string(n)
+35
View File
@@ -0,0 +1,35 @@
package bdd
const resultOffset int32 = 100_000_000
const intsPerNode = 3
// Evaluate traverses a compiled BDD node array and returns the result index.
// nodes is a flat array of [condIdx, hi, lo] triples (1-indexed).
// root is the root node reference. evalCond returns true/false for condition index.
func Evaluate(nodes []int32, root int32, evalCond func(int) bool) int32 {
ref := root
for {
if ref >= resultOffset {
return ref - resultOffset
}
if ref == 1 || ref == -1 {
return 0 // NoMatchRule
}
complement := ref < 0
nodeIdx := ref
if complement {
nodeIdx = -ref
}
base := (nodeIdx - 1) * intsPerNode
condIdx := nodes[base]
hi := nodes[base+1]
lo := nodes[base+2]
if complement != evalCond(int(condIdx)) {
ref = hi
} else {
ref = lo
}
}
}
@@ -0,0 +1,18 @@
package rulesfn
// StringSlice is a string slice with a negative-index-aware Get method for use
// in endpoint rule evaluation.
type StringSlice []string
// Get returns a pointer to the string at index i, or nil if the index is out
// of bounds. Negative indices count from the end of the slice.
func (s StringSlice) Get(i int) *string {
if i < 0 {
i = len(s) + i
}
if i < 0 || i >= len(s) {
return nil
}
v := s[i]
return &v
}
+24
View File
@@ -0,0 +1,24 @@
package eventstream
// EventStream headers with specific meaning to async API functionality.
const (
ChunkSignatureHeader = `:chunk-signature` // chunk signature for message
DateHeader = `:date` // Date header for signature
ContentTypeHeader = ":content-type" // message payload content-type
// Message header and values
MessageTypeHeader = `:message-type` // Identifies type of message.
EventMessageType = `event`
ErrorMessageType = `error`
ExceptionMessageType = `exception`
// Message Events
EventTypeHeader = `:event-type` // Identifies message event type e.g. "Stats".
// Message Error
ErrorCodeHeader = `:error-code`
ErrorMessageHeader = `:error-message`
// Message Exception
ExceptionTypeHeader = `:exception-type`
)
+144
View File
@@ -0,0 +1,144 @@
package eventstream
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"strconv"
)
type decodedMessage struct {
rawMessage
Headers decodedHeaders `json:"headers"`
}
type jsonMessage struct {
Length json.Number `json:"total_length"`
HeadersLen json.Number `json:"headers_length"`
PreludeCRC json.Number `json:"prelude_crc"`
Headers decodedHeaders `json:"headers"`
Payload []byte `json:"payload"`
CRC json.Number `json:"message_crc"`
}
func (d *decodedMessage) UnmarshalJSON(b []byte) (err error) {
var jsonMsg jsonMessage
if err = json.Unmarshal(b, &jsonMsg); err != nil {
return err
}
d.Length, err = numAsUint32(jsonMsg.Length)
if err != nil {
return err
}
d.HeadersLen, err = numAsUint32(jsonMsg.HeadersLen)
if err != nil {
return err
}
d.PreludeCRC, err = numAsUint32(jsonMsg.PreludeCRC)
if err != nil {
return err
}
d.Headers = jsonMsg.Headers
d.Payload = jsonMsg.Payload
d.CRC, err = numAsUint32(jsonMsg.CRC)
if err != nil {
return err
}
return nil
}
func (d *decodedMessage) MarshalJSON() ([]byte, error) {
jsonMsg := jsonMessage{
Length: json.Number(strconv.Itoa(int(d.Length))),
HeadersLen: json.Number(strconv.Itoa(int(d.HeadersLen))),
PreludeCRC: json.Number(strconv.Itoa(int(d.PreludeCRC))),
Headers: d.Headers,
Payload: d.Payload,
CRC: json.Number(strconv.Itoa(int(d.CRC))),
}
return json.Marshal(jsonMsg)
}
func numAsUint32(n json.Number) (uint32, error) {
v, err := n.Int64()
if err != nil {
return 0, fmt.Errorf("failed to get int64 json number, %v", err)
}
return uint32(v), nil
}
func (d decodedMessage) Message() Message {
return Message{
Headers: Headers(d.Headers),
Payload: d.Payload,
}
}
type decodedHeaders Headers
func (hs *decodedHeaders) UnmarshalJSON(b []byte) error {
var jsonHeaders []struct {
Name string `json:"name"`
Type valueType `json:"type"`
Value any `json:"value"`
}
decoder := json.NewDecoder(bytes.NewReader(b))
decoder.UseNumber()
if err := decoder.Decode(&jsonHeaders); err != nil {
return err
}
var headers Headers
for _, h := range jsonHeaders {
value, err := valueFromType(h.Type, h.Value)
if err != nil {
return err
}
headers.Set(h.Name, value)
}
*hs = decodedHeaders(headers)
return nil
}
func valueFromType(typ valueType, val any) (Value, error) {
switch typ {
case trueValueType:
return BoolValue(true), nil
case falseValueType:
return BoolValue(false), nil
case int8ValueType:
v, err := val.(json.Number).Int64()
return Int8Value(int8(v)), err
case int16ValueType:
v, err := val.(json.Number).Int64()
return Int16Value(int16(v)), err
case int32ValueType:
v, err := val.(json.Number).Int64()
return Int32Value(int32(v)), err
case int64ValueType:
v, err := val.(json.Number).Int64()
return Int64Value(v), err
case bytesValueType:
v, err := base64.StdEncoding.DecodeString(val.(string))
return BytesValue(v), err
case stringValueType:
v, err := base64.StdEncoding.DecodeString(val.(string))
return StringValue(string(v)), err
case timestampValueType:
v, err := val.(json.Number).Int64()
return TimestampValue(timeFromEpochMilli(v)), err
case uuidValueType:
v, err := base64.StdEncoding.DecodeString(val.(string))
var tv UUIDValue
copy(tv[:], v)
return tv, err
default:
panic(fmt.Sprintf("unknown type, %s, %T", typ.String(), val))
}
}
+218
View File
@@ -0,0 +1,218 @@
package eventstream
import (
"bytes"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/aws/smithy-go/logging"
"hash"
"hash/crc32"
"io"
)
// DecoderOptions is the Decoder configuration options.
type DecoderOptions struct {
Logger logging.Logger
LogMessages bool
}
// Decoder provides decoding of an Event Stream messages.
type Decoder struct {
options DecoderOptions
}
// NewDecoder initializes and returns a Decoder for decoding event
// stream messages from the reader provided.
func NewDecoder(optFns ...func(*DecoderOptions)) *Decoder {
options := DecoderOptions{}
for _, fn := range optFns {
fn(&options)
}
return &Decoder{
options: options,
}
}
// Decode attempts to decode a single message from the event stream reader.
// Will return the event stream message, or error if decodeMessage fails to read
// the message from the stream.
//
// payloadBuf is a byte slice that will be used in the returned Message.Payload. Callers
// must ensure that the Message.Payload from a previous decode has been consumed before passing in the same underlying
// payloadBuf byte slice.
func (d *Decoder) Decode(reader io.Reader, payloadBuf []byte) (m Message, err error) {
if d.options.Logger != nil && d.options.LogMessages {
debugMsgBuf := bytes.NewBuffer(nil)
reader = io.TeeReader(reader, debugMsgBuf)
defer func() {
logMessageDecode(d.options.Logger, debugMsgBuf, m, err)
}()
}
m, err = decodeMessage(reader, payloadBuf)
return m, err
}
// decodeMessage attempts to decode a single message from the event stream reader.
// Will return the event stream message, or error if decodeMessage fails to read
// the message from the reader.
func decodeMessage(reader io.Reader, payloadBuf []byte) (m Message, err error) {
crc := crc32.New(crc32IEEETable)
hashReader := io.TeeReader(reader, crc)
prelude, err := decodePrelude(hashReader, crc)
if err != nil {
return Message{}, err
}
if prelude.HeadersLen > 0 {
lr := io.LimitReader(hashReader, int64(prelude.HeadersLen))
m.Headers, err = decodeHeaders(lr)
if err != nil {
return Message{}, err
}
}
if payloadLen := prelude.PayloadLen(); payloadLen > 0 {
buf, err := decodePayload(payloadBuf, io.LimitReader(hashReader, int64(payloadLen)))
if err != nil {
return Message{}, err
}
m.Payload = buf
}
msgCRC := crc.Sum32()
if err := validateCRC(reader, msgCRC); err != nil {
return Message{}, err
}
return m, nil
}
func logMessageDecode(logger logging.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) {
w := bytes.NewBuffer(nil)
defer func() { logger.Logf(logging.Debug, w.String()) }()
fmt.Fprintf(w, "Raw message:\n%s\n",
hex.Dump(msgBuf.Bytes()))
if decodeErr != nil {
fmt.Fprintf(w, "decodeMessage error: %v\n", decodeErr)
return
}
rawMsg, err := msg.rawMessage()
if err != nil {
fmt.Fprintf(w, "failed to create raw message, %v\n", err)
return
}
decodedMsg := decodedMessage{
rawMessage: rawMsg,
Headers: decodedHeaders(msg.Headers),
}
fmt.Fprintf(w, "Decoded message:\n")
encoder := json.NewEncoder(w)
if err := encoder.Encode(decodedMsg); err != nil {
fmt.Fprintf(w, "failed to generate decoded message, %v\n", err)
}
}
func decodePrelude(r io.Reader, crc hash.Hash32) (messagePrelude, error) {
var p messagePrelude
var err error
p.Length, err = decodeUint32(r)
if err != nil {
return messagePrelude{}, err
}
p.HeadersLen, err = decodeUint32(r)
if err != nil {
return messagePrelude{}, err
}
if err := p.ValidateLens(); err != nil {
return messagePrelude{}, err
}
preludeCRC := crc.Sum32()
if err := validateCRC(r, preludeCRC); err != nil {
return messagePrelude{}, err
}
p.PreludeCRC = preludeCRC
return p, nil
}
func decodePayload(buf []byte, r io.Reader) ([]byte, error) {
w := bytes.NewBuffer(buf[0:0])
_, err := io.Copy(w, r)
return w.Bytes(), err
}
func decodeUint8(r io.Reader) (uint8, error) {
type byteReader interface {
ReadByte() (byte, error)
}
if br, ok := r.(byteReader); ok {
v, err := br.ReadByte()
return v, err
}
var b [1]byte
_, err := io.ReadFull(r, b[:])
return b[0], err
}
func decodeUint16(r io.Reader) (uint16, error) {
var b [2]byte
bs := b[:]
_, err := io.ReadFull(r, bs)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint16(bs), nil
}
func decodeUint32(r io.Reader) (uint32, error) {
var b [4]byte
bs := b[:]
_, err := io.ReadFull(r, bs)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint32(bs), nil
}
func decodeUint64(r io.Reader) (uint64, error) {
var b [8]byte
bs := b[:]
_, err := io.ReadFull(r, bs)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint64(bs), nil
}
func validateCRC(r io.Reader, expect uint32) error {
msgCRC, err := decodeUint32(r)
if err != nil {
return err
}
if msgCRC != expect {
return ChecksumError{}
}
return nil
}
+294
View File
@@ -0,0 +1,294 @@
package eventstream
import (
"fmt"
"math/big"
"time"
"github.com/aws/smithy-go"
"github.com/aws/smithy-go/document"
"github.com/aws/smithy-go/traits"
)
// ShapeDeserializer wraps a [smithy.ShapeDeserializer] to handle event stream
// message binding traits.
type ShapeDeserializer struct {
Message *Message
inner smithy.ShapeDeserializer
depth int
schema *smithy.Schema
bindings []*smithy.Schema
bindIdx int
inBindings bool
inBody bool
hasPayload bool
hasBody bool
}
var _ smithy.ShapeDeserializer = (*ShapeDeserializer)(nil)
// NewShapeDeserializer returns a deserializer for a Message.
func NewShapeDeserializer(msg *Message, inner smithy.ShapeDeserializer) *ShapeDeserializer {
return &ShapeDeserializer{
Message: msg,
inner: inner,
}
}
func (d *ShapeDeserializer) ReadStruct(s *smithy.Schema) error {
d.depth++
if d.depth > 1 {
return d.inner.ReadStruct(s)
}
d.schema = s
for _, m := range s.Members() {
if _, ok := smithy.SchemaTrait[*traits.EventPayload](m); ok {
d.hasPayload = true
}
if isEventBound(m) {
d.bindings = append(d.bindings, m)
} else {
d.hasBody = true
}
}
return nil
}
func (d *ShapeDeserializer) ReadStructMember() (*smithy.Schema, error) {
if d.depth > 1 {
ms, err := d.inner.ReadStructMember()
if ms == nil {
d.depth--
}
return ms, err
}
// like httpbinding, throw back the bound stuff first before we drop into
// the body
for d.bindIdx < len(d.bindings) {
m := d.bindings[d.bindIdx]
d.bindIdx++
if isEventHeader(m) && d.Message.Headers.Get(m.MemberName()) == nil {
continue
}
d.inBindings = true
return m, nil
}
d.inBindings = false
if d.hasPayload {
d.depth--
return nil, nil
}
if !d.hasBody {
d.depth--
return nil, nil
}
if !d.inBody {
d.inBody = true
if err := d.inner.ReadStruct(d.schema); err != nil {
return nil, err
}
}
ms, err := d.inner.ReadStructMember()
if ms == nil {
d.depth--
}
return ms, err
}
func (d *ShapeDeserializer) ReadString(s *smithy.Schema, v *string) error {
if d.inBindings {
if isEventHeader(s) {
hv := d.Message.Headers.Get(s.MemberName())
if hv == nil {
return nil
}
sv, ok := hv.(StringValue)
if !ok {
return fmt.Errorf("event header %q: expected string, got %T", s.MemberName(), hv)
}
*v = string(sv)
return nil
}
if isEventPayload(s) {
*v = string(d.Message.Payload)
return nil
}
}
return d.inner.ReadString(s, v)
}
func (d *ShapeDeserializer) ReadBool(s *smithy.Schema, v *bool) error {
if d.inBindings && isEventHeader(s) {
hv := d.Message.Headers.Get(s.MemberName())
if hv == nil {
return nil
}
bv, ok := hv.(BoolValue)
if !ok {
return fmt.Errorf("event header %q: expected bool, got %T", s.MemberName(), hv)
}
*v = bool(bv)
return nil
}
return d.inner.ReadBool(s, v)
}
func (d *ShapeDeserializer) readHeaderInt64(name string) (int64, bool, error) {
hv := d.Message.Headers.Get(name)
if hv == nil {
return 0, false, nil
}
switch v := hv.(type) {
case Int8Value:
return int64(v), true, nil
case Int16Value:
return int64(v), true, nil
case Int32Value:
return int64(v), true, nil
case Int64Value:
return int64(v), true, nil
default:
return 0, false, fmt.Errorf("event header %q: expected integer, got %T", name, hv)
}
}
type intn interface {
int8 | int16 | int32 | int64
}
func readEventHeaderInt[T intn](d *ShapeDeserializer, s *smithy.Schema, v *T) error {
n, ok, err := d.readHeaderInt64(s.MemberName())
if err != nil || !ok {
return err
}
*v = T(n)
return nil
}
func (d *ShapeDeserializer) ReadInt8(s *smithy.Schema, v *int8) error {
if d.inBindings && isEventHeader(s) {
return readEventHeaderInt(d, s, v)
}
return d.inner.ReadInt8(s, v)
}
func (d *ShapeDeserializer) ReadInt16(s *smithy.Schema, v *int16) error {
if d.inBindings && isEventHeader(s) {
return readEventHeaderInt(d, s, v)
}
return d.inner.ReadInt16(s, v)
}
func (d *ShapeDeserializer) ReadInt32(s *smithy.Schema, v *int32) error {
if d.inBindings && isEventHeader(s) {
return readEventHeaderInt(d, s, v)
}
return d.inner.ReadInt32(s, v)
}
func (d *ShapeDeserializer) ReadInt64(s *smithy.Schema, v *int64) error {
if d.inBindings && isEventHeader(s) {
return readEventHeaderInt(d, s, v)
}
return d.inner.ReadInt64(s, v)
}
func (d *ShapeDeserializer) ReadFloat32(s *smithy.Schema, v *float32) error {
return d.inner.ReadFloat32(s, v)
}
func (d *ShapeDeserializer) ReadFloat64(s *smithy.Schema, v *float64) error {
return d.inner.ReadFloat64(s, v)
}
func (d *ShapeDeserializer) ReadBlob(s *smithy.Schema, v *[]byte) error {
if d.inBindings {
if isEventHeader(s) {
hv := d.Message.Headers.Get(s.MemberName())
if hv == nil {
return nil
}
bv, ok := hv.(BytesValue)
if !ok {
return fmt.Errorf("event header %q: expected bytes, got %T", s.MemberName(), hv)
}
*v = []byte(bv)
return nil
}
if isEventPayload(s) {
*v = d.Message.Payload
return nil
}
}
return d.inner.ReadBlob(s, v)
}
func (d *ShapeDeserializer) ReadTime(s *smithy.Schema, v *time.Time) error {
if d.inBindings && isEventHeader(s) {
hv := d.Message.Headers.Get(s.MemberName())
if hv == nil {
return nil
}
tv, ok := hv.(TimestampValue)
if !ok {
return fmt.Errorf("event header %q: expected timestamp, got %T", s.MemberName(), hv)
}
*v = time.Time(tv)
return nil
}
return d.inner.ReadTime(s, v)
}
func (d *ShapeDeserializer) ReadList(s *smithy.Schema) error {
return d.inner.ReadList(s)
}
func (d *ShapeDeserializer) ReadListItem(s *smithy.Schema) (bool, error) {
return d.inner.ReadListItem(s)
}
func (d *ShapeDeserializer) ReadMap(s *smithy.Schema) error {
return d.inner.ReadMap(s)
}
func (d *ShapeDeserializer) ReadMapKey(s *smithy.Schema) (string, bool, error) {
return d.inner.ReadMapKey(s)
}
func (d *ShapeDeserializer) ReadUnion(s *smithy.Schema) (*smithy.Schema, error) {
return d.inner.ReadUnion(s)
}
func (d *ShapeDeserializer) ReadNil(s *smithy.Schema) (bool, error) {
return d.inner.ReadNil(s)
}
func (d *ShapeDeserializer) ReadDocument(s *smithy.Schema, v *document.Value) error {
return d.inner.ReadDocument(s, v)
}
func isEventBound(schema *smithy.Schema) bool {
_, h := smithy.SchemaTrait[*traits.EventHeader](schema)
_, p := smithy.SchemaTrait[*traits.EventPayload](schema)
return h || p
}
// ReadBigInt is unimplemented and will return an error.
func (d *ShapeDeserializer) ReadBigInt(_ *smithy.Schema, _ *big.Int) error {
return fmt.Errorf("unimplemented")
}
// ReadBigFloat is unimplemented and will return an error.
func (d *ShapeDeserializer) ReadBigFloat(_ *smithy.Schema, _ *big.Float) error {
return fmt.Errorf("unimplemented")
}
+167
View File
@@ -0,0 +1,167 @@
package eventstream
import (
"bytes"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/aws/smithy-go/logging"
"hash"
"hash/crc32"
"io"
)
// EncoderOptions is the configuration options for Encoder.
type EncoderOptions struct {
Logger logging.Logger
LogMessages bool
}
// Encoder provides EventStream message encoding.
type Encoder struct {
options EncoderOptions
headersBuf *bytes.Buffer
messageBuf *bytes.Buffer
}
// NewEncoder initializes and returns an Encoder to encode Event Stream
// messages.
func NewEncoder(optFns ...func(*EncoderOptions)) *Encoder {
o := EncoderOptions{}
for _, fn := range optFns {
fn(&o)
}
return &Encoder{
options: o,
headersBuf: bytes.NewBuffer(nil),
messageBuf: bytes.NewBuffer(nil),
}
}
// Encode encodes a single EventStream message to the io.Writer the Encoder
// was created with. An error is returned if writing the message fails.
func (e *Encoder) Encode(w io.Writer, msg Message) (err error) {
e.headersBuf.Reset()
e.messageBuf.Reset()
var writer io.Writer = e.messageBuf
if e.options.Logger != nil && e.options.LogMessages {
encodeMsgBuf := bytes.NewBuffer(nil)
writer = io.MultiWriter(writer, encodeMsgBuf)
defer func() {
logMessageEncode(e.options.Logger, encodeMsgBuf, msg, err)
}()
}
if err = EncodeHeaders(e.headersBuf, msg.Headers); err != nil {
return err
}
crc := crc32.New(crc32IEEETable)
hashWriter := io.MultiWriter(writer, crc)
headersLen := uint32(e.headersBuf.Len())
payloadLen := uint32(len(msg.Payload))
if err = encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil {
return err
}
if headersLen > 0 {
if _, err = io.Copy(hashWriter, e.headersBuf); err != nil {
return err
}
}
if payloadLen > 0 {
if _, err = hashWriter.Write(msg.Payload); err != nil {
return err
}
}
msgCRC := crc.Sum32()
if err := binary.Write(writer, binary.BigEndian, msgCRC); err != nil {
return err
}
_, err = io.Copy(w, e.messageBuf)
return err
}
func logMessageEncode(logger logging.Logger, msgBuf *bytes.Buffer, msg Message, encodeErr error) {
w := bytes.NewBuffer(nil)
defer func() { logger.Logf(logging.Debug, w.String()) }()
fmt.Fprintf(w, "Message to encode:\n")
encoder := json.NewEncoder(w)
if err := encoder.Encode(msg); err != nil {
fmt.Fprintf(w, "Failed to get encoded message, %v\n", err)
}
if encodeErr != nil {
fmt.Fprintf(w, "Encode error: %v\n", encodeErr)
return
}
fmt.Fprintf(w, "Raw message:\n%s\n", hex.Dump(msgBuf.Bytes()))
}
func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) error {
p := messagePrelude{
Length: minMsgLen + headersLen + payloadLen,
HeadersLen: headersLen,
}
if err := p.ValidateLens(); err != nil {
return err
}
err := binaryWriteFields(w, binary.BigEndian,
p.Length,
p.HeadersLen,
)
if err != nil {
return err
}
p.PreludeCRC = crc.Sum32()
err = binary.Write(w, binary.BigEndian, p.PreludeCRC)
if err != nil {
return err
}
return nil
}
// EncodeHeaders writes the header values to the writer encoded in the event
// stream format. Returns an error if a header fails to encode.
func EncodeHeaders(w io.Writer, headers Headers) error {
for _, h := range headers {
hn := headerName{
Len: uint8(len(h.Name)),
}
copy(hn.Name[:hn.Len], h.Name)
if err := hn.encode(w); err != nil {
return err
}
if err := h.Value.encode(w); err != nil {
return err
}
}
return nil
}
func binaryWriteFields(w io.Writer, order binary.ByteOrder, vs ...any) error {
for _, v := range vs {
if err := binary.Write(w, order, v); err != nil {
return err
}
}
return nil
}
+23
View File
@@ -0,0 +1,23 @@
package eventstream
import "fmt"
// LengthError provides the error for items being larger than a maximum length.
type LengthError struct {
Part string
Want int
Have int
Value any
}
func (e LengthError) Error() string {
return fmt.Sprintf("%s length invalid, %d/%d, %v",
e.Part, e.Want, e.Have, e.Value)
}
// ChecksumError provides the error for message checksum invalidation errors.
type ChecksumError struct{}
func (e ChecksumError) Error() string {
return "message checksum mismatch"
}
+175
View File
@@ -0,0 +1,175 @@
package eventstream
import (
"encoding/binary"
"fmt"
"io"
)
// Headers are a collection of EventStream header values.
type Headers []Header
// Header is a single EventStream Key Value header pair.
type Header struct {
Name string
Value Value
}
// Set associates the name with a value. If the header name already exists in
// the Headers the value will be replaced with the new one.
func (hs *Headers) Set(name string, value Value) {
var i int
for ; i < len(*hs); i++ {
if (*hs)[i].Name == name {
(*hs)[i].Value = value
return
}
}
*hs = append(*hs, Header{
Name: name, Value: value,
})
}
// Get returns the Value associated with the header. Nil is returned if the
// value does not exist.
func (hs Headers) Get(name string) Value {
for i := range hs {
if h := hs[i]; h.Name == name {
return h.Value
}
}
return nil
}
// Del deletes the value in the Headers if it exists.
func (hs *Headers) Del(name string) {
for i := 0; i < len(*hs); i++ {
if (*hs)[i].Name == name {
copy((*hs)[i:], (*hs)[i+1:])
(*hs) = (*hs)[:len(*hs)-1]
}
}
}
// Clone returns a deep copy of the headers
func (hs Headers) Clone() Headers {
o := make(Headers, 0, len(hs))
for _, h := range hs {
o.Set(h.Name, h.Value)
}
return o
}
func decodeHeaders(r io.Reader) (Headers, error) {
hs := Headers{}
for {
name, err := decodeHeaderName(r)
if err != nil {
if err == io.EOF {
// EOF while getting header name means no more headers
break
}
return nil, err
}
value, err := decodeHeaderValue(r)
if err != nil {
return nil, err
}
hs.Set(name, value)
}
return hs, nil
}
func decodeHeaderName(r io.Reader) (string, error) {
var n headerName
var err error
n.Len, err = decodeUint8(r)
if err != nil {
return "", err
}
name := n.Name[:n.Len]
if _, err := io.ReadFull(r, name); err != nil {
return "", err
}
return string(name), nil
}
func decodeHeaderValue(r io.Reader) (Value, error) {
var raw rawValue
typ, err := decodeUint8(r)
if err != nil {
return nil, err
}
raw.Type = valueType(typ)
var v Value
switch raw.Type {
case trueValueType:
v = BoolValue(true)
case falseValueType:
v = BoolValue(false)
case int8ValueType:
var tv Int8Value
err = tv.decode(r)
v = tv
case int16ValueType:
var tv Int16Value
err = tv.decode(r)
v = tv
case int32ValueType:
var tv Int32Value
err = tv.decode(r)
v = tv
case int64ValueType:
var tv Int64Value
err = tv.decode(r)
v = tv
case bytesValueType:
var tv BytesValue
err = tv.decode(r)
v = tv
case stringValueType:
var tv StringValue
err = tv.decode(r)
v = tv
case timestampValueType:
var tv TimestampValue
err = tv.decode(r)
v = tv
case uuidValueType:
var tv UUIDValue
err = tv.decode(r)
v = tv
default:
panic(fmt.Sprintf("unknown value type %d", raw.Type))
}
// Error could be EOF, let caller deal with it
return v, err
}
const maxHeaderNameLen = 255
type headerName struct {
Len uint8
Name [maxHeaderNameLen]byte
}
func (v headerName) encode(w io.Writer) error {
if err := binary.Write(w, binary.BigEndian, v.Len); err != nil {
return err
}
_, err := w.Write(v.Name[:v.Len])
return err
}
+521
View File
@@ -0,0 +1,521 @@
package eventstream
import (
"encoding/base64"
"encoding/binary"
"encoding/hex"
"fmt"
"io"
"strconv"
"time"
)
const maxHeaderValueLen = 1<<15 - 1 // 2^15-1 or 32KB - 1
// valueType is the EventStream header value type.
type valueType uint8
// Header value types
const (
trueValueType valueType = iota
falseValueType
int8ValueType // Byte
int16ValueType // Short
int32ValueType // Integer
int64ValueType // Long
bytesValueType
stringValueType
timestampValueType
uuidValueType
)
func (t valueType) String() string {
switch t {
case trueValueType:
return "bool"
case falseValueType:
return "bool"
case int8ValueType:
return "int8"
case int16ValueType:
return "int16"
case int32ValueType:
return "int32"
case int64ValueType:
return "int64"
case bytesValueType:
return "byte_array"
case stringValueType:
return "string"
case timestampValueType:
return "timestamp"
case uuidValueType:
return "uuid"
default:
return fmt.Sprintf("unknown value type %d", uint8(t))
}
}
type rawValue struct {
Type valueType
Len uint16 // Only set for variable length slices
Value []byte // byte representation of value, BigEndian encoding.
}
func (r rawValue) encodeScalar(w io.Writer, v any) error {
return binaryWriteFields(w, binary.BigEndian,
r.Type,
v,
)
}
func (r rawValue) encodeFixedSlice(w io.Writer, v []byte) error {
binary.Write(w, binary.BigEndian, r.Type)
_, err := w.Write(v)
return err
}
func (r rawValue) encodeBytes(w io.Writer, v []byte) error {
if len(v) > maxHeaderValueLen {
return LengthError{
Part: "header value",
Want: maxHeaderValueLen, Have: len(v),
Value: v,
}
}
r.Len = uint16(len(v))
err := binaryWriteFields(w, binary.BigEndian,
r.Type,
r.Len,
)
if err != nil {
return err
}
_, err = w.Write(v)
return err
}
func (r rawValue) encodeString(w io.Writer, v string) error {
if len(v) > maxHeaderValueLen {
return LengthError{
Part: "header value",
Want: maxHeaderValueLen, Have: len(v),
Value: v,
}
}
r.Len = uint16(len(v))
type stringWriter interface {
WriteString(string) (int, error)
}
err := binaryWriteFields(w, binary.BigEndian,
r.Type,
r.Len,
)
if err != nil {
return err
}
if sw, ok := w.(stringWriter); ok {
_, err = sw.WriteString(v)
} else {
_, err = w.Write([]byte(v))
}
return err
}
func decodeFixedBytesValue(r io.Reader, buf []byte) error {
_, err := io.ReadFull(r, buf)
return err
}
func decodeBytesValue(r io.Reader) ([]byte, error) {
var raw rawValue
var err error
raw.Len, err = decodeUint16(r)
if err != nil {
return nil, err
}
buf := make([]byte, raw.Len)
_, err = io.ReadFull(r, buf)
if err != nil {
return nil, err
}
return buf, nil
}
func decodeStringValue(r io.Reader) (string, error) {
v, err := decodeBytesValue(r)
return string(v), err
}
// Value represents the abstract header value.
type Value interface {
Get() any
String() string
valueType() valueType
encode(io.Writer) error
}
// An BoolValue provides eventstream encoding, and representation
// of a Go bool value.
type BoolValue bool
// Get returns the underlying type
func (v BoolValue) Get() any {
return bool(v)
}
// valueType returns the EventStream header value type value.
func (v BoolValue) valueType() valueType {
if v {
return trueValueType
}
return falseValueType
}
func (v BoolValue) String() string {
return strconv.FormatBool(bool(v))
}
// encode encodes the BoolValue into an eventstream binary value
// representation.
func (v BoolValue) encode(w io.Writer) error {
return binary.Write(w, binary.BigEndian, v.valueType())
}
// An Int8Value provides eventstream encoding, and representation of a Go
// int8 value.
type Int8Value int8
// Get returns the underlying value.
func (v Int8Value) Get() any {
return int8(v)
}
// valueType returns the EventStream header value type value.
func (Int8Value) valueType() valueType {
return int8ValueType
}
func (v Int8Value) String() string {
return fmt.Sprintf("0x%02x", int8(v))
}
// encode encodes the Int8Value into an eventstream binary value
// representation.
func (v Int8Value) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeScalar(w, v)
}
func (v *Int8Value) decode(r io.Reader) error {
n, err := decodeUint8(r)
if err != nil {
return err
}
*v = Int8Value(n)
return nil
}
// An Int16Value provides eventstream encoding, and representation of a Go
// int16 value.
type Int16Value int16
// Get returns the underlying value.
func (v Int16Value) Get() any {
return int16(v)
}
// valueType returns the EventStream header value type value.
func (Int16Value) valueType() valueType {
return int16ValueType
}
func (v Int16Value) String() string {
return fmt.Sprintf("0x%04x", int16(v))
}
// encode encodes the Int16Value into an eventstream binary value
// representation.
func (v Int16Value) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeScalar(w, v)
}
func (v *Int16Value) decode(r io.Reader) error {
n, err := decodeUint16(r)
if err != nil {
return err
}
*v = Int16Value(n)
return nil
}
// An Int32Value provides eventstream encoding, and representation of a Go
// int32 value.
type Int32Value int32
// Get returns the underlying value.
func (v Int32Value) Get() any {
return int32(v)
}
// valueType returns the EventStream header value type value.
func (Int32Value) valueType() valueType {
return int32ValueType
}
func (v Int32Value) String() string {
return fmt.Sprintf("0x%08x", int32(v))
}
// encode encodes the Int32Value into an eventstream binary value
// representation.
func (v Int32Value) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeScalar(w, v)
}
func (v *Int32Value) decode(r io.Reader) error {
n, err := decodeUint32(r)
if err != nil {
return err
}
*v = Int32Value(n)
return nil
}
// An Int64Value provides eventstream encoding, and representation of a Go
// int64 value.
type Int64Value int64
// Get returns the underlying value.
func (v Int64Value) Get() any {
return int64(v)
}
// valueType returns the EventStream header value type value.
func (Int64Value) valueType() valueType {
return int64ValueType
}
func (v Int64Value) String() string {
return fmt.Sprintf("0x%016x", int64(v))
}
// encode encodes the Int64Value into an eventstream binary value
// representation.
func (v Int64Value) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeScalar(w, v)
}
func (v *Int64Value) decode(r io.Reader) error {
n, err := decodeUint64(r)
if err != nil {
return err
}
*v = Int64Value(n)
return nil
}
// An BytesValue provides eventstream encoding, and representation of a Go
// byte slice.
type BytesValue []byte
// Get returns the underlying value.
func (v BytesValue) Get() any {
return []byte(v)
}
// valueType returns the EventStream header value type value.
func (BytesValue) valueType() valueType {
return bytesValueType
}
func (v BytesValue) String() string {
return base64.StdEncoding.EncodeToString([]byte(v))
}
// encode encodes the BytesValue into an eventstream binary value
// representation.
func (v BytesValue) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeBytes(w, []byte(v))
}
func (v *BytesValue) decode(r io.Reader) error {
buf, err := decodeBytesValue(r)
if err != nil {
return err
}
*v = BytesValue(buf)
return nil
}
// An StringValue provides eventstream encoding, and representation of a Go
// string.
type StringValue string
// Get returns the underlying value.
func (v StringValue) Get() any {
return string(v)
}
// valueType returns the EventStream header value type value.
func (StringValue) valueType() valueType {
return stringValueType
}
func (v StringValue) String() string {
return string(v)
}
// encode encodes the StringValue into an eventstream binary value
// representation.
func (v StringValue) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeString(w, string(v))
}
func (v *StringValue) decode(r io.Reader) error {
s, err := decodeStringValue(r)
if err != nil {
return err
}
*v = StringValue(s)
return nil
}
// An TimestampValue provides eventstream encoding, and representation of a Go
// timestamp.
type TimestampValue time.Time
// Get returns the underlying value.
func (v TimestampValue) Get() any {
return time.Time(v)
}
// valueType returns the EventStream header value type value.
func (TimestampValue) valueType() valueType {
return timestampValueType
}
func (v TimestampValue) epochMilli() int64 {
nano := time.Time(v).UnixNano()
msec := nano / int64(time.Millisecond)
return msec
}
func (v TimestampValue) String() string {
msec := v.epochMilli()
return strconv.FormatInt(msec, 10)
}
// encode encodes the TimestampValue into an eventstream binary value
// representation.
func (v TimestampValue) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
msec := v.epochMilli()
return raw.encodeScalar(w, msec)
}
func (v *TimestampValue) decode(r io.Reader) error {
n, err := decodeUint64(r)
if err != nil {
return err
}
*v = TimestampValue(timeFromEpochMilli(int64(n)))
return nil
}
// MarshalJSON implements the json.Marshaler interface
func (v TimestampValue) MarshalJSON() ([]byte, error) {
return []byte(v.String()), nil
}
func timeFromEpochMilli(t int64) time.Time {
secs := t / 1e3
msec := t % 1e3
return time.Unix(secs, msec*int64(time.Millisecond)).UTC()
}
// An UUIDValue provides eventstream encoding, and representation of a UUID
// value.
type UUIDValue [16]byte
// Get returns the underlying value.
func (v UUIDValue) Get() any {
return v[:]
}
// valueType returns the EventStream header value type value.
func (UUIDValue) valueType() valueType {
return uuidValueType
}
func (v UUIDValue) String() string {
var scratch [36]byte
const dash = '-'
hex.Encode(scratch[:8], v[0:4])
scratch[8] = dash
hex.Encode(scratch[9:13], v[4:6])
scratch[13] = dash
hex.Encode(scratch[14:18], v[6:8])
scratch[18] = dash
hex.Encode(scratch[19:23], v[8:10])
scratch[23] = dash
hex.Encode(scratch[24:], v[10:])
return string(scratch[:])
}
// encode encodes the UUIDValue into an eventstream binary value
// representation.
func (v UUIDValue) encode(w io.Writer) error {
raw := rawValue{
Type: v.valueType(),
}
return raw.encodeFixedSlice(w, v[:])
}
func (v *UUIDValue) decode(r io.Reader) error {
tv := (*v)[:]
return decodeFixedBytesValue(r, tv)
}
+99
View File
@@ -0,0 +1,99 @@
package eventstream
import (
"bytes"
"encoding/binary"
"hash/crc32"
)
const preludeLen = 8
const preludeCRCLen = 4
const msgCRCLen = 4
const minMsgLen = preludeLen + preludeCRCLen + msgCRCLen
var crc32IEEETable = crc32.MakeTable(crc32.IEEE)
// A Message provides the eventstream message representation.
type Message struct {
Headers Headers
Payload []byte
}
func (m *Message) rawMessage() (rawMessage, error) {
var raw rawMessage
if len(m.Headers) > 0 {
var headers bytes.Buffer
if err := EncodeHeaders(&headers, m.Headers); err != nil {
return rawMessage{}, err
}
raw.Headers = headers.Bytes()
raw.HeadersLen = uint32(len(raw.Headers))
}
raw.Length = raw.HeadersLen + uint32(len(m.Payload)) + minMsgLen
hash := crc32.New(crc32IEEETable)
binaryWriteFields(hash, binary.BigEndian, raw.Length, raw.HeadersLen)
raw.PreludeCRC = hash.Sum32()
binaryWriteFields(hash, binary.BigEndian, raw.PreludeCRC)
if raw.HeadersLen > 0 {
hash.Write(raw.Headers)
}
// Read payload bytes and update hash for it as well.
if len(m.Payload) > 0 {
raw.Payload = m.Payload
hash.Write(raw.Payload)
}
raw.CRC = hash.Sum32()
return raw, nil
}
// Clone returns a deep copy of the message.
func (m Message) Clone() Message {
var payload []byte
if m.Payload != nil {
payload = make([]byte, len(m.Payload))
copy(payload, m.Payload)
}
return Message{
Headers: m.Headers.Clone(),
Payload: payload,
}
}
type messagePrelude struct {
Length uint32
HeadersLen uint32
PreludeCRC uint32
}
func (p messagePrelude) PayloadLen() uint32 {
return p.Length - p.HeadersLen - minMsgLen
}
func (p messagePrelude) ValidateLens() error {
if p.Length == 0 {
return LengthError{
Part: "message prelude",
Want: minMsgLen,
Have: int(p.Length),
}
}
return nil
}
type rawMessage struct {
messagePrelude
Headers []byte
Payload []byte
CRC uint32
}
+228
View File
@@ -0,0 +1,228 @@
package eventstream
import (
"math/big"
"time"
"github.com/aws/smithy-go"
"github.com/aws/smithy-go/document"
"github.com/aws/smithy-go/traits"
)
// ShapeSerializer wraps a [smithy.ShapeSerializer], much like the internal
// httpbinding serializer, to handle event stream message binding traits.
type ShapeSerializer struct {
Message *Message
inner smithy.ShapeSerializer
contentType string // may be inflenced by bindings
depth int
hasBody bool
}
var _ smithy.ShapeSerializer = (*ShapeSerializer)(nil)
// NewShapeSerializer returns a serializer for a single Message.
func NewShapeSerializer(msg *Message, inner smithy.ShapeSerializer) *ShapeSerializer {
return &ShapeSerializer{
Message: msg,
inner: inner,
}
}
// ContentType returns the resolved content type for the event message payload
// after serialization, which may be affected by bindings.
func (s *ShapeSerializer) ContentType() string {
return s.contentType
}
// Bytes returns the serialized body bytes.
func (s *ShapeSerializer) Bytes() []byte {
return s.inner.Bytes()
}
// WriteBool implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteBool(schema *smithy.Schema, v bool) {
if isEventHeader(schema) {
s.Message.Headers.Set(schema.MemberName(), BoolValue(v))
return
}
s.inner.WriteBool(schema, v)
}
// WriteInt8 implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteInt8(schema *smithy.Schema, v int8) {
if isEventHeader(schema) {
s.Message.Headers.Set(schema.MemberName(), Int8Value(v))
return
}
s.inner.WriteInt8(schema, v)
}
// WriteInt16 implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteInt16(schema *smithy.Schema, v int16) {
if isEventHeader(schema) {
s.Message.Headers.Set(schema.MemberName(), Int16Value(v))
return
}
s.inner.WriteInt16(schema, v)
}
// WriteInt32 implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteInt32(schema *smithy.Schema, v int32) {
if isEventHeader(schema) {
s.Message.Headers.Set(schema.MemberName(), Int32Value(v))
return
}
s.inner.WriteInt32(schema, v)
}
// WriteInt64 implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteInt64(schema *smithy.Schema, v int64) {
if isEventHeader(schema) {
s.Message.Headers.Set(schema.MemberName(), Int64Value(v))
return
}
s.inner.WriteInt64(schema, v)
}
// WriteFloat32 implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteFloat32(schema *smithy.Schema, v float32) {
s.inner.WriteFloat32(schema, v)
}
// WriteFloat64 implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteFloat64(schema *smithy.Schema, v float64) {
s.inner.WriteFloat64(schema, v)
}
// WriteString implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteString(schema *smithy.Schema, v string) {
if isEventHeader(schema) {
s.Message.Headers.Set(schema.MemberName(), StringValue(v))
return
}
if isEventPayload(schema) {
s.Message.Payload = []byte(v)
s.contentType = "text/plain"
return
}
s.inner.WriteString(schema, v)
}
// WriteBlob implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteBlob(schema *smithy.Schema, v []byte) {
if isEventHeader(schema) {
s.Message.Headers.Set(schema.MemberName(), BytesValue(v))
return
}
if isEventPayload(schema) {
s.Message.Payload = v
s.contentType = "application/octet-stream"
return
}
s.inner.WriteBlob(schema, v)
}
// WriteTime implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteTime(schema *smithy.Schema, v time.Time) {
if isEventHeader(schema) {
s.Message.Headers.Set(schema.MemberName(), TimestampValue(v))
return
}
s.inner.WriteTime(schema, v)
}
// WriteBigInt implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteBigInt(schema *smithy.Schema, v *big.Int) {
s.inner.WriteBigInt(schema, v)
}
// WriteBigFloat implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteBigFloat(schema *smithy.Schema, v *big.Float) {
s.inner.WriteBigFloat(schema, v)
}
// WriteStruct implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteStruct(schema *smithy.Schema) {
s.depth++
if s.depth > 1 {
s.inner.WriteStruct(schema)
return
}
// At depth 1 (the event struct itself), start a JSON body if there are
// implicit body members (members without @eventHeader or @eventPayload).
for _, m := range schema.Members() {
if !isEventBound(m) {
s.inner.WriteStruct(schema)
s.hasBody = true
return
}
}
}
// CloseStruct implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) CloseStruct() {
if s.depth > 1 || s.hasBody {
s.inner.CloseStruct()
}
if s.depth == 1 {
s.hasBody = false
}
s.depth--
}
// WriteUnion implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteUnion(schema, variant *smithy.Schema) {
s.inner.WriteUnion(schema, variant)
}
// CloseUnion implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) CloseUnion() {
s.inner.CloseUnion()
}
// WriteNil implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteNil(schema *smithy.Schema) {
s.inner.WriteNil(schema)
}
// WriteList implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteList(schema *smithy.Schema) {
s.inner.WriteList(schema)
}
// CloseList implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) CloseList() {
s.inner.CloseList()
}
// WriteMap implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteMap(schema *smithy.Schema) {
s.inner.WriteMap(schema)
}
// WriteKey implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteKey(schema *smithy.Schema, key string) {
s.inner.WriteKey(schema, key)
}
// CloseMap implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) CloseMap() {
s.inner.CloseMap()
}
// WriteDocument implements [smithy.ShapeSerializer].
func (s *ShapeSerializer) WriteDocument(schema *smithy.Schema, v document.Value) {
s.inner.WriteDocument(schema, v)
}
func isEventHeader(schema *smithy.Schema) bool {
_, ok := smithy.SchemaTrait[*traits.EventHeader](schema)
return ok
}
func isEventPayload(schema *smithy.Schema) bool {
_, ok := smithy.SchemaTrait[*traits.EventPayload](schema)
return ok
}
+82
View File
@@ -0,0 +1,82 @@
package eventstream
import (
"bytes"
"io"
"time"
)
// MessageSigner signs event stream message header and payload byte pairs.
// Each invocation chains off the previous signature.
type MessageSigner interface {
SignMessage(headers, payload []byte, signingTime time.Time) ([]byte, error)
}
// SigningWriter wraps an io.WriteCloser and signs each event stream message
// frame written to it. Each Write call MUST contain exactly one complete
// encoded event stream message frame.
//
// The signing writer wraps each incoming frame in an outer event stream
// message with :date and :chunk-signature headers, then encodes the outer
// message to the underlying writer.
//
// Close sends a signed empty message to signal end-of-stream, then closes
// the underlying writer.
type SigningWriter struct {
writer io.WriteCloser
signer MessageSigner
encoder *Encoder
headersBuf bytes.Buffer
}
// NewSigningWriter returns a SigningWriter that signs frames and writes them
// to w.
func NewSigningWriter(w io.WriteCloser, signer MessageSigner) *SigningWriter {
return &SigningWriter{
writer: w,
signer: signer,
encoder: NewEncoder(),
}
}
// Write signs a complete event stream message frame and writes the signed
// outer envelope to the underlying writer.
func (s *SigningWriter) Write(frame []byte) (int, error) {
if err := s.signAndWrite(frame); err != nil {
return 0, err
}
return len(frame), nil
}
// Close sends a signed empty message to signal end-of-stream, then closes
// the underlying writer.
func (s *SigningWriter) Close() error {
if err := s.signAndWrite([]byte{}); err != nil {
_ = s.writer.Close()
return err
}
return s.writer.Close()
}
func (s *SigningWriter) signAndWrite(payload []byte) error {
now := time.Now().UTC()
var msg Message
msg.Headers.Set(DateHeader, TimestampValue(now))
msg.Payload = payload
s.headersBuf.Reset()
if err := EncodeHeaders(&s.headersBuf, msg.Headers); err != nil {
return err
}
sig, err := s.signer.SignMessage(s.headersBuf.Bytes(), payload, now)
if err != nil {
return err
}
msg.Headers.Set(ChunkSignatureHeader, BytesValue(sig))
return s.encoder.Encode(s.writer, msg)
}
+26
View File
@@ -0,0 +1,26 @@
package eventstream
import "github.com/aws/smithy-go"
// UnknownUnionMember is returned when a union member is returned over the
// wire, but has an unknown tag.
type UnknownUnionMember struct {
Tag string
Value []byte
}
// Deserialize is a no-op. The raw bytes are already captured in Value.
func (*UnknownUnionMember) Deserialize(smithy.ShapeDeserializer) error {
return nil
}
// UnknownMessageError provides an error when a message is received from the
// stream, but the reader is unable to determine what kind of message it is.
type UnknownMessageError struct {
Type string
Message *Message
}
func (e *UnknownMessageError) Error() string {
return "unknown event stream message type, " + e.Type
}
+1 -1
View File
@@ -3,4 +3,4 @@
package smithy
// goModuleVersion is the tagged release for this module
const goModuleVersion = "1.25.1"
const goModuleVersion = "1.27.2"
+328
View File
@@ -0,0 +1,328 @@
package smithy
import (
"fmt"
"strings"
"sync/atomic"
"unsafe"
)
// ShapeType is a type of Smithy shape.
// See https://smithy.io/2.0/spec/idl.html#defining-shapes.
type ShapeType int
// Enumerates ShapeType per the Smithy IDL.
const (
ShapeTypeBlob ShapeType = iota
ShapeTypeBoolean
ShapeTypeString
ShapeTypeTimestamp
ShapeTypeByte
ShapeTypeShort
ShapeTypeInteger
ShapeTypeLong
ShapeTypeFloat
ShapeTypeDocument
ShapeTypeDouble
ShapeTypeBigDecimal
ShapeTypeBigInteger
ShapeTypeEnum
ShapeTypeIntEnum
ShapeTypeList
ShapeTypeSet
ShapeTypeMap
ShapeTypeStructure
ShapeTypeUnion
ShapeTypeMember
ShapeTypeService
ShapeTypeResource
ShapeTypeOperation
)
// ShapeID fields of a Smithy shape ID.
type ShapeID struct {
Namespace, Name, Member string
}
// String returns the IDL microformat for the shape ID.
func (s ShapeID) String() string {
if s.Member == "" {
return fmt.Sprintf("%s#%s", s.Namespace, s.Name)
}
return fmt.Sprintf("%s#%s$%s", s.Namespace, s.Name, s.Member)
}
func stoid(s string) ShapeID {
ns, n, _ := strings.Cut(s, "#")
n, m, _ := strings.Cut(n, "$")
return ShapeID{ns, n, m}
}
// Schema encodes information about a shape from a Smithy model.
//
// Generated clients use schemas at runtime to dynamically (de)serialize
// request/responses.
type Schema struct {
id ShapeID
typ ShapeType
members map[string]*Schema // member name -> schema
traits map[ShapeID]Trait // trait ID -> non-indexed traits only
indexed []Trait // indexed trait slots, sized to max index present
directMask uint64 // bitmask: bit i set means indexed[i] was declared directly on this schema
targetID ShapeID // for member schemas, the target's shape ID
listMember *Schema
mapKey, mapValue *Schema
ext [numExtensionSlots]unsafe.Pointer // lazily-computed codec extensions, accessed atomically
}
// NewSchema creates a new Schema with the given shape ID and traits.
func NewSchema(id ShapeID, typ ShapeType, numMembers int, ts ...Trait) *Schema {
s := &Schema{
id: id,
typ: typ,
members: make(map[string]*Schema, numMembers),
}
for _, t := range ts {
s.addTrait(t, true)
}
return s
}
func (s *Schema) addTrait(t Trait, direct bool) {
if it, ok := t.(IndexableTrait); ok {
idx := it.TraitIndex()
if idx >= len(s.indexed) {
s.indexed = append(s.indexed, make([]Trait, idx-len(s.indexed)+1)...)
}
s.indexed[idx] = t
if direct {
s.directMask |= 1 << uint(idx)
}
return
}
if s.traits == nil {
s.traits = map[ShapeID]Trait{}
}
s.traits[t.TraitID()] = t
}
// AddMember adds a member to the schema derived from the target, with
// optional trait overrides. The member schema is returned for caller
// reference.
//
// The member schema's effective trait view (accessed via [SchemaTrait])
// inherits all of the target's traits, then applies the overrides. The
// member's direct trait view (accessed via [SchemaDirectTrait]) contains
// only the overrides, i.e. the traits declared directly on the member.
func (s *Schema) AddMember(name string, target *Schema, ts ...Trait) *Schema {
m := &Schema{
id: ShapeID{Member: name},
typ: target.typ,
members: target.members,
indexed: cloneIndexed(target.indexed),
traits: cloneTraits(target.traits),
directMask: 0, // inherited traits are not direct
targetID: target.id,
listMember: target.listMember,
mapKey: target.mapKey,
mapValue: target.mapValue,
}
// member-declared traits override and are direct
for _, t := range ts {
m.addTrait(t, true)
}
s.members[name] = m
// Invalidate cached extensions, schema structure changed.
for i := range s.ext {
atomic.StorePointer(&s.ext[i], nil)
}
switch name {
case "member":
s.listMember = m
case "key":
s.mapKey = m
case "value":
s.mapValue = m
}
return m
}
func cloneIndexed(src []Trait) []Trait {
if src == nil {
return nil
}
dst := make([]Trait, len(src))
copy(dst, src)
return dst
}
func cloneTraits(src map[ShapeID]Trait) map[ShapeID]Trait {
if src == nil {
return nil
}
dst := make(map[ShapeID]Trait, len(src))
for k, v := range src {
dst[k] = v
}
return dst
}
// ListMember returns the "member" schema for list types.
func (s *Schema) ListMember() *Schema {
return s.listMember
}
// MapKey returns the "key" schema for map types.
func (s *Schema) MapKey() *Schema {
return s.mapKey
}
// MapValue returns the "value" schema for map types.
func (s *Schema) MapValue() *Schema {
return s.mapValue
}
// MemberName returns the member component of the schema's shape ID.
func (s *Schema) MemberName() string {
return s.id.Member
}
// ID returns the shape ID of the schema.
func (s *Schema) ID() ShapeID {
return s.id
}
// TargetID returns the shape ID of the member's target shape.
func (s *Schema) TargetID() ShapeID {
return s.targetID
}
// Type returns the shape type of the schema.
func (s *Schema) Type() ShapeType {
return s.typ
}
// Member returns the member schema for the given name, or nil.
func (s *Schema) Member(name string) *Schema {
return s.members[name]
}
// Members returns the schema's members as a map of name to schema.
func (s *Schema) Members() map[string]*Schema {
return s.members
}
// OperationSchema describes an operation, which is essentially its own schema
// with additional pointers to its input and output.
type OperationSchema struct {
*Schema
Input, Output *Schema
inputStream, outputStream bool
}
// NewOperationSchema returns an OperationSchema for (input, output).
func NewOperationSchema(op, input, output *Schema) *OperationSchema {
return &OperationSchema{
Schema: op,
Input: input,
Output: output,
inputStream: isEventStream(input),
outputStream: isEventStream(output),
}
}
// IsInputEventStream reports whether this is an input event stream.
func (s *OperationSchema) IsInputEventStream() bool {
return s.inputStream
}
// IsOutputEventStream reports whether this is an output event stream.
func (s *OperationSchema) IsOutputEventStream() bool {
return s.outputStream
}
// ServiceSchema describes a service shape.
type ServiceSchema struct {
*Schema
Version string
}
// NewServiceSchema returns a ServiceSchema for the given service shape.
func NewServiceSchema(schema *Schema, version string) *ServiceSchema {
return &ServiceSchema{Schema: schema, Version: version}
}
// SchemaTrait returns the target trait on the schema if it exists.
//
// For member schemas this returns the effective trait, which is the trait
// declared directly on the member if present, else the trait inherited from
// the target shape.
func SchemaTrait[T Trait](s *Schema) (T, bool) {
return schemaTrait[T](s, false)
}
// SchemaDirectTrait returns the target trait on the schema if it was
// declared directly on the schema.
//
// For member schemas this returns the trait only if it was declared on the
// member itself, ignoring any trait inherited from the target shape. For
// non-member schemas this is equivalent to [SchemaTrait].
func SchemaDirectTrait[T Trait](s *Schema) (T, bool) {
return schemaTrait[T](s, true)
}
func schemaTrait[T Trait](s *Schema, directOnly bool) (T, bool) {
var zero T
if s == nil {
return zero, false
}
if it, ok := Trait(zero).(IndexableTrait); ok {
idx := it.TraitIndex()
if idx >= len(s.indexed) {
return zero, false
}
if directOnly && s.directMask&(1<<uint(idx)) == 0 {
return zero, false
}
tt, ok := s.indexed[idx].(T)
return tt, ok
}
opaque, ok := s.traits[zero.TraitID()]
if !ok {
return zero, false
}
tt, ok := opaque.(T)
return tt, ok
}
// indexStreaming is the indexed trait slot for @streaming, mirrored from
// traits.indexStreaming. We can't import the traits package from here due to a
// circular dependency.
const indexStreaming = 17
func isEventStream(s *Schema) bool {
if s == nil {
return false
}
for _, m := range s.members {
if m.typ != ShapeTypeUnion {
continue
}
if len(m.indexed) > indexStreaming && m.indexed[indexStreaming] != nil {
return true
}
}
return false
}
+37
View File
@@ -0,0 +1,37 @@
package smithy
import (
"sync/atomic"
"unsafe"
)
// ExtensionID identifies a schema extension slot. Each codec family
// (JSON, CBOR, etc.) uses a distinct slot to cache precomputed data.
type ExtensionID int
const numExtensionSlots = 4
const (
ExtJSON ExtensionID = iota // transport/http/protocol/internal/json
ExtCBOR // transport/http/protocol/internal/cbor
ExtXML // transport/http/protocol/internal/xml
ExtQuery // transport/http/protocol/internal/query
)
// SchemaExtension retrieves or lazily computes the extension for the given
// slot. build is called on first access for a schema and the result is cached.
// The build function must return a pointer to an immutable value.
func SchemaExtension[T any](s *Schema, id ExtensionID, build func(*Schema) *T) *T {
p := atomic.LoadPointer(&s.ext[id])
if p != nil {
return (*T)(p)
}
return computeSchemaExtension(s, id, build)
}
//go:noinline
func computeSchemaExtension[T any](s *Schema, id ExtensionID, build func(*Schema) *T) *T {
v := build(s)
atomic.StorePointer(&s.ext[id], unsafe.Pointer(v))
return v
}
+229
View File
@@ -0,0 +1,229 @@
package smithy
import (
"fmt"
"io"
"math/big"
"time"
"github.com/aws/smithy-go/document"
)
// ShapeSerializer implements the marshaling of an in-code representation of a
// shape to an unspecified data format, which is determined by the
// implementation.
//
// A ShapeSerializer is consumed by the **code-generated** Serialize() method
// of a modeled structure. For example:
//
// func (v *PutItemInput) Serialize(s smithy.ShapeSerializer) {
// s.WriteStruct(schemas.PutItemInput)
// v.SerializeMembers(s)
// s.CloseStruct()
// }
//
// func (v *PutItemInput) SerializeMembers(s smithy.ShapeSerializer) {
// if v.TableName != nil {
// s.WriteString(schemas.PutItemInput_TableName, *v.TableName)
// }
// if v.Item != nil {
// serializeAttributeMap(s, schemas.PutItemInput_Item, v.Item)
// }
// // ...
// }
type ShapeSerializer interface {
Bytes() []byte
WriteInt8(*Schema, int8)
WriteInt16(*Schema, int16)
WriteInt32(*Schema, int32)
WriteInt64(*Schema, int64)
WriteFloat32(*Schema, float32)
WriteFloat64(*Schema, float64)
WriteBool(*Schema, bool)
WriteString(*Schema, string)
WriteBigInt(*Schema, *big.Int)
WriteBigFloat(*Schema, *big.Float)
WriteBlob(*Schema, []byte)
WriteTime(*Schema, time.Time)
WriteUnion(schema, variant *Schema)
CloseUnion()
WriteDocument(*Schema, document.Value)
WriteNil(*Schema)
WriteStruct(*Schema)
CloseStruct()
WriteList(*Schema)
CloseList()
WriteMap(*Schema)
WriteKey(*Schema, string)
CloseMap()
}
// ShapeDeserializer implements the unmarshaling from some unspecified data
// format to an in-code representation of a shape, which is determined by the
// implementation.
type ShapeDeserializer interface {
ReadInt8(*Schema, *int8) error
ReadInt16(*Schema, *int16) error
ReadInt32(*Schema, *int32) error
ReadInt64(*Schema, *int64) error
ReadFloat32(*Schema, *float32) error
ReadFloat64(*Schema, *float64) error
ReadBool(*Schema, *bool) error
ReadString(*Schema, *string) error
ReadBlob(*Schema, *[]byte) error
ReadTime(*Schema, *time.Time) error
ReadBigInt(*Schema, *big.Int) error
ReadBigFloat(*Schema, *big.Float) error
ReadNil(*Schema) (bool, error)
ReadStruct(*Schema) error
ReadStructMember() (*Schema, error)
ReadUnion(*Schema) (*Schema, error)
ReadDocument(*Schema, *document.Value) error
ReadList(*Schema) error
ReadListItem(*Schema) (hasMoreElements bool, err error)
ReadMap(*Schema) error
ReadMapKey(*Schema) (key string, hasMoreElements bool, err error)
}
// Serializable is an entity that can describe itself to a ShapeSerializer to
// be encoded to some format.
//
// Unlike the standard library marshaler interfaces, which idiomatically encode
// to []byte, the output format and data type here is not specified at all.
// This is because Smithy shapes need to encode to a variety of formats or data
// carriers. For example, HTTP-binding JSON protocols need to serialize some
// members to bytes (the HTTP request body) and others directly to fields on
// the HTTP request itself (e.g. headers).
type Serializable interface {
Serialize(ShapeSerializer)
}
// StreamingInput is implemented by input types that have a streaming blob
// payload (an io.Reader member with @httpPayload + @streaming).
type StreamingInput interface {
GetPayloadStream() io.Reader
}
// StreamingOutput is implemented by output types that have a streaming blob
// payload (an io.ReadCloser member with @httpPayload + @streaming).
type StreamingOutput interface {
SetPayloadStream(io.ReadCloser)
}
// Deserializable is an entity that can unmarshal itself from a
// ShapeDeserializer.
type Deserializable interface {
Deserialize(ShapeDeserializer) error
}
// DeserializableError is implemented by modeled error types for a service.
type DeserializableError interface {
Deserializable
error
}
// ReadUnion is a utility API for generated clients.
func ReadUnion(d ShapeDeserializer, schema *Schema, memberFn func(*Schema) error) error {
ms, err := d.ReadUnion(schema)
if ms == nil || err != nil {
return err
}
if err := memberFn(ms); err != nil {
return err
}
for {
ms, err = d.ReadUnion(schema)
if err != nil {
return err
}
if ms == nil {
return nil
}
return fmt.Errorf("union has more than one non-nil member: %s", ms.MemberName())
}
}
// ReadStruct is a utility API for generated clients.
func ReadStruct(d ShapeDeserializer, schema *Schema, memberFn func(*Schema) error) error {
if err := d.ReadStruct(schema); err != nil {
return err
}
for {
ms, err := d.ReadStructMember()
if err != nil {
return err
}
if ms == nil {
return nil
}
if err := memberFn(ms); err != nil {
return err
}
}
}
// ReadList is a utility API for generated clients.
func ReadList(d ShapeDeserializer, schema *Schema, memberFn func() error) error {
if err := d.ReadList(schema); err != nil {
return err
}
var memberSchema *Schema
if schema != nil {
memberSchema = schema.ListMember()
}
for {
ok, err := d.ReadListItem(memberSchema)
if !ok {
return nil
}
if err != nil {
return err
}
if err := memberFn(); err != nil {
return err
}
}
}
// ReadMap is a utility API for generated clients.
func ReadMap(d ShapeDeserializer, schema *Schema, memberFn func(string) error) error {
if err := d.ReadMap(schema); err != nil {
return err
}
var keySchema *Schema
if schema != nil {
keySchema = schema.MapKey()
}
for {
k, ok, err := d.ReadMapKey(keySchema)
if !ok {
return nil
}
if err != nil {
return err
}
if err := memberFn(k); err != nil {
return err
}
}
}
+53
View File
@@ -0,0 +1,53 @@
package sync
import "sync"
// OnceErr wraps the behavior of recording an error
// once and signal on a channel when this has occurred.
// Signaling is done by closing of the channel.
//
// Type is safe for concurrent usage.
type OnceErr struct {
mu sync.RWMutex
err error
ch chan struct{}
}
// NewOnceErr return a new OnceErr
func NewOnceErr() *OnceErr {
return &OnceErr{
ch: make(chan struct{}, 1),
}
}
// Err acquires a read-lock and returns an
// error if one has been set.
func (e *OnceErr) Err() error {
e.mu.RLock()
err := e.err
e.mu.RUnlock()
return err
}
// SetError acquires a write-lock and will set
// the underlying error value if one has not been set.
func (e *OnceErr) SetError(err error) {
if err == nil {
return
}
e.mu.Lock()
if e.err == nil {
e.err = err
close(e.ch)
}
e.mu.Unlock()
}
// ErrorSet returns a channel that will be used to signal
// that an error has been set. This channel will be closed
// when the error value has been set for OnceErr.
func (e *OnceErr) ErrorSet() <-chan struct{} {
return e.ch
}
+21
View File
@@ -0,0 +1,21 @@
package smithy
// Trait represents a trait applied to a shape in a Smithy model. Traits
// related to (de)serialization are included in code-generated Schemas for the
// client.
type Trait interface {
TraitID() ShapeID
}
// IndexableTrait is optionally implemented by Trait values that have a
// reserved index in Schema's indexed trait slice. All traits defined in the
// traits package implement this interface.
//
// You SHOULD NOT implement this outside of a smithy-go trait unless you know
// what you are doing. If you implement this and return a value that collides
// with one of the primary serde-based indexed traits (see index.go) you will
// probably break something.
type IndexableTrait interface {
Trait
TraitIndex() int
}
+69
View File
@@ -0,0 +1,69 @@
package traits
import smithy "github.com/aws/smithy-go"
// HTTPHeader represents smithy.api#httpHeader.
type HTTPHeader struct {
Name string
}
// TraitID identifies the trait.
func (*HTTPHeader) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "httpHeader"} }
// HTTPLabel represents smithy.api#httpLabel.
type HTTPLabel struct{}
// TraitID identifies the trait.
func (*HTTPLabel) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "httpLabel"} }
// HTTPPayload represents smithy.api#httpPayload.
type HTTPPayload struct{}
// TraitID identifies the trait.
func (*HTTPPayload) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "httpPayload"} }
// HTTPPrefixHeaders represents smithy.api#httpPrefixHeaders.
type HTTPPrefixHeaders struct {
Prefix string
}
// TraitID identifies the trait.
func (*HTTPPrefixHeaders) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "httpPrefixHeaders"} }
// HTTPQuery represents smithy.api#httpQuery.
type HTTPQuery struct {
Name string
}
// TraitID identifies the trait.
func (*HTTPQuery) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "httpQuery"} }
// HTTPQueryParams represents smithy.api#httpQueryParams.
type HTTPQueryParams struct{}
// TraitID identifies the trait.
func (*HTTPQueryParams) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "httpQueryParams"} }
// HTTPResponseCode represents smithy.api#httpResponseCode.
type HTTPResponseCode struct{}
// TraitID identifies the trait.
func (*HTTPResponseCode) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "httpResponseCode"} }
// HTTP represents smithy.api#http.
type HTTP struct {
Method string
URI string
Code int
}
// TraitID identifies the trait.
func (*HTTP) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "http"} }
// HTTPError represents smithy.api#httpError.
type HTTPError struct {
Code int
}
// TraitID identifies the trait.
func (*HTTPError) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "httpError"} }
+107
View File
@@ -0,0 +1,107 @@
package traits
// Trait index constants, ordered by frequency of occurrence across AWS API
// models. Lower indices are assigned to more common traits so that the
// per-schema indexed slice stays small.
const (
indexJSONName = iota
indexHTTP
indexHTTPLabel
indexXMLName
indexHTTPQuery
indexEC2QueryName
indexHTTPError
indexHTTPHeader
indexSensitive
indexAWSQueryError
indexTimestampFormat
indexHTTPPayload
indexContextParam
indexHTTPResponseCode
indexHostLabel
indexXMLNamespace
indexXMLFlattened
indexStreaming
indexMediaType
indexHTTPQueryParams
indexEventPayload
indexHTTPPrefixHeaders
indexEventHeader
indexXMLAttribute
indexUnitShape
)
// TraitIndex implements [smithy.IndexableTrait].
func (*JSONName) TraitIndex() int { return indexJSONName }
// TraitIndex implements [smithy.IndexableTrait].
func (*HTTP) TraitIndex() int { return indexHTTP }
// TraitIndex implements [smithy.IndexableTrait].
func (*HTTPLabel) TraitIndex() int { return indexHTTPLabel }
// TraitIndex implements [smithy.IndexableTrait].
func (*XMLName) TraitIndex() int { return indexXMLName }
// TraitIndex implements [smithy.IndexableTrait].
func (*HTTPQuery) TraitIndex() int { return indexHTTPQuery }
// TraitIndex implements [smithy.IndexableTrait].
func (*EC2QueryName) TraitIndex() int { return indexEC2QueryName }
// TraitIndex implements [smithy.IndexableTrait].
func (*HTTPError) TraitIndex() int { return indexHTTPError }
// TraitIndex implements [smithy.IndexableTrait].
func (*HTTPHeader) TraitIndex() int { return indexHTTPHeader }
// TraitIndex implements [smithy.IndexableTrait].
func (*Sensitive) TraitIndex() int { return indexSensitive }
// TraitIndex implements [smithy.IndexableTrait].
func (*AWSQueryError) TraitIndex() int { return indexAWSQueryError }
// TraitIndex implements [smithy.IndexableTrait].
func (*TimestampFormat) TraitIndex() int { return indexTimestampFormat }
// TraitIndex implements [smithy.IndexableTrait].
func (*HTTPPayload) TraitIndex() int { return indexHTTPPayload }
// TraitIndex implements [smithy.IndexableTrait].
func (*ContextParam) TraitIndex() int { return indexContextParam }
// TraitIndex implements [smithy.IndexableTrait].
func (*HTTPResponseCode) TraitIndex() int { return indexHTTPResponseCode }
// TraitIndex implements [smithy.IndexableTrait].
func (*HostLabel) TraitIndex() int { return indexHostLabel }
// TraitIndex implements [smithy.IndexableTrait].
func (*XMLNamespace) TraitIndex() int { return indexXMLNamespace }
// TraitIndex implements [smithy.IndexableTrait].
func (*XMLFlattened) TraitIndex() int { return indexXMLFlattened }
// TraitIndex implements [smithy.IndexableTrait].
func (*Streaming) TraitIndex() int { return indexStreaming }
// TraitIndex implements [smithy.IndexableTrait].
func (*MediaType) TraitIndex() int { return indexMediaType }
// TraitIndex implements [smithy.IndexableTrait].
func (*HTTPQueryParams) TraitIndex() int { return indexHTTPQueryParams }
// TraitIndex implements [smithy.IndexableTrait].
func (*EventPayload) TraitIndex() int { return indexEventPayload }
// TraitIndex implements [smithy.IndexableTrait].
func (*HTTPPrefixHeaders) TraitIndex() int { return indexHTTPPrefixHeaders }
// TraitIndex implements [smithy.IndexableTrait].
func (*EventHeader) TraitIndex() int { return indexEventHeader }
// TraitIndex implements [smithy.IndexableTrait].
func (*XMLAttribute) TraitIndex() int { return indexXMLAttribute }
// TraitIndex implements [smithy.IndexableTrait].
func (*UnitShape) TraitIndex() int { return indexUnitShape }
+56
View File
@@ -0,0 +1,56 @@
package traits
import smithy "github.com/aws/smithy-go"
// JSONName represents smithy.api#jsonName.
type JSONName struct {
Name string
}
// TraitID identifies the trait.
func (*JSONName) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "jsonName"} }
// MediaType represents smithy.api#mediaType.
type MediaType struct {
Type string
}
// TraitID identifies the trait.
func (*MediaType) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "mediaType"} }
// TimestampFormat represents smithy.api#timestampFormat.
type TimestampFormat struct {
Format string
}
// TraitID identifies the trait.
func (*TimestampFormat) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "timestampFormat"} }
// XMLAttribute represents smithy.api#xmlAttribute.
type XMLAttribute struct{}
// TraitID identifies the trait.
func (*XMLAttribute) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "xmlAttribute"} }
// XMLFlattened represents smithy.api#xmlFlattened.
type XMLFlattened struct{}
// TraitID identifies the trait.
func (*XMLFlattened) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "xmlFlattened"} }
// XMLName represents smithy.api#xmlName.
type XMLName struct {
Name string
}
// TraitID identifies the trait.
func (*XMLName) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "xmlName"} }
// XMLNamespace represents smithy.api#xmlNamespace.
type XMLNamespace struct {
URI string
Prefix string
}
// TraitID identifies the trait.
func (*XMLNamespace) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "xmlNamespace"} }
+72
View File
@@ -0,0 +1,72 @@
// Package traits defines representations of Smithy IDL traits that appear in
// code-generated schemas.
package traits
import smithy "github.com/aws/smithy-go"
// Sensitive represents smithy.api#sensitive.
type Sensitive struct{}
// TraitID identifies the trait.
func (*Sensitive) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "sensitive"} }
// EventHeader represents smithy.api#eventHeader.
type EventHeader struct{}
// TraitID identifies the trait.
func (*EventHeader) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "eventHeader"} }
// EventPayload represents smithy.api#eventPayload.
type EventPayload struct{}
// TraitID identifies the trait.
func (*EventPayload) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "eventPayload"} }
// Streaming represents smithy.api#streaming.
type Streaming struct{}
// TraitID identifies the trait.
func (*Streaming) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "streaming"} }
// HostLabel represents smithy.api#hostLabel.
type HostLabel struct{}
// TraitID identifies the trait.
func (*HostLabel) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.api", Name: "hostLabel"} }
// ContextParam represents smithy.rules#contextParam.
type ContextParam struct{}
// TraitID identifies the trait.
func (*ContextParam) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.rules", Name: "contextParam"} }
// AWSQueryError represents aws.protocols#awsQueryError.
type AWSQueryError struct {
ErrorCode string
StatusCode int
}
// TraitID identifies the trait.
func (*AWSQueryError) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "aws.protocols", Name: "awsQueryError"} }
// EC2QueryName represents aws.protocols#ec2QueryName.
type EC2QueryName struct {
Name string
}
// TraitID identifies the trait.
func (*EC2QueryName) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "aws.protocols", Name: "ec2QueryName"} }
// AWSQueryCompatible represents aws.protocols#awsQueryCompatible.
type AWSQueryCompatible struct{}
// TraitID identifies the trait.
func (*AWSQueryCompatible) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "aws.protocols", Name: "awsQueryCompatible"} }
// UnitShape is a synthetic trait applied to input/output shapes that were
// backfilled from Unit. It indicates the shape has no defined members and
// should be treated as absent for protocol serialization purposes.
type UnitShape struct{}
// TraitID identifies the trait.
func (*UnitShape) TraitID() smithy.ShapeID { return smithy.ShapeID{Namespace: "smithy.go", Name: "unitShape"} }
+9
View File
@@ -5,6 +5,7 @@ import (
smithy "github.com/aws/smithy-go"
"github.com/aws/smithy-go/auth"
"github.com/aws/smithy-go/eventstream"
)
// AuthScheme defines an HTTP authentication scheme.
@@ -19,3 +20,11 @@ type AuthScheme interface {
type Signer interface {
SignRequest(context.Context, *Request, auth.Identity, smithy.Properties) error
}
// EventStreamSigner is an optional interface that a [Signer] can implement to
// support signing of event stream messages. If the resolved auth scheme's
// signer implements this interface, the event stream middleware will use it to
// wrap the outbound message stream with a signing layer.
type EventStreamSigner interface {
NewMessageSigner(ctx context.Context, r *Request, identity auth.Identity, props smithy.Properties) (eventstream.MessageSigner, error)
}
+209
View File
@@ -0,0 +1,209 @@
package http
import (
"context"
"fmt"
"io"
"sync"
"github.com/aws/smithy-go"
smithysync "github.com/aws/smithy-go/sync"
)
// EventStreamWriter writes events to a stream using a ClientProtocol.
//
// The writer manages a background goroutine that facilitates the write loop.
// Calls to Send() on a writer will block until the message has been written.
//
// The writer doesn't know anything about signing. If event stream messages are
// getting signed by the client then the underlying io.Writer has already been
// wrapped to handle that at this point.
type EventStreamWriter struct {
protocol ClientProtocol
schema *smithy.Schema
eventStream io.WriteCloser
stream chan singleflight
done chan struct{}
err *smithysync.OnceErr
closeOnce sync.Once
}
// we send one message at a time, the underlying write loop marshals these into
// the writer and reports back any error to the error channel
type singleflight struct {
variant *smithy.Schema
event smithy.Serializable
errCh chan<- error
}
// NewEventStreamWriter returns an EventStreamWriter for the given schema.
func NewEventStreamWriter(protocol ClientProtocol, schema *smithy.Schema, stream io.WriteCloser) *EventStreamWriter {
w := &EventStreamWriter{
protocol: protocol,
schema: schema,
eventStream: stream,
stream: make(chan singleflight),
done: make(chan struct{}),
err: smithysync.NewOnceErr(),
}
go w.writeStream()
return w
}
func (w *EventStreamWriter) writeStream() {
defer w.Close()
for {
select {
case ev := <-w.stream:
err := w.protocol.SerializeEventMessage(w.schema, ev.variant, ev.event, w.eventStream)
if err != nil {
w.err.SetError(err)
}
ev.errCh <- err
case <-w.done:
return
}
}
}
// Send writes a single event to the stream.
func (w *EventStreamWriter) Send(ctx context.Context, variant *smithy.Schema, event smithy.Serializable) error {
if err := w.err.Err(); err != nil {
return err
}
errCh := make(chan error, 1)
select {
case w.stream <- singleflight{variant, event, errCh}:
case <-ctx.Done():
return ctx.Err()
case <-w.done:
return fmt.Errorf("stream closed, unable to send event")
}
select {
case err := <-errCh:
return err
case <-ctx.Done():
return ctx.Err()
case <-w.done:
return fmt.Errorf("stream closed, unable to send event")
}
}
// Close signals end-of-stream and closes the underlying writer. Close is
// safe for concurrent calls.
func (w *EventStreamWriter) Close() error {
w.closeOnce.Do(func() {
close(w.done)
w.err.SetError(w.eventStream.Close())
})
return w.err.Err()
}
// Err returns the first error encountered during writing.
func (w *EventStreamWriter) Err() error {
return w.err.Err()
}
// ErrorSet returns a channel that is closed when an error occurs.
func (w *EventStreamWriter) ErrorSet() <-chan struct{} {
return w.err.ErrorSet()
}
// EventStreamReader reads events from a stream using a ClientProtocol.
type EventStreamReader struct {
protocol ClientProtocol
schema *smithy.Schema
types *smithy.TypeRegistry
eventStream io.ReadCloser
stream chan smithy.Deserializable
done chan struct{}
err *smithysync.OnceErr
closeOnce sync.Once
}
// NewEventStreamReader returns an EventStreamReader that deserializes events
// through the given protocol from r. The schema is the event stream union
// schema.
func NewEventStreamReader(protocol ClientProtocol, schema *smithy.Schema, types *smithy.TypeRegistry, stream io.ReadCloser) *EventStreamReader {
r := &EventStreamReader{
protocol: protocol,
schema: schema,
types: types,
eventStream: stream,
stream: make(chan smithy.Deserializable),
done: make(chan struct{}),
err: smithysync.NewOnceErr(),
}
go r.readEventStream()
return r
}
func (r *EventStreamReader) readEventStream() {
defer r.Close()
defer close(r.stream)
for {
event, err := r.protocol.DeserializeEventMessage(r.schema, r.types, r.eventStream)
if err != nil {
if err == io.EOF {
return
}
select {
case <-r.done:
return
default:
r.err.SetError(err)
return
}
}
select {
case r.stream <- event:
case <-r.done:
return
}
}
}
// Events returns the channel from which deserialized events can be read.
func (r *EventStreamReader) Events() <-chan smithy.Deserializable {
return r.stream
}
// Close stops the reader and releases the underlying stream. Close is safe
// for concurrent calls.
func (r *EventStreamReader) Close() error {
r.closeOnce.Do(func() {
close(r.done)
r.eventStream.Close()
})
return r.err.Err()
}
// Err returns the first error encountered during reading.
func (r *EventStreamReader) Err() error {
return r.err.Err()
}
// ErrorSet returns a channel that is closed when an error occurs.
func (r *EventStreamReader) ErrorSet() <-chan struct{} {
return r.err.ErrorSet()
}
// Closed returns a channel that is closed when the reader is closed.
func (r *EventStreamReader) Closed() <-chan struct{} {
return r.done
}
@@ -0,0 +1,69 @@
package http
import (
"context"
"fmt"
"io"
"github.com/aws/smithy-go/middleware"
)
type eventStreamWriterKey struct{}
// GetInputStreamWriter returns the io.WriteCloser pipe used for the
// operation's input event stream.
func GetInputStreamWriter(ctx context.Context) io.WriteCloser {
writeCloser, _ := middleware.GetStackValue(ctx, eventStreamWriterKey{}).(io.WriteCloser)
return writeCloser
}
func setInputStreamWriter(ctx context.Context, writeCloser io.WriteCloser) context.Context {
return middleware.WithStackValue(ctx, eventStreamWriterKey{}, writeCloser)
}
// InitializeStreamWriter is a Finalize middleware that creates an in-memory
// pipe and sets it as the HTTP request body so event stream messages can be
// written after the request is sent.
type InitializeStreamWriter struct{}
// AddInitializeStreamWriter adds the InitializeStreamWriter middleware to the
// provided stack.
func AddInitializeStreamWriter(stack *middleware.Stack) error {
return stack.Finalize.Add(&InitializeStreamWriter{}, middleware.After)
}
// ID returns the identifier for the middleware.
func (i *InitializeStreamWriter) ID() string {
return "InitializeStreamWriter"
}
// HandleFinalize is the middleware implementation.
func (i *InitializeStreamWriter) HandleFinalize(
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
) (
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
) {
request, ok := in.Request.(*Request)
if !ok {
return out, metadata, fmt.Errorf("unknown transport type: %T", in.Request)
}
inputReader, inputWriter := io.Pipe()
defer func() {
if err == nil {
return
}
_ = inputReader.Close()
_ = inputWriter.Close()
}()
request, err = request.SetStream(inputReader)
if err != nil {
return out, metadata, err
}
in.Request = request
ctx = setInputStreamWriter(ctx, inputWriter)
return next.HandleFinalize(ctx, in)
}
+27
View File
@@ -0,0 +1,27 @@
package http
import (
"context"
"io"
"github.com/aws/smithy-go"
)
// ClientProtocol defines the interface through which client-side operation
// request/responses are (de)serialized across the wire.
//
// While a caller CAN define their own protocol, it is almost never necessary
// to do so. In practice, a generated client will utilize one of the predefined
// protocols implemented as part of the Smithy client runtime.
type ClientProtocol interface {
ID() smithy.ShapeID
SerializeRequest(context.Context, *smithy.OperationSchema, smithy.Serializable, *Request) error
DeserializeResponse(ctx context.Context, schema *smithy.OperationSchema, types *smithy.TypeRegistry, resp *Response, out smithy.Deserializable) error
// event stream APIs
HasInitialEventMessage() bool
SerializeEventMessage(schema, variant *smithy.Schema, v smithy.Serializable, w io.Writer) error
DeserializeEventMessage(schema *smithy.Schema, types *smithy.TypeRegistry, r io.Reader) (smithy.Deserializable, error)
SerializeInitialRequest(schema *smithy.Schema, v smithy.Serializable, w io.Writer) error
DeserializeInitialResponse(schema *smithy.Schema, r io.Reader, out smithy.Deserializable) error
}
+70
View File
@@ -0,0 +1,70 @@
package smithy
import (
"strings"
)
// TypeRegistry creates an instance of a type based on its Smithy IDL shape ID.
//
// Generated clients have an exported package-level registry (named
// TypeRegistry) that holds all structure types for the service.
type TypeRegistry struct {
Entries map[string]*TypeRegistryEntry
}
// RegistryEntry creates a type registry entry.
func RegistryEntry[T any](schema *Schema) *TypeRegistryEntry {
return &TypeRegistryEntry{
Schema: schema,
New: func() any {
return new(T)
},
}
}
// DeserializableError provides an instance of a deserializable error structure
// for a given shape ID.
//
// The ID is given as a string here since this will be called in a context where
// a shape ID is a discriminator read in from some wire payload.
func (t *TypeRegistry) DeserializableError(id string) (DeserializableError, bool) {
return typeRegistryLookup[DeserializableError](t, id)
}
// LookupEntry returns the registry entry for the given shape ID.
func (t *TypeRegistry) LookupEntry(id string) (*TypeRegistryEntry, bool) {
entry, ok := t.Entries[id]
if !ok {
entry, ok = t.lookupShortName(id)
}
return entry, ok
}
// TypeRegistryEntry holds the schema and constructor for a registered shape.
type TypeRegistryEntry struct {
Schema *Schema
New func() any
}
func (t *TypeRegistry) lookupShortName(id string) (*TypeRegistryEntry, bool) {
for key, e := range t.Entries {
if idx := strings.Index(key, "#"); idx != -1 && key[idx+1:] == id {
return e, true
}
}
return nil, false
}
func typeRegistryLookup[T any](t *TypeRegistry, id string) (T, bool) {
entry, ok := t.Entries[id]
if !ok {
entry, ok = t.lookupShortName(id)
}
if !ok {
var v T
return v, false
}
v, ok := entry.New().(T)
return v, ok
}
+5 -4
View File
@@ -19,8 +19,9 @@ As a containerd sub-project, you will find the:
information in our [`containerd/project`](https://github.com/containerd/project) repository.
## Optional
## Gogo Protobuf Support Deprecation
By default, support for gogoproto is available along side the standard Google
protobuf types.
You can choose to leave gogo support out by using the `!no_gogo` build tag.
Support for gogoprotobuf was removed in v2.3.0. The upstream package has been deprecated since 2022 and users of
typeurl should not rely on Gogo Protobuf support anymore. Users which are still transitioning away from it may
continue to use the v2.2 release until that transition is complete. Since v2.2.1, gogo proto support can be
explicitly removed using the `!no_gogo` build tag.
+4 -41
View File
@@ -32,16 +32,8 @@ import (
var (
mu sync.RWMutex
registry = make(map[reflect.Type]string)
handlers []handler
)
type handler interface {
Marshaller(interface{}) func() ([]byte, error)
Unmarshaller(interface{}) func([]byte) error
TypeURL(interface{}) string
GetType(url string) (reflect.Type, bool)
}
// Definitions of common error types used throughout typeurl.
//
// These error types are used with errors.Wrap and errors.Wrapf to add context
@@ -120,11 +112,6 @@ func TypeURL(v interface{}) (string, error) {
case proto.Message:
return string(t.ProtoReflect().Descriptor().FullName()), nil
default:
for _, h := range handlers {
if u := h.TypeURL(v); u != "" {
return u, nil
}
}
return "", fmt.Errorf("type %s: %w", reflect.TypeOf(v), ErrNotFound)
}
}
@@ -160,18 +147,7 @@ func MarshalAny(v interface{}) (Any, error) {
return proto.Marshal(t)
}
default:
for _, h := range handlers {
if m := h.Marshaller(v); m != nil {
marshal = func(v interface{}) ([]byte, error) {
return m()
}
break
}
}
if marshal == nil {
marshal = json.Marshal
}
marshal = json.Marshal
}
url, err := TypeURL(v)
@@ -261,18 +237,12 @@ func unmarshal(typeURL string, value []byte, v interface{}) (interface{}, error)
if isProto {
pm, ok := v.(proto.Message)
if ok {
return v, proto.Unmarshal(value, pm)
}
for _, h := range handlers {
if unmarshal := h.Unmarshaller(v); unmarshal != nil {
return v, unmarshal(value)
}
err = proto.Unmarshal(value, pm)
return v, err
}
}
// fallback to json unmarshaller
return v, json.Unmarshal(value, v)
}
func getTypeByUrl(url string) (_ reflect.Type, isProto bool, _ error) {
@@ -286,13 +256,6 @@ func getTypeByUrl(url string) (_ reflect.Type, isProto bool, _ error) {
mu.RUnlock()
mt, err := protoregistry.GlobalTypes.FindMessageByURL(url)
if err != nil {
if errors.Is(err, protoregistry.NotFound) {
for _, h := range handlers {
if t, isProto := h.GetType(url); t != nil {
return t, isProto, nil
}
}
}
return nil, false, fmt.Errorf("type with url %s: %w", url, ErrNotFound)
}
empty := mt.New().Interface()
-68
View File
@@ -1,68 +0,0 @@
//go:build !no_gogo
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package typeurl
import (
"reflect"
gogoproto "github.com/gogo/protobuf/proto"
)
func init() {
handlers = append(handlers, gogoHandler{})
}
type gogoHandler struct{}
func (gogoHandler) Marshaller(v interface{}) func() ([]byte, error) {
pm, ok := v.(gogoproto.Message)
if !ok {
return nil
}
return func() ([]byte, error) {
return gogoproto.Marshal(pm)
}
}
func (gogoHandler) Unmarshaller(v interface{}) func([]byte) error {
pm, ok := v.(gogoproto.Message)
if !ok {
return nil
}
return func(dt []byte) error {
return gogoproto.Unmarshal(dt, pm)
}
}
func (gogoHandler) TypeURL(v interface{}) string {
pm, ok := v.(gogoproto.Message)
if !ok {
return ""
}
return gogoproto.MessageName(pm)
}
func (gogoHandler) GetType(url string) (reflect.Type, bool) {
t := gogoproto.MessageType(url)
if t == nil {
return nil, false
}
return t.Elem(), true
}
-15
View File
@@ -1,15 +0,0 @@
# This is the official list of GoGo authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS file, which
# lists people. For example, employees are listed in CONTRIBUTORS,
# but not in AUTHORS, because the employer holds the copyright.
# Names should be added to this file as one of
# Organization's name
# Individual's name <submission email address>
# Individual's name <submission email address> <email2> <emailN>
# Please keep the list sorted.
Sendgrid, Inc
Vastech SA (PTY) LTD
Walter Schulze <awalterschulze@gmail.com>
-23
View File
@@ -1,23 +0,0 @@
Anton Povarov <anton.povarov@gmail.com>
Brian Goff <cpuguy83@gmail.com>
Clayton Coleman <ccoleman@redhat.com>
Denis Smirnov <denis.smirnov.91@gmail.com>
DongYun Kang <ceram1000@gmail.com>
Dwayne Schultz <dschultz@pivotal.io>
Georg Apitz <gapitz@pivotal.io>
Gustav Paul <gustav.paul@gmail.com>
Johan Brandhorst <johan.brandhorst@gmail.com>
John Shahid <jvshahid@gmail.com>
John Tuley <john@tuley.org>
Laurent <laurent@adyoulike.com>
Patrick Lee <patrick@dropbox.com>
Peter Edge <peter.edge@gmail.com>
Roger Johansson <rogeralsing@gmail.com>
Sam Nguyen <sam.nguyen@sendgrid.com>
Sergio Arbeo <serabe@gmail.com>
Stephen J Day <stephen.day@docker.com>
Tamir Duberstein <tamird@gmail.com>
Todd Eisenberger <teisenberger@dropbox.com>
Tormod Erevik Lea <tormodlea@gmail.com>
Vyacheslav Kim <kane@sendgrid.com>
Walter Schulze <awalterschulze@gmail.com>
-35
View File
@@ -1,35 +0,0 @@
Copyright (c) 2013, The GoGo Authors. All rights reserved.
Protocol Buffers for Go with Gadgets
Go support for Protocol Buffers - Google's data interchange format
Copyright 2010 The Go Authors. All rights reserved.
https://github.com/golang/protobuf
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-43
View File
@@ -1,43 +0,0 @@
# Go support for Protocol Buffers - Google's data interchange format
#
# Copyright 2010 The Go Authors. All rights reserved.
# https://github.com/golang/protobuf
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
install:
go install
test: install generate-test-pbs
go test
generate-test-pbs:
make install
make -C test_proto
make -C proto3_proto
make
-258
View File
@@ -1,258 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2011 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Protocol buffer deep copy and merge.
// TODO: RawMessage.
package proto
import (
"fmt"
"log"
"reflect"
"strings"
)
// Clone returns a deep copy of a protocol buffer.
func Clone(src Message) Message {
in := reflect.ValueOf(src)
if in.IsNil() {
return src
}
out := reflect.New(in.Type().Elem())
dst := out.Interface().(Message)
Merge(dst, src)
return dst
}
// Merger is the interface representing objects that can merge messages of the same type.
type Merger interface {
// Merge merges src into this message.
// Required and optional fields that are set in src will be set to that value in dst.
// Elements of repeated fields will be appended.
//
// Merge may panic if called with a different argument type than the receiver.
Merge(src Message)
}
// generatedMerger is the custom merge method that generated protos will have.
// We must add this method since a generate Merge method will conflict with
// many existing protos that have a Merge data field already defined.
type generatedMerger interface {
XXX_Merge(src Message)
}
// Merge merges src into dst.
// Required and optional fields that are set in src will be set to that value in dst.
// Elements of repeated fields will be appended.
// Merge panics if src and dst are not the same type, or if dst is nil.
func Merge(dst, src Message) {
if m, ok := dst.(Merger); ok {
m.Merge(src)
return
}
in := reflect.ValueOf(src)
out := reflect.ValueOf(dst)
if out.IsNil() {
panic("proto: nil destination")
}
if in.Type() != out.Type() {
panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src))
}
if in.IsNil() {
return // Merge from nil src is a noop
}
if m, ok := dst.(generatedMerger); ok {
m.XXX_Merge(src)
return
}
mergeStruct(out.Elem(), in.Elem())
}
func mergeStruct(out, in reflect.Value) {
sprop := GetProperties(in.Type())
for i := 0; i < in.NumField(); i++ {
f := in.Type().Field(i)
if strings.HasPrefix(f.Name, "XXX_") {
continue
}
mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i])
}
if emIn, ok := in.Addr().Interface().(extensionsBytes); ok {
emOut := out.Addr().Interface().(extensionsBytes)
bIn := emIn.GetExtensions()
bOut := emOut.GetExtensions()
*bOut = append(*bOut, *bIn...)
} else if emIn, err := extendable(in.Addr().Interface()); err == nil {
emOut, _ := extendable(out.Addr().Interface())
mIn, muIn := emIn.extensionsRead()
if mIn != nil {
mOut := emOut.extensionsWrite()
muIn.Lock()
mergeExtension(mOut, mIn)
muIn.Unlock()
}
}
uf := in.FieldByName("XXX_unrecognized")
if !uf.IsValid() {
return
}
uin := uf.Bytes()
if len(uin) > 0 {
out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...))
}
}
// mergeAny performs a merge between two values of the same type.
// viaPtr indicates whether the values were indirected through a pointer (implying proto2).
// prop is set if this is a struct field (it may be nil).
func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) {
if in.Type() == protoMessageType {
if !in.IsNil() {
if out.IsNil() {
out.Set(reflect.ValueOf(Clone(in.Interface().(Message))))
} else {
Merge(out.Interface().(Message), in.Interface().(Message))
}
}
return
}
switch in.Kind() {
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
reflect.String, reflect.Uint32, reflect.Uint64:
if !viaPtr && isProto3Zero(in) {
return
}
out.Set(in)
case reflect.Interface:
// Probably a oneof field; copy non-nil values.
if in.IsNil() {
return
}
// Allocate destination if it is not set, or set to a different type.
// Otherwise we will merge as normal.
if out.IsNil() || out.Elem().Type() != in.Elem().Type() {
out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T)
}
mergeAny(out.Elem(), in.Elem(), false, nil)
case reflect.Map:
if in.Len() == 0 {
return
}
if out.IsNil() {
out.Set(reflect.MakeMap(in.Type()))
}
// For maps with value types of *T or []byte we need to deep copy each value.
elemKind := in.Type().Elem().Kind()
for _, key := range in.MapKeys() {
var val reflect.Value
switch elemKind {
case reflect.Ptr:
val = reflect.New(in.Type().Elem().Elem())
mergeAny(val, in.MapIndex(key), false, nil)
case reflect.Slice:
val = in.MapIndex(key)
val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
default:
val = in.MapIndex(key)
}
out.SetMapIndex(key, val)
}
case reflect.Ptr:
if in.IsNil() {
return
}
if out.IsNil() {
out.Set(reflect.New(in.Elem().Type()))
}
mergeAny(out.Elem(), in.Elem(), true, nil)
case reflect.Slice:
if in.IsNil() {
return
}
if in.Type().Elem().Kind() == reflect.Uint8 {
// []byte is a scalar bytes field, not a repeated field.
// Edge case: if this is in a proto3 message, a zero length
// bytes field is considered the zero value, and should not
// be merged.
if prop != nil && prop.proto3 && in.Len() == 0 {
return
}
// Make a deep copy.
// Append to []byte{} instead of []byte(nil) so that we never end up
// with a nil result.
out.SetBytes(append([]byte{}, in.Bytes()...))
return
}
n := in.Len()
if out.IsNil() {
out.Set(reflect.MakeSlice(in.Type(), 0, n))
}
switch in.Type().Elem().Kind() {
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
reflect.String, reflect.Uint32, reflect.Uint64:
out.Set(reflect.AppendSlice(out, in))
default:
for i := 0; i < n; i++ {
x := reflect.Indirect(reflect.New(in.Type().Elem()))
mergeAny(x, in.Index(i), false, nil)
out.Set(reflect.Append(out, x))
}
}
case reflect.Struct:
mergeStruct(out, in)
default:
// unknown type, so not a protocol buffer
log.Printf("proto: don't know how to copy %v", in)
}
}
func mergeExtension(out, in map[int32]Extension) {
for extNum, eIn := range in {
eOut := Extension{desc: eIn.desc}
if eIn.value != nil {
v := reflect.New(reflect.TypeOf(eIn.value)).Elem()
mergeAny(v, reflect.ValueOf(eIn.value), false, nil)
eOut.value = v.Interface()
}
if eIn.enc != nil {
eOut.enc = make([]byte, len(eIn.enc))
copy(eOut.enc, eIn.enc)
}
out[extNum] = eOut
}
}
-39
View File
@@ -1,39 +0,0 @@
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2018, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
import "reflect"
type custom interface {
Marshal() ([]byte, error)
Unmarshal(data []byte) error
Size() int
}
var customType = reflect.TypeOf((*custom)(nil)).Elem()
-427
View File
@@ -1,427 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2010 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
/*
* Routines for decoding protocol buffer data to construct in-memory representations.
*/
import (
"errors"
"fmt"
"io"
)
// errOverflow is returned when an integer is too large to be represented.
var errOverflow = errors.New("proto: integer overflow")
// ErrInternalBadWireType is returned by generated code when an incorrect
// wire type is encountered. It does not get returned to user code.
var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")
// DecodeVarint reads a varint-encoded integer from the slice.
// It returns the integer and the number of bytes consumed, or
// zero if there is not enough.
// This is the format for the
// int32, int64, uint32, uint64, bool, and enum
// protocol buffer types.
func DecodeVarint(buf []byte) (x uint64, n int) {
for shift := uint(0); shift < 64; shift += 7 {
if n >= len(buf) {
return 0, 0
}
b := uint64(buf[n])
n++
x |= (b & 0x7F) << shift
if (b & 0x80) == 0 {
return x, n
}
}
// The number is too large to represent in a 64-bit value.
return 0, 0
}
func (p *Buffer) decodeVarintSlow() (x uint64, err error) {
i := p.index
l := len(p.buf)
for shift := uint(0); shift < 64; shift += 7 {
if i >= l {
err = io.ErrUnexpectedEOF
return
}
b := p.buf[i]
i++
x |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
p.index = i
return
}
}
// The number is too large to represent in a 64-bit value.
err = errOverflow
return
}
// DecodeVarint reads a varint-encoded integer from the Buffer.
// This is the format for the
// int32, int64, uint32, uint64, bool, and enum
// protocol buffer types.
func (p *Buffer) DecodeVarint() (x uint64, err error) {
i := p.index
buf := p.buf
if i >= len(buf) {
return 0, io.ErrUnexpectedEOF
} else if buf[i] < 0x80 {
p.index++
return uint64(buf[i]), nil
} else if len(buf)-i < 10 {
return p.decodeVarintSlow()
}
var b uint64
// we already checked the first byte
x = uint64(buf[i]) - 0x80
i++
b = uint64(buf[i])
i++
x += b << 7
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 7
b = uint64(buf[i])
i++
x += b << 14
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 14
b = uint64(buf[i])
i++
x += b << 21
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 21
b = uint64(buf[i])
i++
x += b << 28
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 28
b = uint64(buf[i])
i++
x += b << 35
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 35
b = uint64(buf[i])
i++
x += b << 42
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 42
b = uint64(buf[i])
i++
x += b << 49
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 49
b = uint64(buf[i])
i++
x += b << 56
if b&0x80 == 0 {
goto done
}
x -= 0x80 << 56
b = uint64(buf[i])
i++
x += b << 63
if b&0x80 == 0 {
goto done
}
return 0, errOverflow
done:
p.index = i
return x, nil
}
// DecodeFixed64 reads a 64-bit integer from the Buffer.
// This is the format for the
// fixed64, sfixed64, and double protocol buffer types.
func (p *Buffer) DecodeFixed64() (x uint64, err error) {
// x, err already 0
i := p.index + 8
if i < 0 || i > len(p.buf) {
err = io.ErrUnexpectedEOF
return
}
p.index = i
x = uint64(p.buf[i-8])
x |= uint64(p.buf[i-7]) << 8
x |= uint64(p.buf[i-6]) << 16
x |= uint64(p.buf[i-5]) << 24
x |= uint64(p.buf[i-4]) << 32
x |= uint64(p.buf[i-3]) << 40
x |= uint64(p.buf[i-2]) << 48
x |= uint64(p.buf[i-1]) << 56
return
}
// DecodeFixed32 reads a 32-bit integer from the Buffer.
// This is the format for the
// fixed32, sfixed32, and float protocol buffer types.
func (p *Buffer) DecodeFixed32() (x uint64, err error) {
// x, err already 0
i := p.index + 4
if i < 0 || i > len(p.buf) {
err = io.ErrUnexpectedEOF
return
}
p.index = i
x = uint64(p.buf[i-4])
x |= uint64(p.buf[i-3]) << 8
x |= uint64(p.buf[i-2]) << 16
x |= uint64(p.buf[i-1]) << 24
return
}
// DecodeZigzag64 reads a zigzag-encoded 64-bit integer
// from the Buffer.
// This is the format used for the sint64 protocol buffer type.
func (p *Buffer) DecodeZigzag64() (x uint64, err error) {
x, err = p.DecodeVarint()
if err != nil {
return
}
x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63)
return
}
// DecodeZigzag32 reads a zigzag-encoded 32-bit integer
// from the Buffer.
// This is the format used for the sint32 protocol buffer type.
func (p *Buffer) DecodeZigzag32() (x uint64, err error) {
x, err = p.DecodeVarint()
if err != nil {
return
}
x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31))
return
}
// DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
// This is the format used for the bytes protocol buffer
// type and for embedded messages.
func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) {
n, err := p.DecodeVarint()
if err != nil {
return nil, err
}
nb := int(n)
if nb < 0 {
return nil, fmt.Errorf("proto: bad byte length %d", nb)
}
end := p.index + nb
if end < p.index || end > len(p.buf) {
return nil, io.ErrUnexpectedEOF
}
if !alloc {
// todo: check if can get more uses of alloc=false
buf = p.buf[p.index:end]
p.index += nb
return
}
buf = make([]byte, nb)
copy(buf, p.buf[p.index:])
p.index += nb
return
}
// DecodeStringBytes reads an encoded string from the Buffer.
// This is the format used for the proto2 string type.
func (p *Buffer) DecodeStringBytes() (s string, err error) {
buf, err := p.DecodeRawBytes(false)
if err != nil {
return
}
return string(buf), nil
}
// Unmarshaler is the interface representing objects that can
// unmarshal themselves. The argument points to data that may be
// overwritten, so implementations should not keep references to the
// buffer.
// Unmarshal implementations should not clear the receiver.
// Any unmarshaled data should be merged into the receiver.
// Callers of Unmarshal that do not want to retain existing data
// should Reset the receiver before calling Unmarshal.
type Unmarshaler interface {
Unmarshal([]byte) error
}
// newUnmarshaler is the interface representing objects that can
// unmarshal themselves. The semantics are identical to Unmarshaler.
//
// This exists to support protoc-gen-go generated messages.
// The proto package will stop type-asserting to this interface in the future.
//
// DO NOT DEPEND ON THIS.
type newUnmarshaler interface {
XXX_Unmarshal([]byte) error
}
// Unmarshal parses the protocol buffer representation in buf and places the
// decoded result in pb. If the struct underlying pb does not match
// the data in buf, the results can be unpredictable.
//
// Unmarshal resets pb before starting to unmarshal, so any
// existing data in pb is always removed. Use UnmarshalMerge
// to preserve and append to existing data.
func Unmarshal(buf []byte, pb Message) error {
pb.Reset()
if u, ok := pb.(newUnmarshaler); ok {
return u.XXX_Unmarshal(buf)
}
if u, ok := pb.(Unmarshaler); ok {
return u.Unmarshal(buf)
}
return NewBuffer(buf).Unmarshal(pb)
}
// UnmarshalMerge parses the protocol buffer representation in buf and
// writes the decoded result to pb. If the struct underlying pb does not match
// the data in buf, the results can be unpredictable.
//
// UnmarshalMerge merges into existing data in pb.
// Most code should use Unmarshal instead.
func UnmarshalMerge(buf []byte, pb Message) error {
if u, ok := pb.(newUnmarshaler); ok {
return u.XXX_Unmarshal(buf)
}
if u, ok := pb.(Unmarshaler); ok {
// NOTE: The history of proto have unfortunately been inconsistent
// whether Unmarshaler should or should not implicitly clear itself.
// Some implementations do, most do not.
// Thus, calling this here may or may not do what people want.
//
// See https://github.com/golang/protobuf/issues/424
return u.Unmarshal(buf)
}
return NewBuffer(buf).Unmarshal(pb)
}
// DecodeMessage reads a count-delimited message from the Buffer.
func (p *Buffer) DecodeMessage(pb Message) error {
enc, err := p.DecodeRawBytes(false)
if err != nil {
return err
}
return NewBuffer(enc).Unmarshal(pb)
}
// DecodeGroup reads a tag-delimited group from the Buffer.
// StartGroup tag is already consumed. This function consumes
// EndGroup tag.
func (p *Buffer) DecodeGroup(pb Message) error {
b := p.buf[p.index:]
x, y := findEndGroup(b)
if x < 0 {
return io.ErrUnexpectedEOF
}
err := Unmarshal(b[:x], pb)
p.index += y
return err
}
// Unmarshal parses the protocol buffer representation in the
// Buffer and places the decoded result in pb. If the struct
// underlying pb does not match the data in the buffer, the results can be
// unpredictable.
//
// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal.
func (p *Buffer) Unmarshal(pb Message) error {
// If the object can unmarshal itself, let it.
if u, ok := pb.(newUnmarshaler); ok {
err := u.XXX_Unmarshal(p.buf[p.index:])
p.index = len(p.buf)
return err
}
if u, ok := pb.(Unmarshaler); ok {
// NOTE: The history of proto have unfortunately been inconsistent
// whether Unmarshaler should or should not implicitly clear itself.
// Some implementations do, most do not.
// Thus, calling this here may or may not do what people want.
//
// See https://github.com/golang/protobuf/issues/424
err := u.Unmarshal(p.buf[p.index:])
p.index = len(p.buf)
return err
}
// Slow workaround for messages that aren't Unmarshalers.
// This includes some hand-coded .pb.go files and
// bootstrap protos.
// TODO: fix all of those and then add Unmarshal to
// the Message interface. Then:
// The cast above and code below can be deleted.
// The old unmarshaler can be deleted.
// Clients can call Unmarshal directly (can already do that, actually).
var info InternalMessageInfo
err := info.Unmarshal(pb, p.buf[p.index:])
p.index = len(p.buf)
return err
}
-63
View File
@@ -1,63 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2018 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
import "errors"
// Deprecated: do not use.
type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 }
// Deprecated: do not use.
func GetStats() Stats { return Stats{} }
// Deprecated: do not use.
func MarshalMessageSet(interface{}) ([]byte, error) {
return nil, errors.New("proto: not implemented")
}
// Deprecated: do not use.
func UnmarshalMessageSet([]byte, interface{}) error {
return errors.New("proto: not implemented")
}
// Deprecated: do not use.
func MarshalMessageSetJSON(interface{}) ([]byte, error) {
return nil, errors.New("proto: not implemented")
}
// Deprecated: do not use.
func UnmarshalMessageSetJSON([]byte, interface{}) error {
return errors.New("proto: not implemented")
}
// Deprecated: do not use.
func RegisterMessageSetType(Message, int32, string) {}
-350
View File
@@ -1,350 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2017 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
import (
"fmt"
"reflect"
"strings"
"sync"
"sync/atomic"
)
type generatedDiscarder interface {
XXX_DiscardUnknown()
}
// DiscardUnknown recursively discards all unknown fields from this message
// and all embedded messages.
//
// When unmarshaling a message with unrecognized fields, the tags and values
// of such fields are preserved in the Message. This allows a later call to
// marshal to be able to produce a message that continues to have those
// unrecognized fields. To avoid this, DiscardUnknown is used to
// explicitly clear the unknown fields after unmarshaling.
//
// For proto2 messages, the unknown fields of message extensions are only
// discarded from messages that have been accessed via GetExtension.
func DiscardUnknown(m Message) {
if m, ok := m.(generatedDiscarder); ok {
m.XXX_DiscardUnknown()
return
}
// TODO: Dynamically populate a InternalMessageInfo for legacy messages,
// but the master branch has no implementation for InternalMessageInfo,
// so it would be more work to replicate that approach.
discardLegacy(m)
}
// DiscardUnknown recursively discards all unknown fields.
func (a *InternalMessageInfo) DiscardUnknown(m Message) {
di := atomicLoadDiscardInfo(&a.discard)
if di == nil {
di = getDiscardInfo(reflect.TypeOf(m).Elem())
atomicStoreDiscardInfo(&a.discard, di)
}
di.discard(toPointer(&m))
}
type discardInfo struct {
typ reflect.Type
initialized int32 // 0: only typ is valid, 1: everything is valid
lock sync.Mutex
fields []discardFieldInfo
unrecognized field
}
type discardFieldInfo struct {
field field // Offset of field, guaranteed to be valid
discard func(src pointer)
}
var (
discardInfoMap = map[reflect.Type]*discardInfo{}
discardInfoLock sync.Mutex
)
func getDiscardInfo(t reflect.Type) *discardInfo {
discardInfoLock.Lock()
defer discardInfoLock.Unlock()
di := discardInfoMap[t]
if di == nil {
di = &discardInfo{typ: t}
discardInfoMap[t] = di
}
return di
}
func (di *discardInfo) discard(src pointer) {
if src.isNil() {
return // Nothing to do.
}
if atomic.LoadInt32(&di.initialized) == 0 {
di.computeDiscardInfo()
}
for _, fi := range di.fields {
sfp := src.offset(fi.field)
fi.discard(sfp)
}
// For proto2 messages, only discard unknown fields in message extensions
// that have been accessed via GetExtension.
if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil {
// Ignore lock since DiscardUnknown is not concurrency safe.
emm, _ := em.extensionsRead()
for _, mx := range emm {
if m, ok := mx.value.(Message); ok {
DiscardUnknown(m)
}
}
}
if di.unrecognized.IsValid() {
*src.offset(di.unrecognized).toBytes() = nil
}
}
func (di *discardInfo) computeDiscardInfo() {
di.lock.Lock()
defer di.lock.Unlock()
if di.initialized != 0 {
return
}
t := di.typ
n := t.NumField()
for i := 0; i < n; i++ {
f := t.Field(i)
if strings.HasPrefix(f.Name, "XXX_") {
continue
}
dfi := discardFieldInfo{field: toField(&f)}
tf := f.Type
// Unwrap tf to get its most basic type.
var isPointer, isSlice bool
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
isSlice = true
tf = tf.Elem()
}
if tf.Kind() == reflect.Ptr {
isPointer = true
tf = tf.Elem()
}
if isPointer && isSlice && tf.Kind() != reflect.Struct {
panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name))
}
switch tf.Kind() {
case reflect.Struct:
switch {
case !isPointer:
panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name))
case isSlice: // E.g., []*pb.T
discardInfo := getDiscardInfo(tf)
dfi.discard = func(src pointer) {
sps := src.getPointerSlice()
for _, sp := range sps {
if !sp.isNil() {
discardInfo.discard(sp)
}
}
}
default: // E.g., *pb.T
discardInfo := getDiscardInfo(tf)
dfi.discard = func(src pointer) {
sp := src.getPointer()
if !sp.isNil() {
discardInfo.discard(sp)
}
}
}
case reflect.Map:
switch {
case isPointer || isSlice:
panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name))
default: // E.g., map[K]V
if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T)
dfi.discard = func(src pointer) {
sm := src.asPointerTo(tf).Elem()
if sm.Len() == 0 {
return
}
for _, key := range sm.MapKeys() {
val := sm.MapIndex(key)
DiscardUnknown(val.Interface().(Message))
}
}
} else {
dfi.discard = func(pointer) {} // Noop
}
}
case reflect.Interface:
// Must be oneof field.
switch {
case isPointer || isSlice:
panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name))
default: // E.g., interface{}
// TODO: Make this faster?
dfi.discard = func(src pointer) {
su := src.asPointerTo(tf).Elem()
if !su.IsNil() {
sv := su.Elem().Elem().Field(0)
if sv.Kind() == reflect.Ptr && sv.IsNil() {
return
}
switch sv.Type().Kind() {
case reflect.Ptr: // Proto struct (e.g., *T)
DiscardUnknown(sv.Interface().(Message))
}
}
}
}
default:
continue
}
di.fields = append(di.fields, dfi)
}
di.unrecognized = invalidField
if f, ok := t.FieldByName("XXX_unrecognized"); ok {
if f.Type != reflect.TypeOf([]byte{}) {
panic("expected XXX_unrecognized to be of type []byte")
}
di.unrecognized = toField(&f)
}
atomic.StoreInt32(&di.initialized, 1)
}
func discardLegacy(m Message) {
v := reflect.ValueOf(m)
if v.Kind() != reflect.Ptr || v.IsNil() {
return
}
v = v.Elem()
if v.Kind() != reflect.Struct {
return
}
t := v.Type()
for i := 0; i < v.NumField(); i++ {
f := t.Field(i)
if strings.HasPrefix(f.Name, "XXX_") {
continue
}
vf := v.Field(i)
tf := f.Type
// Unwrap tf to get its most basic type.
var isPointer, isSlice bool
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
isSlice = true
tf = tf.Elem()
}
if tf.Kind() == reflect.Ptr {
isPointer = true
tf = tf.Elem()
}
if isPointer && isSlice && tf.Kind() != reflect.Struct {
panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name))
}
switch tf.Kind() {
case reflect.Struct:
switch {
case !isPointer:
panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name))
case isSlice: // E.g., []*pb.T
for j := 0; j < vf.Len(); j++ {
discardLegacy(vf.Index(j).Interface().(Message))
}
default: // E.g., *pb.T
discardLegacy(vf.Interface().(Message))
}
case reflect.Map:
switch {
case isPointer || isSlice:
panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name))
default: // E.g., map[K]V
tv := vf.Type().Elem()
if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T)
for _, key := range vf.MapKeys() {
val := vf.MapIndex(key)
discardLegacy(val.Interface().(Message))
}
}
}
case reflect.Interface:
// Must be oneof field.
switch {
case isPointer || isSlice:
panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name))
default: // E.g., test_proto.isCommunique_Union interface
if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" {
vf = vf.Elem() // E.g., *test_proto.Communique_Msg
if !vf.IsNil() {
vf = vf.Elem() // E.g., test_proto.Communique_Msg
vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value
if vf.Kind() == reflect.Ptr {
discardLegacy(vf.Interface().(Message))
}
}
}
}
}
}
if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() {
if vf.Type() != reflect.TypeOf([]byte{}) {
panic("expected XXX_unrecognized to be of type []byte")
}
vf.Set(reflect.ValueOf([]byte(nil)))
}
// For proto2 messages, only discard unknown fields in message extensions
// that have been accessed via GetExtension.
if em, err := extendable(m); err == nil {
// Ignore lock since discardLegacy is not concurrency safe.
emm, _ := em.extensionsRead()
for _, mx := range emm {
if m, ok := mx.value.(Message); ok {
discardLegacy(m)
}
}
}
}
-100
View File
@@ -1,100 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
// This file implements conversions between google.protobuf.Duration
// and time.Duration.
import (
"errors"
"fmt"
"time"
)
const (
// Range of a Duration in seconds, as specified in
// google/protobuf/duration.proto. This is about 10,000 years in seconds.
maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
minSeconds = -maxSeconds
)
// validateDuration determines whether the Duration is valid according to the
// definition in google/protobuf/duration.proto. A valid Duration
// may still be too large to fit into a time.Duration (the range of Duration
// is about 10,000 years, and the range of time.Duration is about 290).
func validateDuration(d *duration) error {
if d == nil {
return errors.New("duration: nil Duration")
}
if d.Seconds < minSeconds || d.Seconds > maxSeconds {
return fmt.Errorf("duration: %#v: seconds out of range", d)
}
if d.Nanos <= -1e9 || d.Nanos >= 1e9 {
return fmt.Errorf("duration: %#v: nanos out of range", d)
}
// Seconds and Nanos must have the same sign, unless d.Nanos is zero.
if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) {
return fmt.Errorf("duration: %#v: seconds and nanos have different signs", d)
}
return nil
}
// DurationFromProto converts a Duration to a time.Duration. DurationFromProto
// returns an error if the Duration is invalid or is too large to be
// represented in a time.Duration.
func durationFromProto(p *duration) (time.Duration, error) {
if err := validateDuration(p); err != nil {
return 0, err
}
d := time.Duration(p.Seconds) * time.Second
if int64(d/time.Second) != p.Seconds {
return 0, fmt.Errorf("duration: %#v is out of range for time.Duration", p)
}
if p.Nanos != 0 {
d += time.Duration(p.Nanos)
if (d < 0) != (p.Nanos < 0) {
return 0, fmt.Errorf("duration: %#v is out of range for time.Duration", p)
}
}
return d, nil
}
// DurationProto converts a time.Duration to a Duration.
func durationProto(d time.Duration) *duration {
nanos := d.Nanoseconds()
secs := nanos / 1e9
nanos -= secs * 1e9
return &duration{
Seconds: secs,
Nanos: int32(nanos),
}
}
-49
View File
@@ -1,49 +0,0 @@
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2016, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
import (
"reflect"
"time"
)
var durationType = reflect.TypeOf((*time.Duration)(nil)).Elem()
type duration struct {
Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
}
func (m *duration) Reset() { *m = duration{} }
func (*duration) ProtoMessage() {}
func (*duration) String() string { return "duration<string>" }
func init() {
RegisterType((*duration)(nil), "gogo.protobuf.proto.duration")
}
-205
View File
@@ -1,205 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2010 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
/*
* Routines for encoding data into the wire format for protocol buffers.
*/
import (
"errors"
"reflect"
)
var (
// errRepeatedHasNil is the error returned if Marshal is called with
// a struct with a repeated field containing a nil element.
errRepeatedHasNil = errors.New("proto: repeated field has nil element")
// errOneofHasNil is the error returned if Marshal is called with
// a struct with a oneof field containing a nil element.
errOneofHasNil = errors.New("proto: oneof field has nil value")
// ErrNil is the error returned if Marshal is called with nil.
ErrNil = errors.New("proto: Marshal called with nil")
// ErrTooLarge is the error returned if Marshal is called with a
// message that encodes to >2GB.
ErrTooLarge = errors.New("proto: message encodes to over 2 GB")
)
// The fundamental encoders that put bytes on the wire.
// Those that take integer types all accept uint64 and are
// therefore of type valueEncoder.
const maxVarintBytes = 10 // maximum length of a varint
// EncodeVarint returns the varint encoding of x.
// This is the format for the
// int32, int64, uint32, uint64, bool, and enum
// protocol buffer types.
// Not used by the package itself, but helpful to clients
// wishing to use the same encoding.
func EncodeVarint(x uint64) []byte {
var buf [maxVarintBytes]byte
var n int
for n = 0; x > 127; n++ {
buf[n] = 0x80 | uint8(x&0x7F)
x >>= 7
}
buf[n] = uint8(x)
n++
return buf[0:n]
}
// EncodeVarint writes a varint-encoded integer to the Buffer.
// This is the format for the
// int32, int64, uint32, uint64, bool, and enum
// protocol buffer types.
func (p *Buffer) EncodeVarint(x uint64) error {
for x >= 1<<7 {
p.buf = append(p.buf, uint8(x&0x7f|0x80))
x >>= 7
}
p.buf = append(p.buf, uint8(x))
return nil
}
// SizeVarint returns the varint encoding size of an integer.
func SizeVarint(x uint64) int {
switch {
case x < 1<<7:
return 1
case x < 1<<14:
return 2
case x < 1<<21:
return 3
case x < 1<<28:
return 4
case x < 1<<35:
return 5
case x < 1<<42:
return 6
case x < 1<<49:
return 7
case x < 1<<56:
return 8
case x < 1<<63:
return 9
}
return 10
}
// EncodeFixed64 writes a 64-bit integer to the Buffer.
// This is the format for the
// fixed64, sfixed64, and double protocol buffer types.
func (p *Buffer) EncodeFixed64(x uint64) error {
p.buf = append(p.buf,
uint8(x),
uint8(x>>8),
uint8(x>>16),
uint8(x>>24),
uint8(x>>32),
uint8(x>>40),
uint8(x>>48),
uint8(x>>56))
return nil
}
// EncodeFixed32 writes a 32-bit integer to the Buffer.
// This is the format for the
// fixed32, sfixed32, and float protocol buffer types.
func (p *Buffer) EncodeFixed32(x uint64) error {
p.buf = append(p.buf,
uint8(x),
uint8(x>>8),
uint8(x>>16),
uint8(x>>24))
return nil
}
// EncodeZigzag64 writes a zigzag-encoded 64-bit integer
// to the Buffer.
// This is the format used for the sint64 protocol buffer type.
func (p *Buffer) EncodeZigzag64(x uint64) error {
// use signed number to get arithmetic right shift.
return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
// EncodeZigzag32 writes a zigzag-encoded 32-bit integer
// to the Buffer.
// This is the format used for the sint32 protocol buffer type.
func (p *Buffer) EncodeZigzag32(x uint64) error {
// use signed number to get arithmetic right shift.
return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31))))
}
// EncodeRawBytes writes a count-delimited byte buffer to the Buffer.
// This is the format used for the bytes protocol buffer
// type and for embedded messages.
func (p *Buffer) EncodeRawBytes(b []byte) error {
p.EncodeVarint(uint64(len(b)))
p.buf = append(p.buf, b...)
return nil
}
// EncodeStringBytes writes an encoded string to the Buffer.
// This is the format used for the proto2 string type.
func (p *Buffer) EncodeStringBytes(s string) error {
p.EncodeVarint(uint64(len(s)))
p.buf = append(p.buf, s...)
return nil
}
// Marshaler is the interface representing objects that can marshal themselves.
type Marshaler interface {
Marshal() ([]byte, error)
}
// EncodeMessage writes the protocol buffer to the Buffer,
// prefixed by a varint-encoded length.
func (p *Buffer) EncodeMessage(pb Message) error {
siz := Size(pb)
sizVar := SizeVarint(uint64(siz))
p.grow(siz + sizVar)
p.EncodeVarint(uint64(siz))
return p.Marshal(pb)
}
// All protocol buffer fields are nillable, but be careful.
func isNil(v reflect.Value) bool {
switch v.Kind() {
case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return v.IsNil()
}
return false
}
-33
View File
@@ -1,33 +0,0 @@
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
func NewRequiredNotSetError(field string) *RequiredNotSetError {
return &RequiredNotSetError{field}
}
-300
View File
@@ -1,300 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2011 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Protocol buffer comparison.
package proto
import (
"bytes"
"log"
"reflect"
"strings"
)
/*
Equal returns true iff protocol buffers a and b are equal.
The arguments must both be pointers to protocol buffer structs.
Equality is defined in this way:
- Two messages are equal iff they are the same type,
corresponding fields are equal, unknown field sets
are equal, and extensions sets are equal.
- Two set scalar fields are equal iff their values are equal.
If the fields are of a floating-point type, remember that
NaN != x for all x, including NaN. If the message is defined
in a proto3 .proto file, fields are not "set"; specifically,
zero length proto3 "bytes" fields are equal (nil == {}).
- Two repeated fields are equal iff their lengths are the same,
and their corresponding elements are equal. Note a "bytes" field,
although represented by []byte, is not a repeated field and the
rule for the scalar fields described above applies.
- Two unset fields are equal.
- Two unknown field sets are equal if their current
encoded state is equal.
- Two extension sets are equal iff they have corresponding
elements that are pairwise equal.
- Two map fields are equal iff their lengths are the same,
and they contain the same set of elements. Zero-length map
fields are equal.
- Every other combination of things are not equal.
The return value is undefined if a and b are not protocol buffers.
*/
func Equal(a, b Message) bool {
if a == nil || b == nil {
return a == b
}
v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b)
if v1.Type() != v2.Type() {
return false
}
if v1.Kind() == reflect.Ptr {
if v1.IsNil() {
return v2.IsNil()
}
if v2.IsNil() {
return false
}
v1, v2 = v1.Elem(), v2.Elem()
}
if v1.Kind() != reflect.Struct {
return false
}
return equalStruct(v1, v2)
}
// v1 and v2 are known to have the same type.
func equalStruct(v1, v2 reflect.Value) bool {
sprop := GetProperties(v1.Type())
for i := 0; i < v1.NumField(); i++ {
f := v1.Type().Field(i)
if strings.HasPrefix(f.Name, "XXX_") {
continue
}
f1, f2 := v1.Field(i), v2.Field(i)
if f.Type.Kind() == reflect.Ptr {
if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 {
// both unset
continue
} else if n1 != n2 {
// set/unset mismatch
return false
}
f1, f2 = f1.Elem(), f2.Elem()
}
if !equalAny(f1, f2, sprop.Prop[i]) {
return false
}
}
if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() {
em2 := v2.FieldByName("XXX_InternalExtensions")
if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) {
return false
}
}
if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() {
em2 := v2.FieldByName("XXX_extensions")
if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) {
return false
}
}
uf := v1.FieldByName("XXX_unrecognized")
if !uf.IsValid() {
return true
}
u1 := uf.Bytes()
u2 := v2.FieldByName("XXX_unrecognized").Bytes()
return bytes.Equal(u1, u2)
}
// v1 and v2 are known to have the same type.
// prop may be nil.
func equalAny(v1, v2 reflect.Value, prop *Properties) bool {
if v1.Type() == protoMessageType {
m1, _ := v1.Interface().(Message)
m2, _ := v2.Interface().(Message)
return Equal(m1, m2)
}
switch v1.Kind() {
case reflect.Bool:
return v1.Bool() == v2.Bool()
case reflect.Float32, reflect.Float64:
return v1.Float() == v2.Float()
case reflect.Int32, reflect.Int64:
return v1.Int() == v2.Int()
case reflect.Interface:
// Probably a oneof field; compare the inner values.
n1, n2 := v1.IsNil(), v2.IsNil()
if n1 || n2 {
return n1 == n2
}
e1, e2 := v1.Elem(), v2.Elem()
if e1.Type() != e2.Type() {
return false
}
return equalAny(e1, e2, nil)
case reflect.Map:
if v1.Len() != v2.Len() {
return false
}
for _, key := range v1.MapKeys() {
val2 := v2.MapIndex(key)
if !val2.IsValid() {
// This key was not found in the second map.
return false
}
if !equalAny(v1.MapIndex(key), val2, nil) {
return false
}
}
return true
case reflect.Ptr:
// Maps may have nil values in them, so check for nil.
if v1.IsNil() && v2.IsNil() {
return true
}
if v1.IsNil() != v2.IsNil() {
return false
}
return equalAny(v1.Elem(), v2.Elem(), prop)
case reflect.Slice:
if v1.Type().Elem().Kind() == reflect.Uint8 {
// short circuit: []byte
// Edge case: if this is in a proto3 message, a zero length
// bytes field is considered the zero value.
if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 {
return true
}
if v1.IsNil() != v2.IsNil() {
return false
}
return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte))
}
if v1.Len() != v2.Len() {
return false
}
for i := 0; i < v1.Len(); i++ {
if !equalAny(v1.Index(i), v2.Index(i), prop) {
return false
}
}
return true
case reflect.String:
return v1.Interface().(string) == v2.Interface().(string)
case reflect.Struct:
return equalStruct(v1, v2)
case reflect.Uint32, reflect.Uint64:
return v1.Uint() == v2.Uint()
}
// unknown type, so not a protocol buffer
log.Printf("proto: don't know how to compare %v", v1)
return false
}
// base is the struct type that the extensions are based on.
// x1 and x2 are InternalExtensions.
func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool {
em1, _ := x1.extensionsRead()
em2, _ := x2.extensionsRead()
return equalExtMap(base, em1, em2)
}
func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
if len(em1) != len(em2) {
return false
}
for extNum, e1 := range em1 {
e2, ok := em2[extNum]
if !ok {
return false
}
m1, m2 := e1.value, e2.value
if m1 == nil && m2 == nil {
// Both have only encoded form.
if bytes.Equal(e1.enc, e2.enc) {
continue
}
// The bytes are different, but the extensions might still be
// equal. We need to decode them to compare.
}
if m1 != nil && m2 != nil {
// Both are unencoded.
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
return false
}
continue
}
// At least one is encoded. To do a semantically correct comparison
// we need to unmarshal them first.
var desc *ExtensionDesc
if m := extensionMaps[base]; m != nil {
desc = m[extNum]
}
if desc == nil {
// If both have only encoded form and the bytes are the same,
// it is handled above. We get here when the bytes are different.
// We don't know how to decode it, so just compare them as byte
// slices.
log.Printf("proto: don't know how to compare extension %d of %v", extNum, base)
return false
}
var err error
if m1 == nil {
m1, err = decodeExtension(e1.enc, desc)
}
if m2 == nil && err == nil {
m2, err = decodeExtension(e2.enc, desc)
}
if err != nil {
// The encoded form is invalid.
log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err)
return false
}
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
return false
}
}
return true
}

Some files were not shown because too many files have changed in this diff Show More