mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
rbd: add aws-sts-metdata
encryption type
With Amazon STS and kubernetes cluster is configured with OIDC identity provider, credentials to access Amazon KMS can be fetched using oidc-token(serviceaccount token). Each tenant/namespace needs to create a secret with aws region, role and CMK ARN. Ceph-CSI will assume the given role with oidc token and access aws KMS, with given CMK to encrypt/decrypt DEK which will stored in the image metdata. Refer: https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html Resolves: #2879 Signed-off-by: Rakshith R <rar@redhat.com>
This commit is contained in:
65
vendor/github.com/aws/smithy-go/transport/http/checksum_middleware.go
generated
vendored
Normal file
65
vendor/github.com/aws/smithy-go/transport/http/checksum_middleware.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
)
|
||||
|
||||
const contentMD5Header = "Content-Md5"
|
||||
|
||||
// contentMD5Checksum provides a middleware to compute and set
|
||||
// content-md5 checksum for a http request
|
||||
type contentMD5Checksum struct {
|
||||
}
|
||||
|
||||
// AddContentChecksumMiddleware adds checksum middleware to middleware's
|
||||
// build step.
|
||||
func AddContentChecksumMiddleware(stack *middleware.Stack) error {
|
||||
// This middleware must be executed before request body is set.
|
||||
return stack.Build.Add(&contentMD5Checksum{}, middleware.Before)
|
||||
}
|
||||
|
||||
// ID returns the identifier for the checksum middleware
|
||||
func (m *contentMD5Checksum) ID() string { return "ContentChecksum" }
|
||||
|
||||
// HandleBuild adds behavior to compute md5 checksum and add content-md5 header
|
||||
// on http request
|
||||
func (m *contentMD5Checksum) HandleBuild(
|
||||
ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler,
|
||||
) (
|
||||
out middleware.BuildOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := in.Request.(*Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown request type %T", req)
|
||||
}
|
||||
|
||||
// if Content-MD5 header is already present, return
|
||||
if v := req.Header.Get(contentMD5Header); len(v) != 0 {
|
||||
return next.HandleBuild(ctx, in)
|
||||
}
|
||||
|
||||
// fetch the request stream.
|
||||
stream := req.GetStream()
|
||||
// compute checksum if payload is explicit
|
||||
if stream != nil {
|
||||
v, err := computeMD5Checksum(stream)
|
||||
if err != nil {
|
||||
return out, metadata, fmt.Errorf("error computing md5 checksum, %w", err)
|
||||
}
|
||||
|
||||
// reset the request stream
|
||||
if err := req.RewindStream(); err != nil {
|
||||
return out, metadata, fmt.Errorf(
|
||||
"error rewinding request stream after computing md5 checksum, %w", err)
|
||||
}
|
||||
|
||||
// set the 'Content-MD5' header
|
||||
req.Header.Set(contentMD5Header, string(v))
|
||||
}
|
||||
|
||||
// set md5 header value
|
||||
return next.HandleBuild(ctx, in)
|
||||
}
|
120
vendor/github.com/aws/smithy-go/transport/http/client.go
generated
vendored
Normal file
120
vendor/github.com/aws/smithy-go/transport/http/client.go
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
smithy "github.com/aws/smithy-go"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
)
|
||||
|
||||
// ClientDo provides the interface for custom HTTP client implementations.
|
||||
type ClientDo interface {
|
||||
Do(*http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// ClientDoFunc provides a helper to wrap a function as an HTTP client for
|
||||
// round tripping requests.
|
||||
type ClientDoFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
// Do will invoke the underlying func, returning the result.
|
||||
func (fn ClientDoFunc) Do(r *http.Request) (*http.Response, error) {
|
||||
return fn(r)
|
||||
}
|
||||
|
||||
// ClientHandler wraps a client that implements the HTTP Do method. Standard
|
||||
// implementation is http.Client.
|
||||
type ClientHandler struct {
|
||||
client ClientDo
|
||||
}
|
||||
|
||||
// NewClientHandler returns an initialized middleware handler for the client.
|
||||
func NewClientHandler(client ClientDo) ClientHandler {
|
||||
return ClientHandler{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
// Handle implements the middleware Handler interface, that will invoke the
|
||||
// underlying HTTP client. Requires the input to be a Smithy *Request. Returns
|
||||
// a smithy *Response, or error if the request failed.
|
||||
func (c ClientHandler) Handle(ctx context.Context, input interface{}) (
|
||||
out interface{}, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := input.(*Request)
|
||||
if !ok {
|
||||
return nil, metadata, fmt.Errorf("expect Smithy http.Request value as input, got unsupported type %T", input)
|
||||
}
|
||||
|
||||
builtRequest := req.Build(ctx)
|
||||
if err := ValidateEndpointHost(builtRequest.Host); err != nil {
|
||||
return nil, metadata, err
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(builtRequest)
|
||||
if resp == nil {
|
||||
// Ensure a http response value is always present to prevent unexpected
|
||||
// panics.
|
||||
resp = &http.Response{
|
||||
Header: http.Header{},
|
||||
Body: http.NoBody,
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
err = &RequestSendError{Err: err}
|
||||
|
||||
// Override the error with a context canceled error, if that was canceled.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
err = &smithy.CanceledError{Err: ctx.Err()}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP RoundTripper *should* close the request body. But this may not happen in a timely manner.
|
||||
// So instead Smithy *Request Build wraps the body to be sent in a safe closer that will clear the
|
||||
// stream reference so that it can be safely reused.
|
||||
if builtRequest.Body != nil {
|
||||
_ = builtRequest.Body.Close()
|
||||
}
|
||||
|
||||
return &Response{Response: resp}, metadata, err
|
||||
}
|
||||
|
||||
// RequestSendError provides a generic request transport error. This error
|
||||
// should wrap errors making HTTP client requests.
|
||||
//
|
||||
// The ClientHandler will wrap the HTTP client's error if the client request
|
||||
// fails, and did not fail because of context canceled.
|
||||
type RequestSendError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// ConnectionError returns that the error is related to not being able to send
|
||||
// the request, or receive a response from the service.
|
||||
func (e *RequestSendError) ConnectionError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying error, if there was one.
|
||||
func (e *RequestSendError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
func (e *RequestSendError) Error() string {
|
||||
return fmt.Sprintf("request send failed, %v", e.Err)
|
||||
}
|
||||
|
||||
// NopClient provides a client that ignores the request, and returns an empty
|
||||
// successful HTTP response value.
|
||||
type NopClient struct{}
|
||||
|
||||
// Do ignores the request and returns a 200 status empty response.
|
||||
func (NopClient) Do(r *http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
StatusCode: 200,
|
||||
Header: http.Header{},
|
||||
Body: http.NoBody,
|
||||
}, nil
|
||||
}
|
5
vendor/github.com/aws/smithy-go/transport/http/doc.go
generated
vendored
Normal file
5
vendor/github.com/aws/smithy-go/transport/http/doc.go
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/*
|
||||
Package http provides the HTTP transport client and request/response types
|
||||
needed to round trip API operation calls with an service.
|
||||
*/
|
||||
package http
|
163
vendor/github.com/aws/smithy-go/transport/http/headerlist.go
generated
vendored
Normal file
163
vendor/github.com/aws/smithy-go/transport/http/headerlist.go
generated
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
func splitHeaderListValues(vs []string, splitFn func(string) ([]string, error)) ([]string, error) {
|
||||
values := make([]string, 0, len(vs))
|
||||
|
||||
for i := 0; i < len(vs); i++ {
|
||||
parts, err := splitFn(vs[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values = append(values, parts...)
|
||||
}
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// SplitHeaderListValues attempts to split the elements of the slice by commas,
|
||||
// and return a list of all values separated. Returns error if unable to
|
||||
// separate the values.
|
||||
func SplitHeaderListValues(vs []string) ([]string, error) {
|
||||
return splitHeaderListValues(vs, quotedCommaSplit)
|
||||
}
|
||||
|
||||
func quotedCommaSplit(v string) (parts []string, err error) {
|
||||
v = strings.TrimSpace(v)
|
||||
|
||||
expectMore := true
|
||||
for i := 0; i < len(v); i++ {
|
||||
if unicode.IsSpace(rune(v[i])) {
|
||||
continue
|
||||
}
|
||||
expectMore = false
|
||||
|
||||
// leading space in part is ignored.
|
||||
// Start of value must be non-space, or quote.
|
||||
//
|
||||
// - If quote, enter quoted mode, find next non-escaped quote to
|
||||
// terminate the value.
|
||||
// - Otherwise, find next comma to terminate value.
|
||||
|
||||
remaining := v[i:]
|
||||
|
||||
var value string
|
||||
var valueLen int
|
||||
if remaining[0] == '"' {
|
||||
//------------------------------
|
||||
// Quoted value
|
||||
//------------------------------
|
||||
var j int
|
||||
var skipQuote bool
|
||||
for j += 1; j < len(remaining); j++ {
|
||||
if remaining[j] == '\\' || (remaining[j] != '\\' && skipQuote) {
|
||||
skipQuote = !skipQuote
|
||||
continue
|
||||
}
|
||||
if remaining[j] == '"' {
|
||||
break
|
||||
}
|
||||
}
|
||||
if j == len(remaining) || j == 1 {
|
||||
return nil, fmt.Errorf("value %v missing closing double quote",
|
||||
remaining)
|
||||
}
|
||||
valueLen = j + 1
|
||||
|
||||
tail := remaining[valueLen:]
|
||||
var k int
|
||||
for ; k < len(tail); k++ {
|
||||
if !unicode.IsSpace(rune(tail[k])) && tail[k] != ',' {
|
||||
return nil, fmt.Errorf("value %v has non-space trailing characters",
|
||||
remaining)
|
||||
}
|
||||
if tail[k] == ',' {
|
||||
expectMore = true
|
||||
break
|
||||
}
|
||||
}
|
||||
value = remaining[:valueLen]
|
||||
value, err = strconv.Unquote(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unquote value %v, %w", value, err)
|
||||
}
|
||||
|
||||
// Pad valueLen to include trailing space(s) so `i` is updated correctly.
|
||||
valueLen += k
|
||||
|
||||
} else {
|
||||
//------------------------------
|
||||
// Unquoted value
|
||||
//------------------------------
|
||||
|
||||
// Index of the next comma is the length of the value, or end of string.
|
||||
valueLen = strings.Index(remaining, ",")
|
||||
if valueLen != -1 {
|
||||
expectMore = true
|
||||
} else {
|
||||
valueLen = len(remaining)
|
||||
}
|
||||
value = strings.TrimSpace(remaining[:valueLen])
|
||||
}
|
||||
|
||||
i += valueLen
|
||||
parts = append(parts, value)
|
||||
|
||||
}
|
||||
|
||||
if expectMore {
|
||||
parts = append(parts, "")
|
||||
}
|
||||
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
// SplitHTTPDateTimestampHeaderListValues attempts to split the HTTP-Date
|
||||
// timestamp values in the slice by commas, and return a list of all values
|
||||
// separated. The split is aware of the HTTP-Date timestamp format, and will skip
|
||||
// comma within the timestamp value. Returns an error if unable to split the
|
||||
// timestamp values.
|
||||
func SplitHTTPDateTimestampHeaderListValues(vs []string) ([]string, error) {
|
||||
return splitHeaderListValues(vs, splitHTTPDateHeaderValue)
|
||||
}
|
||||
|
||||
func splitHTTPDateHeaderValue(v string) ([]string, error) {
|
||||
if n := strings.Count(v, ","); n <= 1 {
|
||||
// Nothing to do if only contains a no, or single HTTPDate value
|
||||
return []string{v}, nil
|
||||
} else if n%2 == 0 {
|
||||
return nil, fmt.Errorf("invalid timestamp HTTPDate header comma separations, %q", v)
|
||||
}
|
||||
|
||||
var parts []string
|
||||
var i, j int
|
||||
|
||||
var doSplit bool
|
||||
for ; i < len(v); i++ {
|
||||
if v[i] == ',' {
|
||||
if doSplit {
|
||||
doSplit = false
|
||||
parts = append(parts, strings.TrimSpace(v[j:i]))
|
||||
j = i + 1
|
||||
} else {
|
||||
// Skip the first comma in the timestamp value since that
|
||||
// separates the day from the rest of the timestamp.
|
||||
//
|
||||
// Tue, 17 Dec 2019 23:48:18 GMT
|
||||
doSplit = true
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add final part
|
||||
if j < len(v) {
|
||||
parts = append(parts, strings.TrimSpace(v[j:]))
|
||||
}
|
||||
|
||||
return parts, nil
|
||||
}
|
89
vendor/github.com/aws/smithy-go/transport/http/host.go
generated
vendored
Normal file
89
vendor/github.com/aws/smithy-go/transport/http/host.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ValidateEndpointHost validates that the host string passed in is a valid RFC
|
||||
// 3986 host. Returns error if the host is not valid.
|
||||
func ValidateEndpointHost(host string) error {
|
||||
var errors strings.Builder
|
||||
var hostname string
|
||||
var port string
|
||||
var err error
|
||||
|
||||
if strings.Contains(host, ":") {
|
||||
hostname, port, err = net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
errors.WriteString(fmt.Sprintf("\n endpoint %v, failed to parse, got ", host))
|
||||
errors.WriteString(err.Error())
|
||||
}
|
||||
|
||||
if !ValidPortNumber(port) {
|
||||
errors.WriteString(fmt.Sprintf("port number should be in range [0-65535], got %v", port))
|
||||
}
|
||||
} else {
|
||||
hostname = host
|
||||
}
|
||||
|
||||
labels := strings.Split(hostname, ".")
|
||||
for i, label := range labels {
|
||||
if i == len(labels)-1 && len(label) == 0 {
|
||||
// Allow trailing dot for FQDN hosts.
|
||||
continue
|
||||
}
|
||||
|
||||
if !ValidHostLabel(label) {
|
||||
errors.WriteString("\nendpoint host domain labels must match \"[a-zA-Z0-9-]{1,63}\", but found: ")
|
||||
errors.WriteString(label)
|
||||
}
|
||||
}
|
||||
|
||||
if len(hostname) == 0 && len(port) != 0 {
|
||||
errors.WriteString("\nendpoint host with port must not be empty")
|
||||
}
|
||||
|
||||
if len(hostname) > 255 {
|
||||
errors.WriteString(fmt.Sprintf("\nendpoint host must be less than 255 characters, but was %d", len(hostname)))
|
||||
}
|
||||
|
||||
if len(errors.String()) > 0 {
|
||||
return fmt.Errorf("invalid endpoint host%s", errors.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidPortNumber returns whether the port is valid RFC 3986 port.
|
||||
func ValidPortNumber(port string) bool {
|
||||
i, err := strconv.Atoi(port)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if i < 0 || i > 65535 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ValidHostLabel returns whether the label is a valid RFC 3986 host abel.
|
||||
func ValidHostLabel(label string) bool {
|
||||
if l := len(label); l == 0 || l > 63 {
|
||||
return false
|
||||
}
|
||||
for _, r := range label {
|
||||
switch {
|
||||
case r >= '0' && r <= '9':
|
||||
case r >= 'A' && r <= 'Z':
|
||||
case r >= 'a' && r <= 'z':
|
||||
case r == '-':
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
75
vendor/github.com/aws/smithy-go/transport/http/internal/io/safe.go
generated
vendored
Normal file
75
vendor/github.com/aws/smithy-go/transport/http/internal/io/safe.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
package io
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// NewSafeReadCloser returns a new safeReadCloser that wraps readCloser.
|
||||
func NewSafeReadCloser(readCloser io.ReadCloser) io.ReadCloser {
|
||||
sr := &safeReadCloser{
|
||||
readCloser: readCloser,
|
||||
}
|
||||
|
||||
if _, ok := readCloser.(io.WriterTo); ok {
|
||||
return &safeWriteToReadCloser{safeReadCloser: sr}
|
||||
}
|
||||
|
||||
return sr
|
||||
}
|
||||
|
||||
// safeWriteToReadCloser wraps a safeReadCloser but exposes a WriteTo interface implementation. This will panic
|
||||
// if the underlying io.ReadClose does not support WriteTo. Use NewSafeReadCloser to ensure the proper handling of this
|
||||
// type.
|
||||
type safeWriteToReadCloser struct {
|
||||
*safeReadCloser
|
||||
}
|
||||
|
||||
// WriteTo implements the io.WriteTo interface.
|
||||
func (r *safeWriteToReadCloser) WriteTo(w io.Writer) (int64, error) {
|
||||
r.safeReadCloser.mtx.Lock()
|
||||
defer r.safeReadCloser.mtx.Unlock()
|
||||
|
||||
if r.safeReadCloser.closed {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
return r.safeReadCloser.readCloser.(io.WriterTo).WriteTo(w)
|
||||
}
|
||||
|
||||
// safeReadCloser wraps a io.ReadCloser and presents an io.ReadCloser interface. When Close is called on safeReadCloser
|
||||
// the underlying Close method will be executed, and then the reference to the reader will be dropped. This type
|
||||
// is meant to be used with the net/http library which will retain a reference to the request body for the lifetime
|
||||
// of a goroutine connection. Wrapping in this manner will ensure that no data race conditions are falsely reported.
|
||||
// This type is thread-safe.
|
||||
type safeReadCloser struct {
|
||||
readCloser io.ReadCloser
|
||||
closed bool
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
// Read reads up to len(p) bytes into p from the underlying read. If the reader is closed io.EOF will be returned.
|
||||
func (r *safeReadCloser) Read(p []byte) (n int, err error) {
|
||||
r.mtx.Lock()
|
||||
defer r.mtx.Unlock()
|
||||
if r.closed {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
return r.readCloser.Read(p)
|
||||
}
|
||||
|
||||
// Close calls the underlying io.ReadCloser's Close method, removes the reference to the reader, and returns any error
|
||||
// reported from Close. Subsequent calls to Close will always return a nil error.
|
||||
func (r *safeReadCloser) Close() error {
|
||||
r.mtx.Lock()
|
||||
defer r.mtx.Unlock()
|
||||
if r.closed {
|
||||
return nil
|
||||
}
|
||||
|
||||
r.closed = true
|
||||
rc := r.readCloser
|
||||
r.readCloser = nil
|
||||
return rc.Close()
|
||||
}
|
25
vendor/github.com/aws/smithy-go/transport/http/md5_checksum.go
generated
vendored
Normal file
25
vendor/github.com/aws/smithy-go/transport/http/md5_checksum.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// computeMD5Checksum computes base64 md5 checksum of an io.Reader's contents.
|
||||
// Returns the byte slice of md5 checksum and an error.
|
||||
func computeMD5Checksum(r io.Reader) ([]byte, error) {
|
||||
h := md5.New()
|
||||
// copy errors may be assumed to be from the body.
|
||||
_, err := io.Copy(h, r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read body: %w", err)
|
||||
}
|
||||
|
||||
// encode the md5 checksum in base64.
|
||||
sum := h.Sum(nil)
|
||||
sum64 := make([]byte, base64.StdEncoding.EncodedLen(len(sum)))
|
||||
base64.StdEncoding.Encode(sum64, sum)
|
||||
return sum64, nil
|
||||
}
|
79
vendor/github.com/aws/smithy-go/transport/http/middleware_close_response_body.go
generated
vendored
Normal file
79
vendor/github.com/aws/smithy-go/transport/http/middleware_close_response_body.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// AddErrorCloseResponseBodyMiddleware adds the middleware to automatically
|
||||
// close the response body of an operation request if the request response
|
||||
// failed.
|
||||
func AddErrorCloseResponseBodyMiddleware(stack *middleware.Stack) error {
|
||||
return stack.Deserialize.Insert(&errorCloseResponseBodyMiddleware{}, "OperationDeserializer", middleware.Before)
|
||||
}
|
||||
|
||||
type errorCloseResponseBodyMiddleware struct{}
|
||||
|
||||
func (*errorCloseResponseBodyMiddleware) ID() string {
|
||||
return "ErrorCloseResponseBody"
|
||||
}
|
||||
|
||||
func (m *errorCloseResponseBodyMiddleware) HandleDeserialize(
|
||||
ctx context.Context, input middleware.DeserializeInput, next middleware.DeserializeHandler,
|
||||
) (
|
||||
output middleware.DeserializeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
out, metadata, err := next.HandleDeserialize(ctx, input)
|
||||
if err != nil {
|
||||
if resp, ok := out.RawResponse.(*Response); ok && resp != nil && resp.Body != nil {
|
||||
// Consume the full body to prevent TCP connection resets on some platforms
|
||||
_, _ = io.Copy(ioutil.Discard, resp.Body)
|
||||
// Do not validate that the response closes successfully.
|
||||
resp.Body.Close()
|
||||
}
|
||||
}
|
||||
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
// AddCloseResponseBodyMiddleware adds the middleware to automatically close
|
||||
// the response body of an operation request, after the response had been
|
||||
// deserialized.
|
||||
func AddCloseResponseBodyMiddleware(stack *middleware.Stack) error {
|
||||
return stack.Deserialize.Insert(&closeResponseBody{}, "OperationDeserializer", middleware.Before)
|
||||
}
|
||||
|
||||
type closeResponseBody struct{}
|
||||
|
||||
func (*closeResponseBody) ID() string {
|
||||
return "CloseResponseBody"
|
||||
}
|
||||
|
||||
func (m *closeResponseBody) HandleDeserialize(
|
||||
ctx context.Context, input middleware.DeserializeInput, next middleware.DeserializeHandler,
|
||||
) (
|
||||
output middleware.DeserializeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
out, metadata, err := next.HandleDeserialize(ctx, input)
|
||||
if err != nil {
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
if resp, ok := out.RawResponse.(*Response); ok {
|
||||
// Consume the full body to prevent TCP connection resets on some platforms
|
||||
_, copyErr := io.Copy(ioutil.Discard, resp.Body)
|
||||
if copyErr != nil {
|
||||
middleware.GetLogger(ctx).Logf(logging.Warn, "failed to discard remaining HTTP response body, this may affect connection reuse")
|
||||
}
|
||||
|
||||
closeErr := resp.Body.Close()
|
||||
if closeErr != nil {
|
||||
middleware.GetLogger(ctx).Logf(logging.Warn, "failed to close HTTP response body, this may affect connection reuse")
|
||||
}
|
||||
}
|
||||
|
||||
return out, metadata, err
|
||||
}
|
90
vendor/github.com/aws/smithy-go/transport/http/middleware_content_length.go
generated
vendored
Normal file
90
vendor/github.com/aws/smithy-go/transport/http/middleware_content_length.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
)
|
||||
|
||||
// ComputeContentLength provides a middleware to set the content-length
|
||||
// header for the length of a serialize request body.
|
||||
type ComputeContentLength struct {
|
||||
}
|
||||
|
||||
// AddComputeContentLengthMiddleware adds ComputeContentLength to the middleware
|
||||
// stack's Build step.
|
||||
func AddComputeContentLengthMiddleware(stack *middleware.Stack) error {
|
||||
return stack.Build.Add(&ComputeContentLength{}, middleware.After)
|
||||
}
|
||||
|
||||
// ID returns the identifier for the ComputeContentLength.
|
||||
func (m *ComputeContentLength) ID() string { return "ComputeContentLength" }
|
||||
|
||||
// HandleBuild adds the length of the serialized request to the HTTP header
|
||||
// if the length can be determined.
|
||||
func (m *ComputeContentLength) HandleBuild(
|
||||
ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler,
|
||||
) (
|
||||
out middleware.BuildOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := in.Request.(*Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown request type %T", req)
|
||||
}
|
||||
|
||||
// do nothing if request content-length was set to 0 or above.
|
||||
if req.ContentLength >= 0 {
|
||||
return next.HandleBuild(ctx, in)
|
||||
}
|
||||
|
||||
// attempt to compute stream length
|
||||
if n, ok, err := req.StreamLength(); err != nil {
|
||||
return out, metadata, fmt.Errorf(
|
||||
"failed getting length of request stream, %w", err)
|
||||
} else if ok {
|
||||
req.ContentLength = n
|
||||
if n == 0 {
|
||||
// If the content length could be determined, and the body is empty
|
||||
// the stream must be cleared to prevent unexpected chunk encoding.
|
||||
req, _ = req.SetStream(nil)
|
||||
in.Request = req
|
||||
}
|
||||
}
|
||||
|
||||
return next.HandleBuild(ctx, in)
|
||||
}
|
||||
|
||||
// validateContentLength provides a middleware to validate the content-length
|
||||
// is valid (greater than zero), for the serialized request payload.
|
||||
type validateContentLength struct{}
|
||||
|
||||
// ValidateContentLengthHeader adds middleware that validates request content-length
|
||||
// is set to value greater than zero.
|
||||
func ValidateContentLengthHeader(stack *middleware.Stack) error {
|
||||
return stack.Build.Add(&validateContentLength{}, middleware.After)
|
||||
}
|
||||
|
||||
// ID returns the identifier for the ComputeContentLength.
|
||||
func (m *validateContentLength) ID() string { return "ValidateContentLength" }
|
||||
|
||||
// HandleBuild adds the length of the serialized request to the HTTP header
|
||||
// if the length can be determined.
|
||||
func (m *validateContentLength) HandleBuild(
|
||||
ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler,
|
||||
) (
|
||||
out middleware.BuildOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := in.Request.(*Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown request type %T", req)
|
||||
}
|
||||
|
||||
// if request content-length was set to less than 0, return an error
|
||||
if req.ContentLength < 0 {
|
||||
return out, metadata, fmt.Errorf(
|
||||
"content length for payload is required and must be at least 0")
|
||||
}
|
||||
|
||||
return next.HandleBuild(ctx, in)
|
||||
}
|
88
vendor/github.com/aws/smithy-go/transport/http/middleware_headers.go
generated
vendored
Normal file
88
vendor/github.com/aws/smithy-go/transport/http/middleware_headers.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
)
|
||||
|
||||
type headerValue struct {
|
||||
header string
|
||||
value string
|
||||
append bool
|
||||
}
|
||||
|
||||
type headerValueHelper struct {
|
||||
headerValues []headerValue
|
||||
}
|
||||
|
||||
func (h *headerValueHelper) addHeaderValue(value headerValue) {
|
||||
h.headerValues = append(h.headerValues, value)
|
||||
}
|
||||
|
||||
func (h *headerValueHelper) ID() string {
|
||||
return "HTTPHeaderHelper"
|
||||
}
|
||||
|
||||
func (h *headerValueHelper) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) (out middleware.BuildOutput, metadata middleware.Metadata, err error) {
|
||||
req, ok := in.Request.(*Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown transport type %T", in.Request)
|
||||
}
|
||||
|
||||
for _, value := range h.headerValues {
|
||||
if value.append {
|
||||
req.Header.Add(value.header, value.value)
|
||||
} else {
|
||||
req.Header.Set(value.header, value.value)
|
||||
}
|
||||
}
|
||||
|
||||
return next.HandleBuild(ctx, in)
|
||||
}
|
||||
|
||||
func getOrAddHeaderValueHelper(stack *middleware.Stack) (*headerValueHelper, error) {
|
||||
id := (*headerValueHelper)(nil).ID()
|
||||
m, ok := stack.Build.Get(id)
|
||||
if !ok {
|
||||
m = &headerValueHelper{}
|
||||
err := stack.Build.Add(m, middleware.After)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
requestUserAgent, ok := m.(*headerValueHelper)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%T for %s middleware did not match expected type", m, id)
|
||||
}
|
||||
|
||||
return requestUserAgent, nil
|
||||
}
|
||||
|
||||
// AddHeaderValue returns a stack mutator that adds the header value pair to header.
|
||||
// Appends to any existing values if present.
|
||||
func AddHeaderValue(header string, value string) func(stack *middleware.Stack) error {
|
||||
return func(stack *middleware.Stack) error {
|
||||
helper, err := getOrAddHeaderValueHelper(stack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
helper.addHeaderValue(headerValue{header: header, value: value, append: true})
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetHeaderValue returns a stack mutator that adds the header value pair to header.
|
||||
// Replaces any existing values if present.
|
||||
func SetHeaderValue(header string, value string) func(stack *middleware.Stack) error {
|
||||
return func(stack *middleware.Stack) error {
|
||||
helper, err := getOrAddHeaderValueHelper(stack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
helper.addHeaderValue(headerValue{header: header, value: value, append: false})
|
||||
return nil
|
||||
}
|
||||
}
|
75
vendor/github.com/aws/smithy-go/transport/http/middleware_http_logging.go
generated
vendored
Normal file
75
vendor/github.com/aws/smithy-go/transport/http/middleware_http_logging.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http/httputil"
|
||||
|
||||
"github.com/aws/smithy-go/logging"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
)
|
||||
|
||||
// RequestResponseLogger is a deserialize middleware that will log the request and response HTTP messages and optionally
|
||||
// their respective bodies. Will not perform any logging if none of the options are set.
|
||||
type RequestResponseLogger struct {
|
||||
LogRequest bool
|
||||
LogRequestWithBody bool
|
||||
|
||||
LogResponse bool
|
||||
LogResponseWithBody bool
|
||||
}
|
||||
|
||||
// ID is the middleware identifier.
|
||||
func (r *RequestResponseLogger) ID() string {
|
||||
return "RequestResponseLogger"
|
||||
}
|
||||
|
||||
// HandleDeserialize will log the request and response HTTP messages if configured accordingly.
|
||||
func (r *RequestResponseLogger) HandleDeserialize(
|
||||
ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler,
|
||||
) (
|
||||
out middleware.DeserializeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
logger := middleware.GetLogger(ctx)
|
||||
|
||||
if r.LogRequest || r.LogRequestWithBody {
|
||||
smithyRequest, ok := in.Request.(*Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown transport type %T", in)
|
||||
}
|
||||
|
||||
rc := smithyRequest.Build(ctx)
|
||||
reqBytes, err := httputil.DumpRequestOut(rc, r.LogRequestWithBody)
|
||||
if err != nil {
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
logger.Logf(logging.Debug, "Request\n%v", string(reqBytes))
|
||||
|
||||
if r.LogRequestWithBody {
|
||||
smithyRequest, err = smithyRequest.SetStream(rc.Body)
|
||||
if err != nil {
|
||||
return out, metadata, err
|
||||
}
|
||||
in.Request = smithyRequest
|
||||
}
|
||||
}
|
||||
|
||||
out, metadata, err = next.HandleDeserialize(ctx, in)
|
||||
|
||||
if (err == nil) && (r.LogResponse || r.LogResponseWithBody) {
|
||||
smithyResponse, ok := out.RawResponse.(*Response)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown transport type %T", out.RawResponse)
|
||||
}
|
||||
|
||||
respBytes, err := httputil.DumpResponse(smithyResponse.Response, r.LogResponseWithBody)
|
||||
if err != nil {
|
||||
return out, metadata, fmt.Errorf("failed to dump response %w", err)
|
||||
}
|
||||
|
||||
logger.Logf(logging.Debug, "Response\n%v", string(respBytes))
|
||||
}
|
||||
|
||||
return out, metadata, err
|
||||
}
|
51
vendor/github.com/aws/smithy-go/transport/http/middleware_metadata.go
generated
vendored
Normal file
51
vendor/github.com/aws/smithy-go/transport/http/middleware_metadata.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
)
|
||||
|
||||
type (
|
||||
hostnameImmutableKey struct{}
|
||||
hostPrefixDisableKey struct{}
|
||||
)
|
||||
|
||||
// GetHostnameImmutable retrieves whether the endpoint hostname should be considered
|
||||
// immutable or not.
|
||||
//
|
||||
// Scoped to stack values. Use middleware#ClearStackValues to clear all stack
|
||||
// values.
|
||||
func GetHostnameImmutable(ctx context.Context) (v bool) {
|
||||
v, _ = middleware.GetStackValue(ctx, hostnameImmutableKey{}).(bool)
|
||||
return v
|
||||
}
|
||||
|
||||
// SetHostnameImmutable sets or modifies whether the request's endpoint hostname
|
||||
// should be considered immutable or not.
|
||||
//
|
||||
// Scoped to stack values. Use middleware#ClearStackValues to clear all stack
|
||||
// values.
|
||||
func SetHostnameImmutable(ctx context.Context, value bool) context.Context {
|
||||
return middleware.WithStackValue(ctx, hostnameImmutableKey{}, value)
|
||||
}
|
||||
|
||||
// IsEndpointHostPrefixDisabled retrieves whether the hostname prefixing is
|
||||
// disabled.
|
||||
//
|
||||
// Scoped to stack values. Use middleware#ClearStackValues to clear all stack
|
||||
// values.
|
||||
func IsEndpointHostPrefixDisabled(ctx context.Context) (v bool) {
|
||||
v, _ = middleware.GetStackValue(ctx, hostPrefixDisableKey{}).(bool)
|
||||
return v
|
||||
}
|
||||
|
||||
// DisableEndpointHostPrefix sets or modifies whether the request's endpoint host
|
||||
// prefixing should be disabled. If value is true, endpoint host prefixing
|
||||
// will be disabled.
|
||||
//
|
||||
// Scoped to stack values. Use middleware#ClearStackValues to clear all stack
|
||||
// values.
|
||||
func DisableEndpointHostPrefix(ctx context.Context, value bool) context.Context {
|
||||
return middleware.WithStackValue(ctx, hostPrefixDisableKey{}, value)
|
||||
}
|
79
vendor/github.com/aws/smithy-go/transport/http/middleware_min_proto.go
generated
vendored
Normal file
79
vendor/github.com/aws/smithy-go/transport/http/middleware_min_proto.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MinimumProtocolError is an error type indicating that the established connection did not meet the expected minimum
|
||||
// HTTP protocol version.
|
||||
type MinimumProtocolError struct {
|
||||
proto string
|
||||
expectedProtoMajor int
|
||||
expectedProtoMinor int
|
||||
}
|
||||
|
||||
// Error returns the error message.
|
||||
func (m *MinimumProtocolError) Error() string {
|
||||
return fmt.Sprintf("operation requires minimum HTTP protocol of HTTP/%d.%d, but was %s",
|
||||
m.expectedProtoMajor, m.expectedProtoMinor, m.proto)
|
||||
}
|
||||
|
||||
// RequireMinimumProtocol is a deserialization middleware that asserts that the established HTTP connection
|
||||
// meets the minimum major ad minor version.
|
||||
type RequireMinimumProtocol struct {
|
||||
ProtoMajor int
|
||||
ProtoMinor int
|
||||
}
|
||||
|
||||
// AddRequireMinimumProtocol adds the RequireMinimumProtocol middleware to the stack using the provided minimum
|
||||
// protocol major and minor version.
|
||||
func AddRequireMinimumProtocol(stack *middleware.Stack, major, minor int) error {
|
||||
return stack.Deserialize.Insert(&RequireMinimumProtocol{
|
||||
ProtoMajor: major,
|
||||
ProtoMinor: minor,
|
||||
}, "OperationDeserializer", middleware.Before)
|
||||
}
|
||||
|
||||
// ID returns the middleware identifier string.
|
||||
func (r *RequireMinimumProtocol) ID() string {
|
||||
return "RequireMinimumProtocol"
|
||||
}
|
||||
|
||||
// HandleDeserialize asserts that the established connection is a HTTP connection with the minimum major and minor
|
||||
// protocol version.
|
||||
func (r *RequireMinimumProtocol) HandleDeserialize(
|
||||
ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler,
|
||||
) (
|
||||
out middleware.DeserializeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
out, metadata, err = next.HandleDeserialize(ctx, in)
|
||||
if err != nil {
|
||||
return out, metadata, err
|
||||
}
|
||||
|
||||
response, ok := out.RawResponse.(*Response)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unknown transport type: %T", out.RawResponse)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(response.Proto, "HTTP") {
|
||||
return out, metadata, &MinimumProtocolError{
|
||||
proto: response.Proto,
|
||||
expectedProtoMajor: r.ProtoMajor,
|
||||
expectedProtoMinor: r.ProtoMinor,
|
||||
}
|
||||
}
|
||||
|
||||
if response.ProtoMajor < r.ProtoMajor || response.ProtoMinor < r.ProtoMinor {
|
||||
return out, metadata, &MinimumProtocolError{
|
||||
proto: response.Proto,
|
||||
expectedProtoMajor: r.ProtoMajor,
|
||||
expectedProtoMinor: r.ProtoMinor,
|
||||
}
|
||||
}
|
||||
|
||||
return out, metadata, err
|
||||
}
|
154
vendor/github.com/aws/smithy-go/transport/http/request.go
generated
vendored
Normal file
154
vendor/github.com/aws/smithy-go/transport/http/request.go
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
iointernal "github.com/aws/smithy-go/transport/http/internal/io"
|
||||
)
|
||||
|
||||
// Request provides the HTTP specific request structure for HTTP specific
|
||||
// middleware steps to use to serialize input, and send an operation's request.
|
||||
type Request struct {
|
||||
*http.Request
|
||||
stream io.Reader
|
||||
isStreamSeekable bool
|
||||
streamStartPos int64
|
||||
}
|
||||
|
||||
// NewStackRequest returns an initialized request ready to be populated with the
|
||||
// HTTP request details. Returns empty interface so the function can be used as
|
||||
// a parameter to the Smithy middleware Stack constructor.
|
||||
func NewStackRequest() interface{} {
|
||||
return &Request{
|
||||
Request: &http.Request{
|
||||
URL: &url.URL{},
|
||||
Header: http.Header{},
|
||||
ContentLength: -1, // default to unknown length
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Clone returns a deep copy of the Request for the new context. A reference to
|
||||
// the Stream is copied, but the underlying stream is not copied.
|
||||
func (r *Request) Clone() *Request {
|
||||
rc := *r
|
||||
rc.Request = rc.Request.Clone(context.TODO())
|
||||
return &rc
|
||||
}
|
||||
|
||||
// StreamLength returns the number of bytes of the serialized stream attached
|
||||
// to the request and ok set. If the length cannot be determined, an error will
|
||||
// be returned.
|
||||
func (r *Request) StreamLength() (size int64, ok bool, err error) {
|
||||
if r.stream == nil {
|
||||
return 0, true, nil
|
||||
}
|
||||
|
||||
if l, ok := r.stream.(interface{ Len() int }); ok {
|
||||
return int64(l.Len()), true, nil
|
||||
}
|
||||
|
||||
if !r.isStreamSeekable {
|
||||
return 0, false, nil
|
||||
}
|
||||
|
||||
s := r.stream.(io.Seeker)
|
||||
endOffset, err := s.Seek(0, io.SeekEnd)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
|
||||
// The reason to seek to streamStartPos instead of 0 is to ensure that the
|
||||
// SDK only sends the stream from the starting position the user's
|
||||
// application provided it to the SDK at. For example application opens a
|
||||
// file, and wants to skip the first N bytes uploading the rest. The
|
||||
// application would move the file's offset N bytes, then hand it off to
|
||||
// the SDK to send the remaining. The SDK should respect that initial offset.
|
||||
_, err = s.Seek(r.streamStartPos, io.SeekStart)
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
|
||||
return endOffset - r.streamStartPos, true, nil
|
||||
}
|
||||
|
||||
// RewindStream will rewind the io.Reader to the relative start position if it
|
||||
// is an io.Seeker.
|
||||
func (r *Request) RewindStream() error {
|
||||
// If there is no stream there is nothing to rewind.
|
||||
if r.stream == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !r.isStreamSeekable {
|
||||
return fmt.Errorf("request stream is not seekable")
|
||||
}
|
||||
_, err := r.stream.(io.Seeker).Seek(r.streamStartPos, io.SeekStart)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetStream returns the request stream io.Reader if a stream is set. If no
|
||||
// stream is present nil will be returned.
|
||||
func (r *Request) GetStream() io.Reader {
|
||||
return r.stream
|
||||
}
|
||||
|
||||
// IsStreamSeekable returns whether the stream is seekable.
|
||||
func (r *Request) IsStreamSeekable() bool {
|
||||
return r.isStreamSeekable
|
||||
}
|
||||
|
||||
// SetStream returns a clone of the request with the stream set to the provided reader.
|
||||
// May return an error if the provided reader is seekable but returns an error.
|
||||
func (r *Request) SetStream(reader io.Reader) (rc *Request, err error) {
|
||||
rc = r.Clone()
|
||||
|
||||
switch v := reader.(type) {
|
||||
case io.Seeker:
|
||||
n, err := v.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
rc.isStreamSeekable = true
|
||||
rc.streamStartPos = n
|
||||
default:
|
||||
rc.isStreamSeekable = false
|
||||
}
|
||||
rc.stream = reader
|
||||
|
||||
return rc, err
|
||||
}
|
||||
|
||||
// Build returns a build standard HTTP request value from the Smithy request.
|
||||
// The request's stream is wrapped in a safe container that allows it to be
|
||||
// reused for subsequent attempts.
|
||||
func (r *Request) Build(ctx context.Context) *http.Request {
|
||||
req := r.Request.Clone(ctx)
|
||||
|
||||
if r.stream == nil && req.ContentLength == -1 {
|
||||
req.ContentLength = 0
|
||||
}
|
||||
|
||||
switch stream := r.stream.(type) {
|
||||
case *io.PipeReader:
|
||||
req.Body = ioutil.NopCloser(stream)
|
||||
req.ContentLength = -1
|
||||
default:
|
||||
if r.stream != nil {
|
||||
req.Body = iointernal.NewSafeReadCloser(ioutil.NopCloser(stream))
|
||||
}
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
||||
|
||||
// RequestCloner is a function that can take an input request type and clone the request
|
||||
// for use in a subsequent retry attempt.
|
||||
func RequestCloner(v interface{}) interface{} {
|
||||
return v.(*Request).Clone()
|
||||
}
|
34
vendor/github.com/aws/smithy-go/transport/http/response.go
generated
vendored
Normal file
34
vendor/github.com/aws/smithy-go/transport/http/response.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Response provides the HTTP specific response structure for HTTP specific
|
||||
// middleware steps to use to deserialize the response from an operation call.
|
||||
type Response struct {
|
||||
*http.Response
|
||||
}
|
||||
|
||||
// ResponseError provides the HTTP centric error type wrapping the underlying
|
||||
// error with the HTTP response value.
|
||||
type ResponseError struct {
|
||||
Response *Response
|
||||
Err error
|
||||
}
|
||||
|
||||
// HTTPStatusCode returns the HTTP response status code received from the service.
|
||||
func (e *ResponseError) HTTPStatusCode() int { return e.Response.StatusCode }
|
||||
|
||||
// HTTPResponse returns the HTTP response received from the service.
|
||||
func (e *ResponseError) HTTPResponse() *Response { return e.Response }
|
||||
|
||||
// Unwrap returns the nested error if any, or nil.
|
||||
func (e *ResponseError) Unwrap() error { return e.Err }
|
||||
|
||||
func (e *ResponseError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"http response error StatusCode: %d, %v",
|
||||
e.Response.StatusCode, e.Err)
|
||||
}
|
13
vendor/github.com/aws/smithy-go/transport/http/time.go
generated
vendored
Normal file
13
vendor/github.com/aws/smithy-go/transport/http/time.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
smithytime "github.com/aws/smithy-go/time"
|
||||
)
|
||||
|
||||
// ParseTime parses a time string like the HTTP Date header. This uses a more
|
||||
// relaxed rule set for date parsing compared to the standard library.
|
||||
func ParseTime(text string) (t time.Time, err error) {
|
||||
return smithytime.ParseHTTPDate(text)
|
||||
}
|
44
vendor/github.com/aws/smithy-go/transport/http/url.go
generated
vendored
Normal file
44
vendor/github.com/aws/smithy-go/transport/http/url.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
package http
|
||||
|
||||
import "strings"
|
||||
|
||||
// JoinPath returns an absolute URL path composed of the two paths provided.
|
||||
// Enforces that the returned path begins with '/'. If added path is empty the
|
||||
// returned path suffix will match the first parameter suffix.
|
||||
func JoinPath(a, b string) string {
|
||||
if len(a) == 0 {
|
||||
a = "/"
|
||||
} else if a[0] != '/' {
|
||||
a = "/" + a
|
||||
}
|
||||
|
||||
if len(b) != 0 && b[0] == '/' {
|
||||
b = b[1:]
|
||||
}
|
||||
|
||||
if len(b) != 0 && len(a) > 1 && a[len(a)-1] != '/' {
|
||||
a = a + "/"
|
||||
}
|
||||
|
||||
return a + b
|
||||
}
|
||||
|
||||
// JoinRawQuery returns an absolute raw query expression. Any duplicate '&'
|
||||
// will be collapsed to single separator between values.
|
||||
func JoinRawQuery(a, b string) string {
|
||||
a = strings.TrimFunc(a, isAmpersand)
|
||||
b = strings.TrimFunc(b, isAmpersand)
|
||||
|
||||
if len(a) == 0 {
|
||||
return b
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return a
|
||||
}
|
||||
|
||||
return a + "&" + b
|
||||
}
|
||||
|
||||
func isAmpersand(v rune) bool {
|
||||
return v == '&'
|
||||
}
|
37
vendor/github.com/aws/smithy-go/transport/http/user_agent.go
generated
vendored
Normal file
37
vendor/github.com/aws/smithy-go/transport/http/user_agent.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UserAgentBuilder is a builder for a HTTP User-Agent string.
|
||||
type UserAgentBuilder struct {
|
||||
sb strings.Builder
|
||||
}
|
||||
|
||||
// NewUserAgentBuilder returns a new UserAgentBuilder.
|
||||
func NewUserAgentBuilder() *UserAgentBuilder {
|
||||
return &UserAgentBuilder{sb: strings.Builder{}}
|
||||
}
|
||||
|
||||
// AddKey adds the named component/product to the agent string
|
||||
func (u *UserAgentBuilder) AddKey(key string) {
|
||||
u.appendTo(key)
|
||||
}
|
||||
|
||||
// AddKeyValue adds the named key to the agent string with the given value.
|
||||
func (u *UserAgentBuilder) AddKeyValue(key, value string) {
|
||||
u.appendTo(key + "/" + value)
|
||||
}
|
||||
|
||||
// Build returns the constructed User-Agent string. May be called multiple times.
|
||||
func (u *UserAgentBuilder) Build() string {
|
||||
return u.sb.String()
|
||||
}
|
||||
|
||||
func (u *UserAgentBuilder) appendTo(value string) {
|
||||
if u.sb.Len() > 0 {
|
||||
u.sb.WriteRune(' ')
|
||||
}
|
||||
u.sb.WriteString(value)
|
||||
}
|
Reference in New Issue
Block a user