func (u *uploader) upload() (*UploadOutput, error) {
	u.init()
	if u.ctx.PartSize < MinUploadPartSize {
		msg := fmt.Sprintf("part size must be at least %d bytes", MinUploadPartSize)
		return nil, awserr.New("ConfigError", msg, nil)
	}
	reader, _, err := u.nextReader()
	if err == io.EOF {  
		return u.singlePart(reader)
	} else if err != nil {
		return nil, awserr.New("ReadRequestBody", "read upload data failed", err)
	}
	mu := multiuploader{uploader: u}
	return mu.upload(reader)
}
internal logic for deciding whether to upload a single part or use a
multipart upload.
package s3manager
import (
	"bytes"
	"fmt"
	"io"
	"sort"
	"sync"
	"time"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/awsutil"
	"github.com/aws/aws-sdk-go/aws/client"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3iface"
)
const MaxUploadParts = 10000
const MinUploadPartSize int64 = 1024 * 1024 * 5
const DefaultUploadPartSize = MinUploadPartSize
const DefaultUploadConcurrency = 5
type MultiUploadFailure interface {
	awserr.Error
	UploadID() string
}
type awsError awserr.Error
type multiUploadError struct {
	awsError
	uploadID string
}
func (m multiUploadError) Error() string {
	extra := fmt.Sprintf("upload id: %s", m.uploadID)
	return awserr.SprintError(m.Code(), m.Message(), extra, m.OrigErr())
}
func (m multiUploadError) String() string {
	return m.Error()
}
func (m multiUploadError) UploadID() string {
	return m.uploadID
}
type UploadInput struct {
	ACL *string `location:"header" locationName:"x-amz-acl" type:"string"`
	Bucket *string `location:"uri" locationName:"Bucket" type:"string" required:"true"`
	CacheControl *string `location:"header" locationName:"Cache-Control" type:"string"`
	ContentDisposition *string `location:"header" locationName:"Content-Disposition" type:"string"`
	ContentEncoding *string `location:"header" locationName:"Content-Encoding" type:"string"`
	ContentLanguage *string `location:"header" locationName:"Content-Language" type:"string"`
	ContentType *string `location:"header" locationName:"Content-Type" type:"string"`
	Expires *time.Time `location:"header" locationName:"Expires" type:"timestamp" timestampFormat:"rfc822"`
	GrantFullControl *string `location:"header" locationName:"x-amz-grant-full-control" type:"string"`
	GrantRead *string `location:"header" locationName:"x-amz-grant-read" type:"string"`
	GrantReadACP *string `location:"header" locationName:"x-amz-grant-read-acp" type:"string"`
	GrantWriteACP *string `location:"header" locationName:"x-amz-grant-write-acp" type:"string"`
	Key *string `location:"uri" locationName:"Key" type:"string" required:"true"`
	Metadata map[string]*string `location:"headers" locationName:"x-amz-meta-" type:"map"`
	RequestPayer *string `location:"header" locationName:"x-amz-request-payer" type:"string"`
	SSECustomerAlgorithm *string `location:"header" locationName:"x-amz-server-side-encryption-customer-algorithm" type:"string"`
	SSECustomerKey *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key" type:"string"`
	SSECustomerKeyMD5 *string `location:"header" locationName:"x-amz-server-side-encryption-customer-key-MD5" type:"string"`
	SSEKMSKeyId *string `location:"header" locationName:"x-amz-server-side-encryption-aws-kms-key-id" type:"string"`
	ServerSideEncryption *string `location:"header" locationName:"x-amz-server-side-encryption" type:"string"`
	StorageClass *string `location:"header" locationName:"x-amz-storage-class" type:"string"`
	WebsiteRedirectLocation *string `location:"header" locationName:"x-amz-website-redirect-location" type:"string"`
	Body io.Reader
}
type UploadOutput struct {
	Location string
	VersionID *string
	UploadID string
}
type Uploader struct {
	PartSize int64
	Concurrency int
	LeavePartsOnError bool
	MaxUploadParts int
	S3 s3iface.S3API
}
func NewUploader(c client.ConfigProvider, options ...func(*Uploader)) *Uploader {
	u := &Uploader{
		S3:                s3.New(c),
		PartSize:          DefaultUploadPartSize,
		Concurrency:       DefaultUploadConcurrency,
		LeavePartsOnError: false,
		MaxUploadParts:    MaxUploadParts,
	}
	for _, option := range options {
		option(u)
	}
	return u
}
func NewUploaderWithClient(svc s3iface.S3API, options ...func(*Uploader)) *Uploader {
	u := &Uploader{
		S3:                svc,
		PartSize:          DefaultUploadPartSize,
		Concurrency:       DefaultUploadConcurrency,
		LeavePartsOnError: false,
		MaxUploadParts:    MaxUploadParts,
	}
	for _, option := range options {
		option(u)
	}
	return u
}
func (u Uploader) Upload(input *UploadInput, options ...func(*Uploader)) (*UploadOutput, error) {
	i := uploader{in: input, ctx: u}
	for _, option := range options {
		option(&i.ctx)
	}
	return i.upload()
}
type uploader struct {
	ctx Uploader
	in *UploadInput
	readerPos int64  
	totalSize int64  
}