Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions gems/smithy-client/lib/smithy-client/default_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ module Smithy
module Client
# @api private
class DefaultParams
include Schema::Shapes

def initialize(shape)
@shape = shape
end
Expand All @@ -22,18 +20,18 @@ def apply(params)
private

def apply_shape(shape, value)
case shape.target
when ListShape then list(shape, value)
when MapShape then map(shape, value)
when StructureShape then structure(shape, value)
case Schema::Extension.target_shape(shape)
when Schema::Extension::SHAPE_LIST then list(shape, value)
when Schema::Extension::SHAPE_MAP then map(shape, value)
when Schema::Extension::SHAPE_STRUCTURE then structure(shape, value)
else value
end
end

def list(shape, values)
return if values.nil?

member = shape.target.member
member, = Schema::Extension.list_member(shape.target)
values.each do |value|
apply_shape(member, value)
end
Expand All @@ -43,7 +41,7 @@ def list(shape, values)
def map(shape, values)
return if values.nil?

value_shape = shape.target.value
value_shape, = Schema::Extension.map_value_member(shape.target)
values.each_pair do |_key, value|
apply_shape(value_shape, value)
end
Expand Down Expand Up @@ -72,9 +70,9 @@ def default?(shape, traits)

def default(member_shape)
default = member_shape.traits['smithy.api#default']
case member_shape.target
when BlobShape then Base64.strict_decode64(default)
when TimestampShape then timestamp_default(default)
case Schema::Extension.target_shape(member_shape)
when Schema::Extension::SHAPE_BLOB then Base64.strict_decode64(default)
when Schema::Extension::SHAPE_TIMESTAMP then timestamp_default(default)
else default
end
end
Expand Down
17 changes: 10 additions & 7 deletions gems/smithy-client/lib/smithy-client/param_converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ def c(shape, value)
end

def convert_shape(shape, value)
case shape.target
when ListShape then list(shape, value)
when MapShape then map(shape, value)
when StructureShape then structure(shape, value)
when UnionShape then union(shape, value)
case Schema::Extension.target_shape(shape)
when Schema::Extension::SHAPE_LIST then list(shape, value)
when Schema::Extension::SHAPE_MAP then map(shape, value)
when Schema::Extension::SHAPE_STRUCTURE then structure(shape, value)
when Schema::Extension::SHAPE_UNION then union(shape, value)
else c(shape, value)
end
end
Expand All @@ -53,15 +53,18 @@ def list(shape, values)
values = c(shape, values)
return values unless values.is_a?(Array)

values.collect { |v| convert_shape(shape.target.member, v) }
member, = Schema::Extension.list_member(shape.target)
values.collect { |v| convert_shape(member, v) }
end

def map(shape, values)
values = c(shape, values)
return values unless values.is_a?(Hash)

key_member, = Schema::Extension.map_key_member(shape.target)
value_member, = Schema::Extension.map_value_member(shape.target)
values.each.with_object({}) do |(key, value), hash|
hash[convert_shape(shape.target.key, key)] = convert_shape(shape.target.value, value)
hash[convert_shape(key_member, key)] = convert_shape(value_member, value)
end
end

Expand Down
77 changes: 38 additions & 39 deletions gems/smithy-client/lib/smithy-client/param_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,47 +27,46 @@ def validate!(params, context: 'params')

private

# rubocop:disable-next Metrics
# rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
def validate_shape(shape, value, errors, context)
case shape.target
when StructureShape then structure(shape, value, errors, context)
when ListShape then list(shape, value, errors, context)
when MapShape then map(shape, value, errors, context)
when DocumentShape then document(shape, value, errors, context)
when UnionShape then union(shape, value, errors, context)
when StringShape, EnumShape
case Schema::Extension.target_shape(shape)
when Schema::Extension::SHAPE_STRUCTURE then structure(shape, value, errors, context)
when Schema::Extension::SHAPE_LIST then list(shape, value, errors, context)
when Schema::Extension::SHAPE_MAP then map(shape, value, errors, context)
when Schema::Extension::SHAPE_DOCUMENT then document(shape, value, errors, context)
when Schema::Extension::SHAPE_UNION then union(shape, value, errors, context)
when Schema::Extension::SHAPE_STRING, Schema::Extension::SHAPE_ENUM
errors << expected_got(context, 'a String', value) unless value.is_a?(String)
when IntegerShape, IntEnumShape
when Schema::Extension::SHAPE_INTEGER, Schema::Extension::SHAPE_INT_ENUM
errors << expected_got(context, 'an Integer', value) unless value.is_a?(Integer)
when BigDecimalShape
when Schema::Extension::SHAPE_BIG_DECIMAL
errors << expected_got(context, 'a BigDecimal', value) unless value.is_a?(BigDecimal)
when FloatShape
when Schema::Extension::SHAPE_FLOAT
errors << expected_got(context, 'a Float', value) unless value.is_a?(Float)
when TimestampShape
when Schema::Extension::SHAPE_TIMESTAMP
errors << expected_got(context, 'a Time object', value) unless value.is_a?(Time)
when BooleanShape
when Schema::Extension::SHAPE_BOOLEAN
errors << expected_got(context, 'true or false', value) unless [true, false].include?(value)
when BlobShape
unless value.is_a?(String)
if streaming_input?(shape)
unless io_like?(value)
errors << expected_got(
context,
'a String or IO like object that supports read and rewind',
value
)
end
elsif !io_like?(value, require_size: true)
errors << expected_got(
context,
'a String or IO like object that supports read, rewind, and size',
value
)
end
end
when Schema::Extension::SHAPE_BLOB
blob(shape, value, errors, context)
end
end

def blob(shape, value, errors, context)
return if value.is_a?(String)

streaming = streaming_input?(shape)
return if io_like?(value, require_size: !streaming)

expected =
if streaming
'a String or IO like object that supports read and rewind'
else
'a String or IO like object that supports read, rewind, and size'
end
errors << expected_got(context, expected, value)
end

def document(shape, value, errors, context)
document_types = [Hash, Array, Numeric, String, TrueClass, FalseClass, NilClass]
unless document_types.any? { |t| value.is_a?(t) }
Expand All @@ -92,10 +91,11 @@ def list(shape, values, errors, context)
return
end

member, = Schema::Extension.list_member(shape.target)
values.each.with_index do |value, index|
next unless value

validate_shape(shape.target.member, value, errors, context + "[#{index}]")
validate_shape(member, value, errors, context + "[#{index}]")
end
end

Expand All @@ -105,11 +105,13 @@ def map(shape, values, errors, context)
return
end

key_member, = Schema::Extension.map_key_member(shape.target)
value_member, = Schema::Extension.map_value_member(shape.target)
values.each do |key, value|
validate_shape(shape.target.key, key, errors, "#{context} #{key.inspect} key")
validate_shape(key_member, key, errors, "#{context} #{key.inspect} key")
next unless value

validate_shape(shape.target.value, value, errors, context + "[#{key.inspect}]")
validate_shape(value_member, value, errors, context + "[#{key.inspect}]")
end
end

Expand Down Expand Up @@ -174,10 +176,7 @@ def valid_union?(shape, values, errors, context)
end

def validate_required_members(shape, values, errors, context)
shape.target.members.each do |name, member_shape|
traits = member_shape.traits
next unless traits.key?('smithy.api#required') && !traits.key?('smithy.api#clientOptional')

Schema::Extension.required_members(shape.target).each do |name|
if values[name].nil?
param = "#{context}[#{name.inspect}]"
errors << "missing required parameter #{param}"
Expand All @@ -186,7 +185,7 @@ def validate_required_members(shape, values, errors, context)
end

def streaming_input?(shape)
shape.target.traits.key?('smithy.api#streaming')
Schema::Extension.streaming?(shape.target)
end

def io_like?(value, require_size: false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def call(context)
private

def checksum_required_operation?(context)
context.operation.traits.key?('smithy.api#httpChecksumRequired')
Schema::Extension.checksum_required?(context.operation)
end

def md5(value)
Expand Down
16 changes: 5 additions & 11 deletions gems/smithy-client/lib/smithy-client/plugins/host_prefix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def add_handlers(handlers, config)
# @api private
class Handler < Smithy::Client::Handler
def call(context)
host_prefix = context.operation.traits.dig('smithy.api#endpoint', 'hostPrefix')
host_prefix = Schema::Extension.endpoint_host_prefix(context.operation)
apply_host_prefix(context, host_prefix) if host_prefix
@handler.call(context)
end
Expand All @@ -42,21 +42,15 @@ def call(context)

# TODO: optimize this to collect all labels in one pass
def apply_host_prefix(context, host_prefix)
input = context.operation.input
host_labels = Schema::Extension.host_label_index(context.operation.input)
prefix = host_prefix.gsub(/\{.+?}/) do |label|
label_value(input, label.delete('{}'), context.params)
label_value(host_labels, label.delete('{}'), context.params)
end
context.http_request.endpoint.host = prefix + context.http_request.endpoint.host
end

def label_value(input, label, params)
name = nil
input.members.each do |member_name, member_shape|
next unless member_shape.traits.key?('smithy.api#hostLabel')
next unless member_shape.name == label

name = member_name
end
def label_value(host_labels, label, params)
name = host_labels[label]
raise ArgumentError, "#{label} is not a valid host label" if name.nil?
raise ArgumentError, "params[:#{name}] must not be nil or blank" if params[name].nil? || params[name].empty?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ def call(context)
private

def apply_idempotency_token(input, params)
input.members.each do |member_name, member_shape|
next unless member_shape.traits.key?('smithy.api#idempotencyToken')
member_name = Schema::Extension.idempotency_token_member(input)
return unless member_name

params[member_name] ||= SecureRandom.uuid
end
params[member_name] ||= SecureRandom.uuid
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,35 +67,26 @@ def add_handlers(handlers, config)
# @api private
class Handler < Client::Handler
def call(context)
if request_compression_trait?(context)
selected_encoding = request_encoding_selection(context)
if selected_encoding
if streaming?(context.operation.input)
process_streaming_compression(selected_encoding, context)
elsif context.http_request.body.size >= context.config.request_min_compression_size_bytes
process_compression(selected_encoding, context)
end
selected_encoding = request_encoding_selection(context)
if selected_encoding
if streaming?(context.operation.input)
process_streaming_compression(selected_encoding, context)
elsif context.http_request.body.size >= context.config.request_min_compression_size_bytes
process_compression(selected_encoding, context)
end
end
track_feature(selected_encoding) { @handler.call(context) }
end

private

def request_compression_trait?(context)
context.operation.traits.key?('smithy.api#requestCompression')
end

def request_encoding_selection(context)
encodings = context.operation.traits['smithy.api#requestCompression']['encodings']
encodings.find { |encoding| RequestCompression::SUPPORTED_ENCODINGS.include?(encoding) }
encodings = Schema::Extension.request_compression_encodings(context.operation)
encodings&.find { |encoding| RequestCompression::SUPPORTED_ENCODINGS.include?(encoding) }
end

def streaming?(input)
input.members.any? do |_, member_shape|
member_shape.target.traits.key?('smithy.api#streaming') &&
!member_shape.target.traits.key?('smithy.api#requiresLength')
end
Schema::Extension.streaming_member_unknown_length(input)
end

def process_streaming_compression(encoding, context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,10 @@ def reset_response(context, response)

# TODO: Revisit after trait is finalized.
def long_polling_operation?(context)
context.operation.traits.key?('smithy.api#longPoll')
operation = context.operation
return operation.traits.key?('smithy.api#longPoll') unless operation.respond_to?(:key?)

Schema::Extension.long_polling?(operation)
end

def track_feature(retry_strategy, &block)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,15 @@ def apply_transfer_encoding(context, payload_shape)
end

def streaming_member(context)
context.operation.input.members.detect do |_, member_shape|
member_shape.target.traits.key?('smithy.api#streaming')
end&.last
Schema::Extension.streaming_member(context.operation.input)
end

def requires_length?(shape)
shape.traits.key?('smithy.api#requiresLength')
Schema::Extension.requires_length?(shape)
end

def unsigned_payload?(context)
context.operation.traits.key?('aws.auth#unsignedPayload')
Schema::Extension.unsigned_payload?(context.operation)
end
end

Expand Down
6 changes: 1 addition & 5 deletions gems/smithy-client/lib/smithy-client/rpc_v2_cbor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,7 @@ def apply_url_path(context)
end

def event_stream?(input_shape)
input_shape.members.each_value do |member_shape|
shape = member_shape.target
return true if shape.traits.key?('smithy.api#streaming') && shape.is_a?(Schema::Shapes::UnionShape)
end
false
Schema::Extension.event_stream_member(input_shape)
end

def valid_response?(context)
Expand Down
Loading
Loading