vendor: update buildkit to 41c29fffe299
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
+4
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
+1
-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"
|
||||
|
||||
Generated
Vendored
+51
@@ -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)
|
||||
}
|
||||
+26
@@ -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.
|
||||
|
||||
+1
-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
@@ -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
@@ -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.
|
||||
|
||||
+1
-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
@@ -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
@@ -3,4 +3,4 @@
|
||||
package v4a
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.4.24"
|
||||
const goModuleVersion = "1.4.30"
|
||||
|
||||
Generated
Vendored
+12
@@ -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.
|
||||
|
||||
Generated
Vendored
+1
-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"
|
||||
|
||||
+26
@@ -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.
|
||||
|
||||
Generated
Vendored
+1
-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
@@ -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
@@ -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
@@ -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, ¶ms, c)
|
||||
})
|
||||
return resolveResult(ref, ¶ms, c)
|
||||
}
|
||||
|
||||
type endpointParamsBinder interface {
|
||||
|
||||
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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, ¶ms, c)
|
||||
})
|
||||
return resolveResult(ref, ¶ms, c)
|
||||
}
|
||||
|
||||
type endpointParamsBinder interface {
|
||||
|
||||
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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, ¶ms, c)
|
||||
})
|
||||
return resolveResult(ref, ¶ms, c)
|
||||
}
|
||||
|
||||
type endpointParamsBinder interface {
|
||||
|
||||
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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, ¶ms, c)
|
||||
})
|
||||
return resolveResult(ref, ¶ms, c)
|
||||
}
|
||||
|
||||
type endpointParamsBinder interface {
|
||||
|
||||
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
+69
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user