-
Notifications
You must be signed in to change notification settings - Fork 7
Improvements to make V4 work #291
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'openssl' | ||
|
||
module Smithy | ||
module Client | ||
module Plugins | ||
# @api private | ||
class ChecksumRequired < Plugin | ||
def add_handlers(handlers, _config) | ||
# Ensure checksum is computed AFTER the request is built but BEFORE it is signed | ||
handlers.add(Handler, priority: 15) | ||
end | ||
|
||
# @api private | ||
class Handler < Client::Handler | ||
CHUNK_SIZE = 1 * 1024 * 1024 # one MB | ||
|
||
def call(context) | ||
if checksum_required_operation?(context) | ||
context.request.headers['Content-Md5'] ||= md5(context.request.body) | ||
end | ||
@handler.call(context) | ||
end | ||
|
||
private | ||
|
||
def checksum_required_operation?(context) | ||
context.operation.traits.include?('smithy.api#httpChecksumRequired') | ||
end | ||
|
||
def md5(value) | ||
md5 = OpenSSL::Digest.new('MD5') | ||
update_in_chunks(md5, value) | ||
md5.base64digest | ||
end | ||
|
||
def update_in_chunks(digest, io) | ||
loop do | ||
chunk = io.read(CHUNK_SIZE) | ||
break unless chunk | ||
|
||
digest.update(chunk) | ||
end | ||
io.rewind | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# frozen_string_literal: true | ||
|
||
module Smithy | ||
module Client | ||
module Plugins | ||
# @api private | ||
class HostPrefix < Plugin | ||
option( | ||
:disable_host_prefix_injection, | ||
default: false, | ||
doc_type: 'Boolean', | ||
docstring: 'When true, the SDK will not prepend the modeled host prefix to the endpoint.' | ||
) do |_config| | ||
value = ENV['DISABLE_HOST_PREFIX_INJECTION'] || 'false' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wondering if we have a set plan for accommodating There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think so, by overwriting the option in a different plugin. |
||
Util.str_to_bool(value) | ||
end | ||
|
||
def after_initialize(client) | ||
validate_disable_host_prefix_injection(client.config) | ||
end | ||
|
||
def validate_disable_host_prefix_injection(config) | ||
return if [true, false].include?(config.disable_host_prefix_injection) | ||
|
||
raise ArgumentError, | ||
':disable_host_prefix_injection must be either `true` or `false`' | ||
end | ||
|
||
def add_handlers(handlers, config) | ||
handlers.add(Handler, priority: 25) unless config.disable_host_prefix_injection | ||
end | ||
|
||
# @api private | ||
class Handler < Smithy::Client::Handler | ||
def call(context) | ||
host_prefix = context.operation.traits.dig('smithy.api#endpoint', 'hostPrefix') | ||
apply_host_prefix(context, host_prefix) if host_prefix | ||
@handler.call(context) | ||
end | ||
|
||
private | ||
|
||
# TODO: optimize this to collect all labels in one pass | ||
def apply_host_prefix(context, host_prefix) | ||
input = context.operation.input | ||
prefix = host_prefix.gsub(/\{.+?}/) do |label| | ||
label_value(input, label.delete('{}'), context.params) | ||
end | ||
context.request.endpoint.host = prefix + context.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.include?('smithy.api#hostLabel') | ||
next unless member_shape.name == label | ||
|
||
name = member_name | ||
end | ||
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? | ||
mullermp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
params[name] | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'securerandom' | ||
|
||
module Smithy | ||
module Client | ||
module Plugins | ||
# @api private | ||
class IdempotencyToken < Plugin | ||
def add_handlers(handlers, _config) | ||
handlers.add(Handler, step: :initialize) | ||
end | ||
|
||
# @api private | ||
class Handler < Client::Handler | ||
def call(context) | ||
apply_idempotency_token(context.operation.input, context.params) | ||
@handler.call(context) | ||
end | ||
|
||
private | ||
|
||
def apply_idempotency_token(input, params) | ||
input.members.each do |member_name, member_shape| | ||
next unless member_shape.traits.include?('smithy.api#idempotencyToken') | ||
|
||
params[member_name] ||= SecureRandom.uuid | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is my bad - I meant to put
__type
instead of__target
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, we need to revisit this anyway, and I don't see any tests related to it.