Documentation
¶
Overview ¶
Package s3 implements an S3-compatible object API over any github.com/go-filesystems/interface.Filesystem, as an net/http.Handler.
Every driver in the family — ext4, xfs, btrfs, zfs, ntfs, fat32, exfat, hfsplus, apfs, iso9660, squashfs, ufs, ffs, uefi, oci — becomes something the AWS SDK, minio-go, rclone, a backup tool or a browser's fetch() can read and write, from a pure-Go binary with no cgo and no root.
Why S3 alongside the mounts ¶
github.com/go-filesystems/nfs, /sftp and /webdav make a Filesystem MOUNTABLE. S3 is the opposite shape and that is the point: nothing mounts, nothing is a path on somebody's machine, and every operation is one HTTP request that can be authorised, logged, rate-limited and served from anywhere. It is what programs speak now — a backup tool, a container registry's storage, a data pipeline, a phone app — and none of them wants a mount.
A bucket is a top-level directory ¶
The mapping is the whole design decision, so it is worth stating plainly:
GET / the top-level DIRECTORIES, as buckets GET /photos?list-type=2 the files under /photos, as keys GET /photos/holiday.jpg the file /photos/holiday.jpg
A key is a path and a "directory" is a prefix, which is what S3 clients already believe: they display prefixes ending in the delimiter as folders. A driver whose root holds files rather than directories therefore has no buckets, and says so rather than inventing one.
What is here, and what is refused by name ¶
ListBuckets, HeadBucket, CreateBucket, DeleteBucket, ListObjectsV2 (with prefix, delimiter, max-keys and continuation), HeadObject, GetObject with Range, PutObject, DeleteObject and DeleteObjects.
Multipart upload is NOT here: it is a session across requests with its own storage of parts, and pretending otherwise would make a client's 5 GB upload fail at the end rather than at the start. A client that asks gets NotImplemented, which is what makes it fall back to a single PUT.
Nor are versioning, ACLs, policies, lifecycle rules, replication or tagging: a Filesystem has nowhere to keep any of them, and answering "yes" to a policy nobody enforces is worse than answering "no".
Signatures ¶
Requests are authenticated with AWS Signature Version 4, header or presigned, which is what every client sends. Exports are READ-ONLY by default, following the rest of the family: most of what this is pointed at is a forensic or build artefact, and an accidental write to one is unrecoverable.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CredentialLookup ¶
CredentialLookup returns the secret for an access key, and whether that key exists here.
⚠ Returning ("", false) for an unknown key and a real secret otherwise is the whole contract. Do NOT return ("", true) for an unknown key hoping the signature will fail anyway: it would, but the two cases then take different amounts of work and a caller can tell them apart.
type Server ¶
type Server struct {
// Credentials resolves an access key to its secret. Required: a server
// with no way to check a signature would have to accept every request,
// and New refuses to build one.
Credentials CredentialLookup
// Region the signatures are expected to carry. Empty accepts whatever the
// client signed with, which is what a private deployment wants -- clients
// invent a region and would otherwise all have to agree on the same
// invention.
Region string
// ReadOnly refuses every mutating verb. Default TRUE, deliberately: see
// the package doc.
ReadOnly bool
// MaxObjectBytes is the largest object whose ETag is the MD5 of its
// content (larger ones get a multipart-shaped ETag, which clients do not
// compare with one), and the largest a driver without Opener may serve,
// since such a driver can only hand over a whole file in memory. A driver
// with Opener is streamed whatever the size. 0 takes the default.
MaxObjectBytes int64
// ClockSkew is how far a signed request may be from this server's clock.
// 0 takes the default. It is replay protection, not a courtesy.
ClockSkew time.Duration
// Clock is for tests.
Clock func() time.Time
// contains filtered or unexported fields
}
Server serves an S3-compatible API over one Filesystem.
The zero value is not usable: New builds one. It is an http.Handler, so it composes with anything -- TLS, a reverse proxy, a rate limiter -- rather than owning a listener.
func New ¶
func New(fsys filesystem.Filesystem, creds CredentialLookup) (*Server, error)
New builds a Server over fsys.
