diff --git a/go.mod b/go.mod index 2c3c62d..668c19a 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.26 require ( github.com/aws/aws-lambda-go v1.54.0 - github.com/aws/aws-sdk-go-v2 v1.41.9 + github.com/aws/aws-sdk-go-v2 v1.41.12 github.com/aws/aws-sdk-go-v2/config v1.32.18 github.com/aws/aws-sdk-go-v2/service/codedeploy v1.36.0 ) @@ -21,5 +21,5 @@ require ( github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 // indirect - github.com/aws/smithy-go v1.26.0 // indirect + github.com/aws/smithy-go v1.27.1 // indirect ) diff --git a/go.sum b/go.sum index 59cd085..8b6a13e 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/aws/aws-lambda-go v1.54.0 h1:EGYpdyRGF88xszqlGcBewz811mJeRS+maNlLZXFheII= github.com/aws/aws-lambda-go v1.54.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A= -github.com/aws/aws-sdk-go-v2 v1.41.9 h1:/rYeyO2+HrMztAmxAq9++XJtFMqSIpSsNA0yDGALYq4= -github.com/aws/aws-sdk-go-v2 v1.41.9/go.mod h1:+HsoOEX80qAVUitj1A2DhCNTjmb3edVyuDypb6LNEeo= +github.com/aws/aws-sdk-go-v2 v1.41.12 h1:DIKX2c31ekm9RA2D9FBj1EWXx++9AdAqRw+e78Tq2Ck= +github.com/aws/aws-sdk-go-v2 v1.41.12/go.mod h1:27+ACypSLljLAEKsCYOmrjKh83vuTRkuAe9Uv/3A4bg= github.com/aws/aws-sdk-go-v2/config v1.32.18 h1:Hcia46bxhGgF3BaSnG8nSNCWmqTK6bj9xN9/FJ3WK6Q= github.com/aws/aws-sdk-go-v2/config v1.32.18/go.mod h1:zEjCAYmxqDadH1WX8CdBvmLKhUEUVFgKRQG38zjDmrY= github.com/aws/aws-sdk-go-v2/credentials v1.19.17 h1:gP2nkGsS+KMvF/jfFz2Vv2qiiOqWKyPACSzPsqHgoW8= @@ -28,8 +28,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0 h1:nDARhv/oF55bcxF7rCI/4PDx github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.0/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg= github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 h1:F/M5Y9I3nwr2IEpshZgh1GeHpOItExNM9L1euNuh/fk= github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod h1:mTNxImtovCOEEuD65mKW7DCsL+2gjEH+RPEAexAzAio= -github.com/aws/smithy-go v1.26.0 h1:9ouqbi+NyKP7fV3Te7UElCwdAb6Y8uk7LGwPE5tVe/s= -github.com/aws/smithy-go v1.26.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/aws/smithy-go v1.27.1 h1:4T340VFndXtADGF52gYa1POyL7s9E4Z1OeZ1hCscIw8= +github.com/aws/smithy-go v1.27.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go index 3c59b29..ff84834 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go @@ -3,4 +3,4 @@ package aws // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.41.9" +const goModuleVersion = "1.41.12" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/v4signer_adapter_eventstream.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/v4signer_adapter_eventstream.go new file mode 100644 index 0000000..320e888 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/v4signer_adapter_eventstream.go @@ -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) +} diff --git a/vendor/github.com/aws/smithy-go/CHANGELOG.md b/vendor/github.com/aws/smithy-go/CHANGELOG.md index 7fc37ff..6ff611a 100644 --- a/vendor/github.com/aws/smithy-go/CHANGELOG.md +++ b/vendor/github.com/aws/smithy-go/CHANGELOG.md @@ -1,3 +1,26 @@ +# 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 diff --git a/vendor/github.com/aws/smithy-go/README.md b/vendor/github.com/aws/smithy-go/README.md index a413ff3..c5e1456 100644 --- a/vendor/github.com/aws/smithy-go/README.md +++ b/vendor/github.com/aws/smithy-go/README.md @@ -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 diff --git a/vendor/github.com/aws/smithy-go/document/document.go b/vendor/github.com/aws/smithy-go/document/document.go index 8f852d9..82b48eb 100644 --- a/vendor/github.com/aws/smithy-go/document/document.go +++ b/vendor/github.com/aws/smithy-go/document/document.go @@ -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) diff --git a/vendor/github.com/aws/smithy-go/eventstream/const.go b/vendor/github.com/aws/smithy-go/eventstream/const.go new file mode 100644 index 0000000..893156c --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/const.go @@ -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` +) diff --git a/vendor/github.com/aws/smithy-go/eventstream/debug.go b/vendor/github.com/aws/smithy-go/eventstream/debug.go new file mode 100644 index 0000000..6049402 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/debug.go @@ -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)) + } +} diff --git a/vendor/github.com/aws/smithy-go/eventstream/decode.go b/vendor/github.com/aws/smithy-go/eventstream/decode.go new file mode 100644 index 0000000..d9ab765 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/decode.go @@ -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 +} diff --git a/vendor/github.com/aws/smithy-go/eventstream/deserializer.go b/vendor/github.com/aws/smithy-go/eventstream/deserializer.go new file mode 100644 index 0000000..8bc931a --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/deserializer.go @@ -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") +} diff --git a/vendor/github.com/aws/smithy-go/eventstream/encode.go b/vendor/github.com/aws/smithy-go/eventstream/encode.go new file mode 100644 index 0000000..61cf723 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/encode.go @@ -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 +} diff --git a/vendor/github.com/aws/smithy-go/eventstream/error.go b/vendor/github.com/aws/smithy-go/eventstream/error.go new file mode 100644 index 0000000..7616214 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/error.go @@ -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" +} diff --git a/vendor/github.com/aws/smithy-go/eventstream/header.go b/vendor/github.com/aws/smithy-go/eventstream/header.go new file mode 100644 index 0000000..f580bda --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/header.go @@ -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 +} diff --git a/vendor/github.com/aws/smithy-go/eventstream/header_value.go b/vendor/github.com/aws/smithy-go/eventstream/header_value.go new file mode 100644 index 0000000..61ed353 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/header_value.go @@ -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) +} diff --git a/vendor/github.com/aws/smithy-go/eventstream/message.go b/vendor/github.com/aws/smithy-go/eventstream/message.go new file mode 100644 index 0000000..1a77654 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/message.go @@ -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 +} diff --git a/vendor/github.com/aws/smithy-go/eventstream/serializer.go b/vendor/github.com/aws/smithy-go/eventstream/serializer.go new file mode 100644 index 0000000..018481e --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/serializer.go @@ -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 +} diff --git a/vendor/github.com/aws/smithy-go/eventstream/signer.go b/vendor/github.com/aws/smithy-go/eventstream/signer.go new file mode 100644 index 0000000..69f7779 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/signer.go @@ -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) +} diff --git a/vendor/github.com/aws/smithy-go/eventstream/types.go b/vendor/github.com/aws/smithy-go/eventstream/types.go new file mode 100644 index 0000000..4627bb2 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/eventstream/types.go @@ -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 +} diff --git a/vendor/github.com/aws/smithy-go/go_module_metadata.go b/vendor/github.com/aws/smithy-go/go_module_metadata.go index bf309b9..ba81f77 100644 --- a/vendor/github.com/aws/smithy-go/go_module_metadata.go +++ b/vendor/github.com/aws/smithy-go/go_module_metadata.go @@ -3,4 +3,4 @@ package smithy // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.26.0" +const goModuleVersion = "1.27.1" diff --git a/vendor/github.com/aws/smithy-go/schema.go b/vendor/github.com/aws/smithy-go/schema.go new file mode 100644 index 0000000..6293d34 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/schema.go @@ -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< indexStreaming && m.indexed[indexStreaming] != nil { + return true + } + } + return false +} diff --git a/vendor/github.com/aws/smithy-go/schema_ext.go b/vendor/github.com/aws/smithy-go/schema_ext.go new file mode 100644 index 0000000..7503b30 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/schema_ext.go @@ -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 +} diff --git a/vendor/github.com/aws/smithy-go/serde.go b/vendor/github.com/aws/smithy-go/serde.go new file mode 100644 index 0000000..a9effc5 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/serde.go @@ -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 + } + } +} diff --git a/vendor/github.com/aws/smithy-go/sync/error.go b/vendor/github.com/aws/smithy-go/sync/error.go new file mode 100644 index 0000000..6292076 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/sync/error.go @@ -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 +} diff --git a/vendor/github.com/aws/smithy-go/trait.go b/vendor/github.com/aws/smithy-go/trait.go new file mode 100644 index 0000000..a45db96 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/trait.go @@ -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 +} diff --git a/vendor/github.com/aws/smithy-go/traits/http.go b/vendor/github.com/aws/smithy-go/traits/http.go new file mode 100644 index 0000000..b06e9fe --- /dev/null +++ b/vendor/github.com/aws/smithy-go/traits/http.go @@ -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"} } diff --git a/vendor/github.com/aws/smithy-go/traits/index.go b/vendor/github.com/aws/smithy-go/traits/index.go new file mode 100644 index 0000000..47733af --- /dev/null +++ b/vendor/github.com/aws/smithy-go/traits/index.go @@ -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 } diff --git a/vendor/github.com/aws/smithy-go/traits/serde.go b/vendor/github.com/aws/smithy-go/traits/serde.go new file mode 100644 index 0000000..25b7f0d --- /dev/null +++ b/vendor/github.com/aws/smithy-go/traits/serde.go @@ -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"} } diff --git a/vendor/github.com/aws/smithy-go/traits/traits.go b/vendor/github.com/aws/smithy-go/traits/traits.go new file mode 100644 index 0000000..599be4e --- /dev/null +++ b/vendor/github.com/aws/smithy-go/traits/traits.go @@ -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"} } diff --git a/vendor/github.com/aws/smithy-go/transport/http/auth.go b/vendor/github.com/aws/smithy-go/transport/http/auth.go index 58e1ab5..5b5adad 100644 --- a/vendor/github.com/aws/smithy-go/transport/http/auth.go +++ b/vendor/github.com/aws/smithy-go/transport/http/auth.go @@ -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) +} diff --git a/vendor/github.com/aws/smithy-go/transport/http/eventstream.go b/vendor/github.com/aws/smithy-go/transport/http/eventstream.go new file mode 100644 index 0000000..251db8a --- /dev/null +++ b/vendor/github.com/aws/smithy-go/transport/http/eventstream.go @@ -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 +} diff --git a/vendor/github.com/aws/smithy-go/transport/http/eventstream_middleware.go b/vendor/github.com/aws/smithy-go/transport/http/eventstream_middleware.go new file mode 100644 index 0000000..f7d60dc --- /dev/null +++ b/vendor/github.com/aws/smithy-go/transport/http/eventstream_middleware.go @@ -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) +} diff --git a/vendor/github.com/aws/smithy-go/transport/http/protocol.go b/vendor/github.com/aws/smithy-go/transport/http/protocol.go new file mode 100644 index 0000000..80fc9e6 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/transport/http/protocol.go @@ -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 +} diff --git a/vendor/github.com/aws/smithy-go/type_registry.go b/vendor/github.com/aws/smithy-go/type_registry.go new file mode 100644 index 0000000..3c4e02a --- /dev/null +++ b/vendor/github.com/aws/smithy-go/type_registry.go @@ -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 +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 077045d..46c2d1e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -4,7 +4,7 @@ github.com/aws/aws-lambda-go/lambda github.com/aws/aws-lambda-go/lambda/handlertrace github.com/aws/aws-lambda-go/lambda/messages github.com/aws/aws-lambda-go/lambdacontext -# github.com/aws/aws-sdk-go-v2 v1.41.9 +# github.com/aws/aws-sdk-go-v2 v1.41.12 ## explicit; go 1.24 github.com/aws/aws-sdk-go-v2/aws github.com/aws/aws-sdk-go-v2/aws/defaults @@ -89,7 +89,7 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc/types github.com/aws/aws-sdk-go-v2/service/sts github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints github.com/aws/aws-sdk-go-v2/service/sts/types -# github.com/aws/smithy-go v1.26.0 +# github.com/aws/smithy-go v1.27.1 ## explicit; go 1.24 github.com/aws/smithy-go github.com/aws/smithy-go/auth @@ -103,6 +103,7 @@ github.com/aws/smithy-go/encoding/xml 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/eventstream github.com/aws/smithy-go/internal/sync/singleflight github.com/aws/smithy-go/io github.com/aws/smithy-go/logging @@ -111,8 +112,10 @@ github.com/aws/smithy-go/middleware github.com/aws/smithy-go/private/requestcompression github.com/aws/smithy-go/ptr github.com/aws/smithy-go/rand +github.com/aws/smithy-go/sync github.com/aws/smithy-go/time github.com/aws/smithy-go/tracing +github.com/aws/smithy-go/traits github.com/aws/smithy-go/transport/http github.com/aws/smithy-go/transport/http/internal/io github.com/aws/smithy-go/waiter