Documentation
¶
Overview ¶
Package s3 is an S3 client that builds with TinyGo.
The maintained Go clients cannot be used here. aws-sdk-go-v2 reaches for the full net/http.Transport API, which TinyGo declares as an empty struct, and its transport layer imports net/http/httputil, which does not compile under TinyGo at all. This package therefore speaks the S3 REST API directly: a SigV4 signer, request builders, and XML decoding, over whichever HTTP stack the build selects.
client, err := s3.New(
s3.WithRegion("ap-northeast-1"),
s3.WithCredentials(s3.Credentials{AccessKeyID: id, SecretAccessKey: secret}),
)
obj, err := client.Get(ctx, "bucket", "photos/cat.jpg")
defer obj.Body.Close()
Implementation selection ¶
Signing, request building, and response decoding are shared code: the two builds differ only in how a request reaches the network.
- standard Go builds use net/http and crypto/tls
- TinyGo builds use github.com/shibukawa/tinygodriver/https, which performs TLS through the TLS stack of the host OS
- go build -tags force_tinygo_logic selects the TinyGo path under host Go, which is how that path is tested without a TinyGo toolchain
Neither build follows redirects through http.Client, because a redirected request must be signed again for its new host. Redirects are handled here instead, so a bucket in another region works the same way on both builds.
Credentials ¶
Credentials are static values or environment variables. There is no shared credentials file, no SSO, and no IMDS lookup:
s3.WithCredentials(s3.Credentials{AccessKeyID: id, SecretAccessKey: secret})
s3.WithCredentialsFromEnv() // AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, ...
New reads the environment when no credentials option is given.
Scope ¶
Put sends one request and is bounded by what the endpoint accepts in a single PUT (5 GiB on AWS). Above that, CreateMultipartUpload, UploadPart, CompleteMultipartUpload and AbortMultipartUpload are the operations; nothing here splits a stream into parts, since the caller knows the part boundaries and the failure policy.
Presign is the one operation that makes no request: it returns a SigV4 query-signed URL for a GET, PUT, HEAD or DELETE, so a browser can talk to the bucket directly for a bounded time while the application holds the credentials.
Index ¶
- Constants
- Variables
- type Client
- func (c *Client) AbortMultipartUpload(ctx context.Context, upload MultipartUpload) error
- func (c *Client) CompleteMultipartUpload(ctx context.Context, upload MultipartUpload, parts []CompletedPart) (*PutResult, error)
- func (c *Client) CreateBucket(ctx context.Context, bucket string) error
- func (c *Client) CreateMultipartUpload(ctx context.Context, bucket, key string, opts ...PutOption) (*MultipartUpload, error)
- func (c *Client) Delete(ctx context.Context, bucket, key string) error
- func (c *Client) DeleteBucket(ctx context.Context, bucket string) error
- func (c *Client) Endpoint() string
- func (c *Client) Get(ctx context.Context, bucket, key string) (*Object, error)
- func (c *Client) GetRange(ctx context.Context, bucket, key string, offset, length int64) (*Object, error)
- func (c *Client) Head(ctx context.Context, bucket, key string) (*ObjectInfo, error)
- func (c *Client) List(ctx context.Context, bucket string, opts ...ListOption) (*ListResult, error)
- func (c *Client) Presign(ctx context.Context, bucket, key string, opts PresignOptions) (*url.URL, error)
- func (c *Client) Put(ctx context.Context, bucket, key string, body io.Reader, opts ...PutOption) (*PutResult, error)
- func (c *Client) Region() string
- func (c *Client) UploadPart(ctx context.Context, upload MultipartUpload, partNumber int, body io.Reader, ...) (*CompletedPart, error)
- type CompletedPart
- type Credentials
- type Error
- type ListOption
- type ListResult
- type MultipartUpload
- type Object
- type ObjectInfo
- type Option
- func WithCredentials(creds Credentials) Option
- func WithCredentialsFromEnv() Option
- func WithEndpoint(endpoint string) Option
- func WithHTTPClient(client *http.Client) Option
- func WithPathStyle(pathStyle bool) Option
- func WithRegion(region string) Option
- func WithTimeout(timeout time.Duration) Option
- func WithUnsignedPayload(unsigned bool) Option
- type PresignOptions
- type PutOption
- type PutResult
Constants ¶
const ( MinPartNumber = 1 MaxPartNumber = 10000 )
Part number bounds, which S3 fixes. A part below the 5 MiB minimum is refused by the endpoint at completion, not here: the last part may be smaller, and only the endpoint knows which one that is.
const ( DefaultPresignExpiry = 15 * time.Minute MaxPresignExpiry = 7 * 24 * time.Hour )
Presign expiry bounds. S3 rejects X-Amz-Expires above seven days; the default is the one the AWS SDKs use.
const Backend = aws.Backend
Backend identifies the HTTP stack selected by build constraints: "net/http" on standard Go builds, "https" on TinyGo builds.
const DefaultTimeout = 60 * time.Second
DefaultTimeout bounds one logical operation when no timeout is configured.
Variables ¶
var ( ErrNoSuchKey = errors.New("s3: no such key") ErrNoSuchBucket = errors.New("s3: no such bucket") ErrAccessDenied = errors.New("s3: access denied") ErrBucketExists = errors.New("s3: bucket already exists") ErrBucketNotEmpty = errors.New("s3: bucket not empty") ErrInvalidRange = errors.New("s3: requested range not satisfiable") ErrBadCredentials = errors.New("s3: credentials rejected") ErrNoSuchUpload = errors.New("s3: no such multipart upload") ErrInvalidPart = errors.New("s3: invalid part") // Configuration failures are the shared ones, so errors.Is matches whether // the caller compares against s3 or cloud/aws. ErrNoCredentials = aws.ErrNoCredentials ErrNoRegion = aws.ErrNoRegion ErrTooManyRedirect = errors.New("s3: too many redirects") // ErrPresignExpiry reports a Presign expiry S3 would refuse: negative, or // more than MaxPresignExpiry. ErrPresignExpiry = errors.New("s3: presign expiry out of range") )
Sentinel errors. S3 error codes are mapped onto them so application code can branch with errors.Is without matching strings.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client talks to one S3 endpoint. It is safe for concurrent use.
func New ¶
New builds a Client. Region, endpoint, and credentials fall back to the environment, so a configured shell needs no options at all.
func (*Client) AbortMultipartUpload ¶ added in v1.2.12
func (c *Client) AbortMultipartUpload(ctx context.Context, upload MultipartUpload) error
AbortMultipartUpload discards upload and every part it holds. Aborting an upload that no longer exists is ErrNoSuchUpload.
func (*Client) CompleteMultipartUpload ¶ added in v1.2.12
func (c *Client) CompleteMultipartUpload(ctx context.Context, upload MultipartUpload, parts []CompletedPart) (*PutResult, error)
CompleteMultipartUpload assembles the parts, in the order given, into the object. parts must be in ascending part number order, which is what S3 requires; each ETag is the one UploadPart reported.
S3 may answer 200 and then carry an error document in the body when the assembly fails part way, and that reply is reported as an error here, as a 4xx would be.
func (*Client) CreateBucket ¶
CreateBucket creates a bucket in the client's region. A bucket that already belongs to the caller reports ErrBucketExists.
func (*Client) CreateMultipartUpload ¶ added in v1.2.12
func (c *Client) CreateMultipartUpload(ctx context.Context, bucket, key string, opts ...PutOption) (*MultipartUpload, error)
CreateMultipartUpload starts an upload of key in parts. The Put options set the object's Content-Type, Content-Encoding and metadata; they are fixed here, since the parts carry only bytes.
An upload that is neither completed nor aborted keeps its parts, and AWS bills them, until a lifecycle rule removes it. Abort on every failure path.
func (*Client) Delete ¶
Delete removes an object. Deleting a key that does not exist succeeds, which is how S3 itself behaves.
func (*Client) DeleteBucket ¶
DeleteBucket removes an empty bucket.
func (*Client) GetRange ¶
func (c *Client) GetRange(ctx context.Context, bucket, key string, offset, length int64) (*Object, error)
GetRange retrieves length bytes starting at offset. A length of zero or less reads to the end of the object.
func (*Client) List ¶
func (c *Client) List(ctx context.Context, bucket string, opts ...ListOption) (*ListResult, error)
List returns one page of a bucket listing. A truncated page carries NextToken, which WithContinuationToken feeds back to fetch the next one.
func (*Client) Presign ¶ added in v1.2.12
func (c *Client) Presign(ctx context.Context, bucket, key string, opts PresignOptions) (*url.URL, error)
Presign returns a URL that authorizes one request against key without the caller's credentials, signed through SigV4 query parameters. The endpoint, region, addressing style and credentials are the ones Get and Put use, so a URL for an S3-compatible server needs no second configuration.
The body is not covered: the signature carries UNSIGNED-PAYLOAD, because whoever sends the request never sees the credentials and the signer never sees the body. Only the host and the headers named in opts are signed.
Presigning is a pure function of the client and its arguments; ctx is here so the signature matches the rest of the client, and it goes unused.
func (*Client) Put ¶
func (c *Client) Put(ctx context.Context, bucket, key string, body io.Reader, opts ...PutOption) (*PutResult, error)
Put stores body under key.
There is no multipart upload, so the whole object is sent in one request and the endpoint's single-request limit applies (5 GiB on AWS).
SigV4 signs a hash of the body, so the body must be read twice. A body that implements io.Seeker (an *os.File, a *bytes.Reader) is hashed and rewound; anything else is buffered in memory. Configure WithUnsignedPayload to stream instead, at the cost of the signature no longer covering the body.
func (*Client) Region ¶
Region reports the signing region, which redirect handling may have updated.
func (*Client) UploadPart ¶ added in v1.2.12
func (c *Client) UploadPart(ctx context.Context, upload MultipartUpload, partNumber int, body io.Reader, opts ...PutOption) (*CompletedPart, error)
UploadPart sends one part of upload. Part numbers run from MinPartNumber to MaxPartNumber and need not be contiguous or in order; the list handed to CompleteMultipartUpload decides the object's order. Sending a number twice replaces the earlier part.
The body follows Put's rules: a seekable body is hashed and rewound, anything else is buffered, and WithUnsignedPayload streams. WithContentLength is the one Put option that applies here.
type CompletedPart ¶ added in v1.2.12
CompletedPart is what UploadPart reports and CompleteMultipartUpload needs: the part's number and the ETag the endpoint assigned it.
type Credentials ¶
type Credentials = aws.Credentials
Credentials are the values SigV4 signs with. It is an alias, so credentials built here work with any other client in this repository.
func CredentialsFromEnv ¶
func CredentialsFromEnv() Credentials
CredentialsFromEnv reads AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN.
type Error ¶
type Error struct {
Op string // "Get", "Put", "List", ...
Bucket string
Key string
StatusCode int
Code string
Message string
RequestID string
// contains filtered or unexported fields
}
Error is a failed S3 operation. Code and Message come from the XML error document when the endpoint sent one.
type ListOption ¶
type ListOption func(*listConfig)
ListOption configures a single List call.
func WithContinuationToken ¶
func WithContinuationToken(token string) ListOption
WithContinuationToken resumes a truncated listing from ListResult.NextToken.
func WithDelimiter ¶
func WithDelimiter(delimiter string) ListOption
WithDelimiter groups keys sharing a prefix up to the delimiter, reporting them in ListResult.CommonPrefixes. Use "/" to walk a listing like a directory tree.
func WithMaxKeys ¶
func WithMaxKeys(maxKeys int) ListOption
WithMaxKeys caps how many keys one page returns.
func WithPrefix ¶
func WithPrefix(prefix string) ListOption
WithPrefix limits the listing to keys with this prefix.
func WithStartAfter ¶
func WithStartAfter(key string) ListOption
WithStartAfter begins the listing after this key.
type ListResult ¶
type ListResult struct {
Objects []ObjectInfo
CommonPrefixes []string
IsTruncated bool
// NextToken continues a truncated listing through WithContinuationToken.
NextToken string
}
ListResult is one page of a listing.
type MultipartUpload ¶ added in v1.2.12
MultipartUpload identifies an upload in progress. CreateMultipartUpload returns one, and the other multipart calls take it back, so the bucket, key and upload ID cannot drift apart between calls.
type Object ¶
type Object struct {
ObjectInfo
Body io.ReadCloser
}
Object is an object body together with its metadata. Body must be closed.
type ObjectInfo ¶
type ObjectInfo struct {
Key string
Size int64
ETag string
ContentType string
ContentEncoding string
LastModified time.Time
// Metadata holds user metadata, with the x-amz-meta- prefix removed.
Metadata map[string]string
}
ObjectInfo is the metadata S3 reports for an object.
type Option ¶
type Option func(*config)
Option configures a Client.
func WithCredentials ¶
func WithCredentials(creds Credentials) Option
WithCredentials sets static credentials.
func WithCredentialsFromEnv ¶
func WithCredentialsFromEnv() Option
WithCredentialsFromEnv reads credentials from the environment. New does this already when no credentials option is given; the option states it explicitly.
func WithEndpoint ¶
WithEndpoint overrides the endpoint URL, for S3-compatible servers such as RustFS or MinIO. It defaults to AWS_ENDPOINT_URL_S3, AWS_ENDPOINT_URL, or the regional AWS endpoint.
func WithHTTPClient ¶
WithHTTPClient supplies the http.Client to use.
Its CheckRedirect must return http.ErrUseLastResponse on standard Go builds: a redirected request has to be signed again for its new host, which this package does itself.
func WithPathStyle ¶
WithPathStyle selects between https://endpoint/bucket/key and https://bucket.endpoint/key addressing.
The default is virtual-host addressing for amazonaws.com endpoints and path addressing everywhere else, which is what S3-compatible servers expect.
func WithRegion ¶
WithRegion sets the signing region. It defaults to AWS_REGION, then AWS_DEFAULT_REGION.
func WithTimeout ¶
WithTimeout bounds one logical operation, including redirects and reading the response body. Zero means DefaultTimeout.
func WithUnsignedPayload ¶
WithUnsignedPayload signs requests with UNSIGNED-PAYLOAD instead of the body hash, so Put streams a body it cannot rewind instead of buffering it.
The request headers stay signed. Use it only over https, where TLS protects the body that the signature no longer covers.
type PresignOptions ¶ added in v1.2.12
type PresignOptions struct {
// Method is the HTTP method the URL authorizes: GET, PUT, HEAD or
// DELETE. Empty means GET.
Method string
// Expires bounds the URL's life, written as X-Amz-Expires in whole seconds
// and rounded up. Zero means DefaultPresignExpiry; more than
// MaxPresignExpiry, which S3 would reject, is ErrPresignExpiry.
Expires time.Duration
// ContentType, when set, is signed, so the sender must send exactly it.
ContentType string
// Headers are further request headers to sign. Each is a header the
// sender must reproduce exactly, so a PUT that stores Content-Disposition
// or x-amz-meta-* metadata names them here, and a plain GET names none: a
// link in a page cannot add a header.
Headers map[string]string
// Query adds parameters to the URL, signed with it. On a GET,
// response-content-disposition and response-content-type shape the reply
// without asking the browser for a header; on a part upload, uploadId and
// partNumber address the part.
Query map[string]string
}
PresignOptions describe the request a presigned URL authorizes.
type PutOption ¶
type PutOption func(*putConfig)
PutOption configures a single Put.
func WithContentEncoding ¶
WithContentEncoding sets the object's Content-Encoding, for a body that is already compressed.
func WithContentLength ¶
WithContentLength states the body size for a stream the package cannot measure, which matters together with WithUnsignedPayload: without a length, the body goes out chunked, and AWS rejects a chunked PutObject.
func WithContentType ¶
WithContentType sets the object's Content-Type.
func WithMetadata ¶
WithMetadata attaches user metadata, sent as x-amz-meta-* headers.