func isDefaultPort(scheme, port string) bool {
	if port == "" {
		return true
	}
	lowerCaseScheme := strings.ToLower(scheme)
	if (lowerCaseScheme == "http" && port == "80") || (lowerCaseScheme == "https" && port == "443") {
		return true
	}
	return false
}
Returns true if the specified URI is using the standard port
(i.e. port 80 for HTTP URIs or 443 for HTTPS URIs)
package request
import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"reflect"
	"strings"
	"time"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/client/metadata"
	"github.com/aws/aws-sdk-go/internal/sdkio"
)
const (
	ErrCodeSerialization = "SerializationError"
	ErrCodeRead = "ReadError"
	ErrCodeResponseTimeout = "ResponseTimeout"
	ErrCodeInvalidPresignExpire = "InvalidPresignExpireError"
	CanceledErrorCode = "RequestCanceled"
	ErrCodeRequestError = "RequestError"
)
type Request struct {
	Config     aws.Config
	ClientInfo metadata.ClientInfo
	Handlers   Handlers
	Retryer
	AttemptTime            time.Time
	Time                   time.Time
	Operation              *Operation
	HTTPRequest            *http.Request
	HTTPResponse           *http.Response
	Body                   io.ReadSeeker
	streamingBody          io.ReadCloser
	BodyStart              int64  
	Params                 interface{}
	Error                  error
	Data                   interface{}
	RequestID              string
	RetryCount             int
	Retryable              *bool
	RetryDelay             time.Duration
	NotHoist               bool
	SignedHeaderVals       http.Header
	LastSignedAt           time.Time
	DisableFollowRedirects bool
	RetryErrorCodes []string
	ThrottleErrorCodes []string
	ExpireTime time.Duration
	context aws.Context
	built bool
	safeBody *offsetReader
}
type Operation struct {
	Name       string
	HTTPMethod string
	HTTPPath   string
	*Paginator
	BeforePresignFn func(r *Request) error
}
func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
	retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request {
	if retryer == nil {
		retryer = noOpRetryer{}
	}
	method := operation.HTTPMethod
	if method == "" {
		method = "POST"
	}
	httpReq, _ := http.NewRequest(method, "", nil)
	var err error
	httpReq.URL, err = url.Parse(clientInfo.Endpoint + operation.HTTPPath)
	if err != nil {
		httpReq.URL = &url.URL{}
		err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err)
	}
	r := &Request{
		Config:     cfg,
		ClientInfo: clientInfo,
		Handlers:   handlers.Copy(),
		Retryer:     retryer,
		Time:        time.Now(),
		ExpireTime:  0,
		Operation:   operation,
		HTTPRequest: httpReq,
		Body:        nil,
		Params:      params,
		Error:       err,
		Data:        data,
	}
	r.SetBufferBody([]byte{})
	return r
}
type Option func(*Request)
func WithGetResponseHeader(key string, val *string) Option {
	return func(r *Request) {
		r.Handlers.Complete.PushBack(func(req *Request) {
			*val = req.HTTPResponse.Header.Get(key)
		})
	}
}
func WithGetResponseHeaders(headers *http.Header) Option {
	return func(r *Request) {
		r.Handlers.Complete.PushBack(func(req *Request) {
			*headers = req.HTTPResponse.Header
		})
	}
}
func WithLogLevel(l aws.LogLevelType) Option {
	return func(r *Request) {
		r.Config.LogLevel = aws.LogLevel(l)
	}
}
func (r *Request) ApplyOptions(opts ...Option) {
	for _, opt := range opts {
		opt(r)
	}
}
func (r *Request) Context() aws.Context {
	if r.context != nil {
		return r.context
	}
	return aws.BackgroundContext()
}
func (r *Request) SetContext(ctx aws.Context) {
	if ctx == nil {
		panic("context cannot be nil")
	}
	setRequestContext(r, ctx)
}
func (r *Request) WillRetry() bool {
	if !aws.IsReaderSeekable(r.Body) && r.HTTPRequest.Body != NoBody {
		return false
	}
	return r.Error != nil && aws.BoolValue(r.Retryable) && r.RetryCount < r.MaxRetries()
}
func fmtAttemptCount(retryCount, maxRetries int) string {
	return fmt.Sprintf("attempt %v/%v", retryCount, maxRetries)
}
func (r *Request) ParamsFilled() bool {
	return r.Params != nil && reflect.ValueOf(r.Params).Elem().IsValid()
}
func (r *Request) DataFilled() bool {
	return r.Data != nil && reflect.ValueOf(r.Data).Elem().IsValid()
}
func (r *Request) SetBufferBody(buf []byte) {
	r.SetReaderBody(bytes.NewReader(buf))
}
func (r *Request) SetStringBody(s string) {
	r.SetReaderBody(strings.NewReader(s))
}
func (r *Request) SetReaderBody(reader io.ReadSeeker) {
	r.Body = reader
	if aws.IsReaderSeekable(reader) {
		var err error
		r.BodyStart, err = reader.Seek(0, sdkio.SeekCurrent)
		if err != nil {
			r.Error = awserr.New(ErrCodeSerialization,
				"failed to determine start of request body", err)
			return
		}
	}
	r.ResetBody()
}
func (r *Request) SetStreamingBody(reader io.ReadCloser) {
	r.streamingBody = reader
	r.SetReaderBody(aws.ReadSeekCloser(reader))
}
func (r *Request) Presign(expire time.Duration) (string, error) {
	r = r.copy()
	r.NotHoist = false
	u, _, err := getPresignedURL(r, expire)
	return u, err
}
func (r *Request) PresignRequest(expire time.Duration) (string, http.Header, error) {
	r = r.copy()
	return getPresignedURL(r, expire)
}
func (r *Request) IsPresigned() bool {
	return r.ExpireTime != 0
}
func getPresignedURL(r *Request, expire time.Duration) (string, http.Header, error) {
	if expire <= 0 {
		return "", nil, awserr.New(
			ErrCodeInvalidPresignExpire,
			"presigned URL requires an expire duration greater than 0",
			nil,
		)
	}
	r.ExpireTime = expire
	if r.Operation.BeforePresignFn != nil {
		if err := r.Operation.BeforePresignFn(r); err != nil {
			return "", nil, err
		}
	}
	if err := r.Sign(); err != nil {
		return "", nil, err
	}
	return r.HTTPRequest.URL.String(), r.SignedHeaderVals, nil
}
const (
	notRetrying = "not retrying"
)
func debugLogReqError(r *Request, stage, retryStr string, err error) {
	if !r.Config.LogLevel.Matches(aws.LogDebugWithRequestErrors) {
		return
	}
	r.Config.Logger.Log(fmt.Sprintf("DEBUG: %s %s/%s failed, %s, error %v",
		stage, r.ClientInfo.ServiceName, r.Operation.Name, retryStr, err))
}
func (r *Request) Build() error {
	if !r.built {
		r.Handlers.Validate.Run(r)
		if r.Error != nil {
			debugLogReqError(r, "Validate Request", notRetrying, r.Error)
			return r.Error
		}
		r.Handlers.Build.Run(r)
		if r.Error != nil {
			debugLogReqError(r, "Build Request", notRetrying, r.Error)
			return r.Error
		}
		r.built = true
	}
	return r.Error
}
func (r *Request) Sign() error {
	r.Build()
	if r.Error != nil {
		debugLogReqError(r, "Build Request", notRetrying, r.Error)
		return r.Error
	}
	SanitizeHostForHeader(r.HTTPRequest)
	r.Handlers.Sign.Run(r)
	return r.Error
}
func (r *Request) getNextRequestBody() (body io.ReadCloser, err error) {
	if r.streamingBody != nil {
		return r.streamingBody, nil
	}
	if r.safeBody != nil {
		r.safeBody.Close()
	}
	r.safeBody, err = newOffsetReader(r.Body, r.BodyStart)
	if err != nil {
		return nil, awserr.New(ErrCodeSerialization,
			"failed to get next request body reader", err)
	}
	l, err := aws.SeekerLen(r.Body)
	if err != nil {
		return nil, awserr.New(ErrCodeSerialization,
			"failed to compute request body size", err)
	}
	if l == 0 {
		body = NoBody
	} else if l > 0 {
		body = r.safeBody
	} else {
		switch r.Operation.HTTPMethod {
		case "GET", "HEAD", "DELETE":
			body = NoBody
		default:
			body = r.safeBody
		}
	}
	return body, nil
}
func (r *Request) GetBody() io.ReadSeeker {
	return r.safeBody
}
func (r *Request) Send() error {
	defer func() {
		r.Handlers.Complete.Run(r)
	}()
	if err := r.Error; err != nil {
		return err
	}
	for {
		r.Error = nil
		r.AttemptTime = time.Now()
		if err := r.Sign(); err != nil {
			debugLogReqError(r, "Sign Request", notRetrying, err)
			return err
		}
		if err := r.sendRequest(); err == nil {
			return nil
		}
		r.Handlers.Retry.Run(r)
		r.Handlers.AfterRetry.Run(r)
		if r.Error != nil || !aws.BoolValue(r.Retryable) {
			return r.Error
		}
		if err := r.prepareRetry(); err != nil {
			r.Error = err
			return err
		}
	}
}
func (r *Request) prepareRetry() error {
	if r.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) {
		r.Config.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d",
			r.ClientInfo.ServiceName, r.Operation.Name, r.RetryCount))
	}
	r.HTTPRequest = copyHTTPRequest(r.HTTPRequest, nil)
	r.ResetBody()
	if err := r.Error; err != nil {
		return awserr.New(ErrCodeSerialization,
			"failed to prepare body for retry", err)
	}
	if r.HTTPResponse != nil && r.HTTPResponse.Body != nil {
		r.HTTPResponse.Body.Close()
	}
	return nil
}
func (r *Request) sendRequest() (sendErr error) {
	defer r.Handlers.CompleteAttempt.Run(r)
	r.Retryable = nil
	r.Handlers.Send.Run(r)
	if r.Error != nil {
		debugLogReqError(r, "Send Request",
			fmtAttemptCount(r.RetryCount, r.MaxRetries()),
			r.Error)
		return r.Error
	}
	r.Handlers.UnmarshalMeta.Run(r)
	r.Handlers.ValidateResponse.Run(r)
	if r.Error != nil {
		r.Handlers.UnmarshalError.Run(r)
		debugLogReqError(r, "Validate Response",
			fmtAttemptCount(r.RetryCount, r.MaxRetries()),
			r.Error)
		return r.Error
	}
	r.Handlers.Unmarshal.Run(r)
	if r.Error != nil {
		debugLogReqError(r, "Unmarshal Response",
			fmtAttemptCount(r.RetryCount, r.MaxRetries()),
			r.Error)
		return r.Error
	}
	return nil
}
func (r *Request) copy() *Request {
	req := &Request{}
	*req = *r
	req.Handlers = r.Handlers.Copy()
	op := *r.Operation
	req.Operation = &op
	return req
}
func AddToUserAgent(r *Request, s string) {
	curUA := r.HTTPRequest.Header.Get("User-Agent")
	if len(curUA) > 0 {
		s = curUA + " " + s
	}
	r.HTTPRequest.Header.Set("User-Agent", s)
}
func SanitizeHostForHeader(r *http.Request) {
	host := getHost(r)
	port := portOnly(host)
	if port != "" && isDefaultPort(r.URL.Scheme, port) {
		r.Host = stripPort(host)
	}
}
func getHost(r *http.Request) string {
	if r.Host != "" {
		return r.Host
	}
	if r.URL == nil {
		return ""
	}
	return r.URL.Host
}
func stripPort(hostport string) string {
	colon := strings.IndexByte(hostport, ':')
	if colon == -1 {
		return hostport
	}
	if i := strings.IndexByte(hostport, ']'); i != -1 {
		return strings.TrimPrefix(hostport[:i], "[")
	}
	return hostport[:colon]
}
func portOnly(hostport string) string {
	colon := strings.IndexByte(hostport, ':')
	if colon == -1 {
		return ""
	}
	if i := strings.Index(hostport, "]:"); i != -1 {
		return hostport[i+len("]:"):]
	}
	if strings.Contains(hostport, "]") {
		return ""
	}
	return hostport[colon+len(":"):]
}