Documentation ¶
Index ¶
- Constants
- func BucketNotFound(bucket string) error
- func ErrorInvalidArgument(name, value, message string) error
- func ErrorMessage(code ErrorCode, message string) error
- func ErrorMessagef(code ErrorCode, message string, args ...interface{}) error
- func HasErrorCode(err error, code ErrorCode) bool
- func IsAlreadyExists(err error) bool
- func KeyNotFound(key string) error
- func MergeMetadata(ctx context.Context, db Backend, bucketName string, objectName string, ...) error
- func ReadAll(r io.Reader, size int64) (b []byte, err error)
- func ResourceError(code ErrorCode, resource string) error
- func URLEncode(s string) string
- func ValidateBucketName(name string) error
- type AuthenticatedBackend
- type Backend
- type BucketInfo
- type Buckets
- type CommonPrefix
- type CompleteMultipartUploadRequest
- type CompleteMultipartUploadResponse
- type CompleteMultipartUploadResult
- type CompletedPart
- type Content
- type ContentTime
- type CopyObjectResult
- type DeleteMarker
- type DeleteRequest
- type Error
- type ErrorCode
- type ErrorInvalidArgumentResponse
- type ErrorResponse
- type ErrorResult
- type GetBucketLocation
- type GoFakeS3
- type InitiateMultipartUpload
- type InternalErrorCode
- type ListBucketPage
- type ListBucketResult
- type ListBucketResultBase
- type ListBucketResultV2
- type ListBucketVersionsPage
- type ListBucketVersionsResult
- type ListMultipartUploadItem
- type ListMultipartUploadPartItem
- type ListMultipartUploadPartsResult
- type ListMultipartUploadsResult
- type LogLevel
- type Logger
- type MFADeleteStatus
- type MultiDeleteResult
- type MultipartBackend
- type Object
- type ObjectDeleteResult
- type ObjectID
- type ObjectList
- type ObjectRange
- type ObjectRangeRequest
- type Option
- func WithAutoBucket(enabled bool) Option
- func WithGlobalLog() Option
- func WithHostBucket(enabled bool) Option
- func WithHostBucketBase(hosts ...string) Option
- func WithIntegrityCheck(check bool) Option
- func WithLogger(logger Logger) Option
- func WithMetadataSizeLimit(size int) Option
- func WithRequestID(id uint64) Option
- func WithTimeSkewLimit(skew time.Duration) Option
- func WithTimeSource(timeSource TimeSource) Option
- func WithUnimplementedPageError() Option
- func WithoutVersioning() Option
- type Prefix
- type PrefixMatch
- type PutObjectResult
- type Storage
- type StorageClass
- type TimeSource
- type TimeSourceAdvancer
- type UploadID
- type UploadListMarker
- type UploadPartResult
- type UserInfo
- type Version
- type VersionID
- type VersionItem
- type VersionedBackend
- type VersioningConfiguration
- type VersioningStatus
Constants ¶
const ( // From https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html: // "The name for a key is a sequence of Unicode characters whose UTF-8 // encoding is at most 1024 bytes long." KeySizeLimit = 1024 // From https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html: // Within the PUT request header, the user-defined metadata is limited to 2 // KB in size. The size of user-defined metadata is measured by taking the // sum of the number of bytes in the UTF-8 encoding of each key and value. // // As this does not specify KB or KiB, KB is used in gofakes3. The reason // for this is if gofakes3 is used for testing, and your tests show that // 2KiB works, but Amazon uses 2KB... that's a much worse time to discover // the disparity! DefaultMetadataSizeLimit = 2000 // Like DefaultMetadataSizeLimit, the docs don't specify MB or MiB, so we // will accept 5MB for now. The Go client SDK rejects 5MB with the error // "part size must be at least 5242880 bytes", which is a hint that it // has been interpreted as MiB at least _somewhere_, but we should remain // liberal in what we accept in the face of ambiguity. DefaultUploadPartSize = 5 * 1000 * 1000 DefaultSkewLimit = 15 * time.Minute MaxUploadsLimit = 1000 DefaultMaxUploads = 1000 MaxUploadPartsLimit = 1000 DefaultMaxUploadParts = 1000 MaxBucketKeys = 1000 DefaultMaxBucketKeys = 1000 MaxBucketVersionKeys = 1000 DefaultMaxBucketVersionKeys = 1000 // From the docs: "Part numbers can be any number from 1 to 10,000, inclusive." MaxUploadPartNumber = 10000 )
const (
DefaultBucketVersionKeys = 1000
)
const RangeNoEnd = -1
Variables ¶
This section is empty.
Functions ¶
func BucketNotFound ¶
func ErrorInvalidArgument ¶
func ErrorMessage ¶
func ErrorMessagef ¶
func HasErrorCode ¶
HasErrorCode asserts that the error has a specific error code:
if HasErrorCode(err, ErrNoSuchBucket) { // handle condition }
If err is nil and code is ErrNone, HasErrorCode returns true.
func IsAlreadyExists ¶
IsAlreadyExists asserts that the error is a kind that indicates the resource already exists, similar to os.IsExist.
func KeyNotFound ¶
func MergeMetadata ¶
func ReadAll ¶
ReadAll is a fakeS3-centric replacement for io.ReadAll(), for use when the size of the result is known ahead of time. It is considerably faster to preallocate the entire slice than to allow growslice to be triggered repeatedly, especially with larger buffers.
It also reports S3-specific errors in certain conditions, like ErrIncompleteBody.
func ResourceError ¶
func URLEncode ¶
s3URLEncode is based on Golang's url.QueryEscape() code, while considering some S3 exceptions:
- Avoid encoding '/' and '*'
- Force encoding of '~'
func ValidateBucketName ¶
ValidateBucketName applies the rules from the AWS docs: https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html#bucketnamingrules
1. Bucket names must comply with DNS naming conventions. 2. Bucket names must be at least 3 and no more than 63 characters long. 3. Bucket names must not contain uppercase characters or underscores. 4. Bucket names must start with a lowercase letter or number.
The DNS RFC confirms that the valid range of characters in an LDH label is 'a-z0-9-': https://tools.ietf.org/html/rfc5890#section-2.3.1
Types ¶
type AuthenticatedBackend ¶
type Backend ¶
type Backend interface { // ListBuckets returns a list of all buckets owned by the authenticated // sender of the request. // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTServiceGET.html ListBuckets(ctx context.Context) ([]BucketInfo, error) // ListBucket returns the contents of a bucket. Backends should use the // supplied prefix to limit the contents of the bucket and to sort the // matched items into the Contents and CommonPrefixes fields. // // ListBucket must return a gofakes3.ErrNoSuchBucket error if the bucket // does not exist. See gofakes3.BucketNotFound() for a convenient way to create one. // // The prefix MUST be correctly handled for the backend to be valid. Each // item you consider returning should be checked using prefix.Match(name), // even if the prefix is empty. The Backend MUST treat a nil prefix // identically to a zero prefix. // // At this stage, implementers MAY return gofakes3.ErrInternalPageNotImplemented // if the page argument is non-empty. In this case, gofakes3 may or may // not, depending on how it was configured, retry the same request with no page. // We have observed (though not yet confirmed) that simple clients tend to // work fine if you ignore the pagination request, but this may not suit // your application. Not all backends bundled with gofakes3 correctly // support this pagination yet, but that will change. ListBucket(ctx context.Context, name string, prefix *Prefix, page ListBucketPage) (*ObjectList, error) // CreateBucket creates the bucket if it does not already exist. The name // should be assumed to be a valid name. // // If the bucket already exists, a gofakes3.ResourceError with // gofakes3.ErrBucketAlreadyExists MUST be returned. CreateBucket(ctx context.Context, name string) error // BucketExists should return a boolean indicating the bucket existence, or // an error if the backend was unable to determine existence. BucketExists(ctx context.Context, name string) (exists bool, err error) // DeleteBucket deletes a bucket if and only if it is empty. // // If the bucket is not empty, gofakes3.ResourceError with // gofakes3.ErrBucketNotEmpty MUST be returned. // // If the bucket does not exist, gofakes3.ErrNoSuchBucket MUST be returned. // // AWS does not validate the bucket's name for anything other than existence. DeleteBucket(ctx context.Context, name string) error // GetObject must return a gofakes3.ErrNoSuchKey error if the object does // not exist. See gofakes3.KeyNotFound() for a convenient way to create // one. // // If the returned Object is not nil, you MUST call Object.Contents.Close(), // otherwise you will leak resources. Implementers should return a no-op // implementation of io.ReadCloser. // // If rnge is nil, it is assumed you want the entire object. If rnge is not // nil, but the underlying backend does not support range requests, // implementers MUST return ErrNotImplemented. // // If the backend is a VersionedBackend, GetObject retrieves the latest version. GetObject(ctx context.Context, bucketName, objectName string, rangeRequest *ObjectRangeRequest) (*Object, error) // HeadObject fetches the Object from the backend, but reading the Contents // will return io.EOF immediately. // // If the returned Object is not nil, you MUST call Object.Contents.Close(), // otherwise you will leak resources. Implementers should return a no-op // implementation of io.ReadCloser. // // HeadObject should return a NotFound() error if the object does not // exist. HeadObject(ctx context.Context, bucketName, objectName string) (*Object, error) // DeleteObject deletes an object from the bucket. // // If the backend is a VersionedBackend and versioning is enabled, this // should introduce a delete marker rather than actually delete the object. // // DeleteObject must return a gofakes3.ErrNoSuchBucket error if the bucket // does not exist. See gofakes3.BucketNotFound() for a convenient way to create one. // FIXME: confirm with S3 whether this is the correct behaviour. // // DeleteObject must not return an error if the object does not exist. Source: // https://docs.aws.amazon.com/sdk-for-go/api/service/s3/#S3.DeleteObject: // // Removes the null version (if there is one) of an object and inserts a // delete marker, which becomes the latest version of the object. If there // isn't a null version, Amazon S3 does not remove any objects. // DeleteObject(ctx context.Context, bucketName, objectName string) (ObjectDeleteResult, error) // PutObject should assume that the key is valid. The map containing meta // may be nil. // // The size can be used if the backend needs to read the whole reader; use // gofakes3.ReadAll() for this job rather than io.ReadAll(). PutObject(ctx context.Context, bucketName, key string, meta map[string]string, input io.Reader, size int64) (PutObjectResult, error) DeleteMulti(ctx context.Context, bucketName string, objects ...string) (MultiDeleteResult, error) CopyObject(ctx context.Context, srcBucket, srcKey, dstBucket, dstKey string, meta map[string]string) (CopyObjectResult, error) }
Backend provides a set of operations to be implemented in order to support gofakes3.
The Backend API is not yet stable; if you create your own Backend, breakage is likely until this notice is removed.
type BucketInfo ¶
type BucketInfo struct { Name string `xml:"Name"` // CreationDate is required; without it, boto returns the error "('String // does not contain a date:', ”)" CreationDate ContentTime `xml:"CreationDate"` }
BucketInfo represents a single bucket returned by the ListBuckets response.
type Buckets ¶
type Buckets []BucketInfo
type CommonPrefix ¶
type CommonPrefix struct {
Prefix string `xml:"Prefix"`
}
CommonPrefix is used in Bucket.CommonPrefixes to list partial delimited keys that represent pseudo-directories.
type CompleteMultipartUploadRequest ¶
type CompleteMultipartUploadRequest struct {
Parts []CompletedPart `xml:"Part"`
}
type CompleteMultipartUploadResult ¶
type CompleteMultipartUploadResult struct { // If versioning is enabled on the bucket, this should be set to the // created version ID. If versioning is not enabled, this should be // empty. VersionID VersionID `xml:"VersionId,omitempty"` // ETag is the value of the ETag header returned by the backend. ETag string `xml:"ETag,omitempty"` }
type CompletedPart ¶
type Content ¶
type Content struct { Key string `xml:"Key"` LastModified ContentTime `xml:"LastModified"` ETag string `xml:"ETag"` Size int64 `xml:"Size"` StorageClass StorageClass `xml:"StorageClass,omitempty"` Owner *UserInfo `xml:"Owner,omitempty"` }
type ContentTime ¶
func NewContentTime ¶
func NewContentTime(t time.Time) ContentTime
func (ContentTime) MarshalXML ¶
func (c ContentTime) MarshalXML(e *xml.Encoder, start xml.StartElement) error
type CopyObjectResult ¶
type CopyObjectResult struct { XMLName xml.Name `xml:"CopyObjectResult"` ETag string `xml:"ETag,omitempty"` LastModified ContentTime `xml:"LastModified,omitempty"` }
CopyObjectResult contains the response from a CopyObject operation.
func CopyObject ¶
func CopyObject(ctx context.Context, db Backend, srcBucket, srcKey, dstBucket, dstKey string, meta map[string]string) (result CopyObjectResult, err error)
CopyObject is a helper function useful for quickly implementing CopyObject on a backend that already supports GetObject and PutObject. This isn't very efficient so only use this if performance isn't important.
type DeleteMarker ¶
type DeleteMarker struct { XMLName xml.Name `xml:"DeleteMarker"` Key string `xml:"Key"` VersionID VersionID `xml:"VersionId"` IsLatest bool `xml:"IsLatest"` LastModified ContentTime `xml:"LastModified,omitempty"` Owner *UserInfo `xml:"Owner,omitempty"` }
func (DeleteMarker) GetVersionID ¶
func (d DeleteMarker) GetVersionID() VersionID
type DeleteRequest ¶
type DeleteRequest struct { Objects []ObjectID `xml:"Object"` // Element to enable quiet mode for the request. When you add this element, // you must set its value to true. // // By default, the operation uses verbose mode in which the response // includes the result of deletion of each key in your request. In quiet // mode the response includes only keys where the delete operation // encountered an error. For a successful deletion, the operation does not // return any information about the delete in the response body. Quiet bool `xml:"Quiet"` }
type ErrorCode ¶
type ErrorCode string
ErrorCode represents an S3 error code, documented here: https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
const ( ErrNone ErrorCode = "" ErrAccessDenied ErrorCode = "AccessDenied" // The Content-MD5 you specified did not match what we received. ErrBadDigest ErrorCode = "BadDigest" ErrBucketAlreadyExists ErrorCode = "BucketAlreadyExists" // Raised when attempting to delete a bucket that still contains items. ErrBucketNotEmpty ErrorCode = "BucketNotEmpty" // "Indicates that the versioning configuration specified in the request is invalid" ErrIllegalVersioningConfiguration ErrorCode = "IllegalVersioningConfigurationException" // You did not provide the number of bytes specified by the Content-Length // HTTP header: ErrIncompleteBody ErrorCode = "IncompleteBody" // POST requires exactly one file upload per request. ErrIncorrectNumberOfFilesInPostRequest ErrorCode = "IncorrectNumberOfFilesInPostRequest" // InlineDataTooLarge occurs when using the PutObjectInline method of the // SOAP interface // (https://docs.aws.amazon.com/AmazonS3/latest/API/SOAPPutObjectInline.html). // This is not documented on the errors page; the error is included here // only for reference. ErrInlineDataTooLarge ErrorCode = "InlineDataTooLarge" ErrInvalidArgument ErrorCode = "InvalidArgument" // https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html#bucketnamingrules ErrInvalidBucketName ErrorCode = "InvalidBucketName" // The Content-MD5 you specified is not valid. ErrInvalidDigest ErrorCode = "InvalidDigest" ErrInvalidRange ErrorCode = "InvalidRange" ErrInvalidToken ErrorCode = "InvalidToken" ErrKeyTooLong ErrorCode = "KeyTooLongError" // This is not a typo: Error is part of the string, but redundant in the constant name ErrMalformedPOSTRequest ErrorCode = "MalformedPOSTRequest" // One or more of the specified parts could not be found. The part might // not have been uploaded, or the specified entity tag might not have // matched the part's entity tag. ErrInvalidPart ErrorCode = "InvalidPart" // The list of parts was not in ascending order. Parts list must be // specified in order by part number. ErrInvalidPartOrder ErrorCode = "InvalidPartOrder" ErrInvalidURI ErrorCode = "InvalidURI" ErrMetadataTooLarge ErrorCode = "MetadataTooLarge" ErrMethodNotAllowed ErrorCode = "MethodNotAllowed" ErrMalformedXML ErrorCode = "MalformedXML" // You must provide the Content-Length HTTP header. ErrMissingContentLength ErrorCode = "MissingContentLength" // See BucketNotFound() for a helper function for this error: ErrNoSuchBucket ErrorCode = "NoSuchBucket" // See KeyNotFound() for a helper function for this error: ErrNoSuchKey ErrorCode = "NoSuchKey" // The specified multipart upload does not exist. The upload ID might be // invalid, or the multipart upload might have been aborted or completed. ErrNoSuchUpload ErrorCode = "NoSuchUpload" ErrNoSuchVersion ErrorCode = "NoSuchVersion" // No need to retransmit the object ErrNotModified ErrorCode = "NotModified" ErrRequestTimeTooSkewed ErrorCode = "RequestTimeTooSkewed" ErrTooManyBuckets ErrorCode = "TooManyBuckets" ErrNotImplemented ErrorCode = "NotImplemented" ErrInternal ErrorCode = "InternalError" )
Error codes are documented here: https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
If you add a code to this list, please also add it to ErrorCode.Status().
type ErrorInvalidArgumentResponse ¶
type ErrorInvalidArgumentResponse struct { ErrorResponse ArgumentName string `xml:"ArgumentName"` ArgumentValue string `xml:"ArgumentValue"` }
type ErrorResponse ¶
type ErrorResponse struct { XMLName xml.Name `xml:"Error"` Code ErrorCode Message string `xml:",omitempty"` RequestID string `xml:"RequestId,omitempty"` HostID string `xml:"HostId,omitempty"` }
ErrorResponse is the base error type returned by S3 when any error occurs.
Some errors contain their own additional fields in the response, for example ErrRequestTimeTooSkewed, which contains the server time and the skew limit. To create one of these responses, subclass it (but please don't export it):
type notQuiteRightResponse struct { ErrorResponse ExtraField int }
Next, create a constructor that populates the error. Interfaces won't work for this job as the error itself does double-duty as the XML response object. Fill the struct out however you please, but don't forget to assign Code and Message:
func NotQuiteRight(at time.Time, max time.Duration) error { code := ErrNotQuiteRight return ¬QuiteRightResponse{ ErrorResponse{Code: code, Message: code.Message()}, 123456789, } }
func (*ErrorResponse) Error ¶
func (e *ErrorResponse) Error() string
func (*ErrorResponse) ErrorCode ¶
func (e *ErrorResponse) ErrorCode() ErrorCode
type ErrorResult ¶
type ErrorResult struct { XMLName xml.Name `xml:"Error"` Key string `xml:"Key,omitempty"` Code ErrorCode `xml:"Code,omitempty"` Message string `xml:"Message,omitempty"` Resource string `xml:"Resource,omitempty"` RequestID string `xml:"RequestId,omitempty"` }
func ErrorResultFromError ¶
func ErrorResultFromError(err error) ErrorResult
func (ErrorResult) String ¶
func (er ErrorResult) String() string
type GetBucketLocation ¶
type GoFakeS3 ¶
type GoFakeS3 struct {
// contains filtered or unexported fields
}
GoFakeS3 implements HTTP handlers for processing S3 requests and returning S3 responses.
Logic is delegated to other components, like Backend or uploader.
func New ¶
New creates a new GoFakeS3 using the supplied Backend. Backends are pluggable. Several Backend implementations ship with GoFakeS3, which can be found in the gofakes3/backends package.
func (*GoFakeS3) DelAuthKeys ¶
type InitiateMultipartUpload ¶
type InternalErrorCode ¶
type InternalErrorCode string
InternalErrorCode represents an GoFakeS3 error code. It maps to ErrInternal when constructing a response.
const (
ErrInternalPageNotImplemented InternalErrorCode = "PaginationNotImplemented"
)
INTERNAL errors! These are not part of the S3 interface, they are codes we have declared ourselves. Should all map to a 500 status code:
func (InternalErrorCode) Error ¶
func (e InternalErrorCode) Error() string
func (InternalErrorCode) ErrorCode ¶
func (e InternalErrorCode) ErrorCode() ErrorCode
type ListBucketPage ¶
type ListBucketPage struct { // Specifies the key in the bucket that represents the last item in // the previous page. The first key in the returned page will be the // next lexicographically (UTF-8 binary) sorted key after Marker. // If HasMarker is true, this must be non-empty. Marker string HasMarker bool // Sets the maximum number of keys returned in the response body. The // response might contain fewer keys, but will never contain more. If // additional keys satisfy the search criteria, but were not returned // because max-keys was exceeded, the response contains // <isTruncated>true</isTruncated>. To return the additional keys, see // key-marker and version-id-marker. // // MaxKeys MUST be > 0, otherwise it is ignored. MaxKeys int64 }
func (ListBucketPage) IsEmpty ¶
func (p ListBucketPage) IsEmpty() bool
type ListBucketResult ¶
type ListBucketResult struct { ListBucketResultBase // Indicates where in the bucket listing begins. Marker is included in the // response if it was sent with the request. Marker string `xml:"Marker"` // When the response is truncated (that is, the IsTruncated element value // in the response is true), you can use the key name in this field as a // marker in the subsequent request to get next set of objects. Amazon S3 // lists objects in UTF-8 character encoding in lexicographical order. // // NOTE: This element is returned only if you specify a delimiter request // parameter. If the response does not include the NextMarker and it is // truncated, you can use the value of the last Key in the response as the // marker in the subsequent request to get the next set of object keys. NextMarker string `xml:"NextMarker,omitempty"` }
type ListBucketResultBase ¶
type ListBucketResultBase struct { XMLName xml.Name `xml:"ListBucketResult"` Xmlns string `xml:"xmlns,attr"` // Name of the bucket. Name string `xml:"Name"` // Specifies whether (true) or not (false) all of the results were // returned. If the number of results exceeds that specified by MaxKeys, // all of the results might not be returned. IsTruncated bool `xml:"IsTruncated"` // Causes keys that contain the same string between the prefix and the // first occurrence of the delimiter to be rolled up into a single result // element in the CommonPrefixes collection. These rolled-up keys are not // returned elsewhere in the response. // // NOTE: Each rolled-up result in CommonPrefixes counts as only one return // against the MaxKeys value. (BW: been waiting to find some confirmation of // that for a while!) Delimiter string `xml:"Delimiter,omitempty"` Prefix string `xml:"Prefix"` MaxKeys int64 `xml:"MaxKeys,omitempty"` CommonPrefixes []CommonPrefix `xml:"CommonPrefixes,omitempty"` Contents []*Content `xml:"Contents"` }
type ListBucketResultV2 ¶
type ListBucketResultV2 struct { ListBucketResultBase // If ContinuationToken was sent with the request, it is included in the // response. ContinuationToken string `xml:"ContinuationToken,omitempty"` // Returns the number of keys included in the response. The value is always // less than or equal to the MaxKeys value. KeyCount int64 `xml:"KeyCount,omitempty"` // If the response is truncated, Amazon S3 returns this parameter with a // continuation token. You can specify the token as the continuation-token // in your next request to retrieve the next set of keys. NextContinuationToken string `xml:"NextContinuationToken,omitempty"` // If StartAfter was sent with the request, it is included in the response. StartAfter string `xml:"StartAfter,omitempty"` }
type ListBucketVersionsPage ¶
type ListBucketVersionsPage struct { // Specifies the key in the bucket that you want to start listing from. // If HasKeyMarker is true, this must be non-empty. KeyMarker string HasKeyMarker bool // Specifies the object version you want to start listing from. If // HasVersionIDMarker is true, this must be non-empty. VersionIDMarker VersionID HasVersionIDMarker bool // Sets the maximum number of keys returned in the response body. The // response might contain fewer keys, but will never contain more. If // additional keys satisfy the search criteria, but were not returned // because max-keys was exceeded, the response contains // <isTruncated>true</isTruncated>. To return the additional keys, see // key-marker and version-id-marker. // // MaxKeys MUST be > 0, otherwise it is ignored. MaxKeys int64 }
type ListBucketVersionsResult ¶
type ListBucketVersionsResult struct { XMLName xml.Name `xml:"ListBucketVersionsResult"` Xmlns string `xml:"xmlns,attr"` Name string `xml:"Name"` Delimiter string `xml:"Delimiter,omitempty"` Prefix string `xml:"Prefix,omitempty"` CommonPrefixes []CommonPrefix `xml:"CommonPrefixes,omitempty"` IsTruncated bool `xml:"IsTruncated"` MaxKeys int64 `xml:"MaxKeys"` // Marks the last Key returned in a truncated response. KeyMarker string `xml:"KeyMarker,omitempty"` // When the number of responses exceeds the value of MaxKeys, NextKeyMarker // specifies the first key not returned that satisfies the search criteria. // Use this value for the key-marker request parameter in a subsequent // request. NextKeyMarker string `xml:"NextKeyMarker,omitempty"` // Marks the last version of the Key returned in a truncated response. VersionIDMarker VersionID `xml:"VersionIdMarker,omitempty"` // When the number of responses exceeds the value of MaxKeys, // NextVersionIdMarker specifies the first object version not returned that // satisfies the search criteria. Use this value for the version-id-marker // request parameter in a subsequent request. NextVersionIDMarker VersionID `xml:"NextVersionIdMarker,omitempty"` // AWS responds with a list of either <Version> or <DeleteMarker> objects. The order // needs to be preserved and they need to be direct of ListBucketVersionsResult: // <ListBucketVersionsResult> // <DeleteMarker ... /> // <Version ... /> // <DeleteMarker ... /> // <Version ... /> // </ListBucketVersionsResult> Versions []VersionItem // contains filtered or unexported fields }
func NewListBucketVersionsResult ¶
func NewListBucketVersionsResult( bucketName string, prefix *Prefix, page *ListBucketVersionsPage, ) *ListBucketVersionsResult
func (*ListBucketVersionsResult) AddPrefix ¶
func (b *ListBucketVersionsResult) AddPrefix(prefix string)
type ListMultipartUploadItem ¶
type ListMultipartUploadItem struct { Key string `xml:"Key"` UploadID UploadID `xml:"UploadId"` Initiator *UserInfo `xml:"Initiator,omitempty"` Owner *UserInfo `xml:"Owner,omitempty"` StorageClass StorageClass `xml:"StorageClass,omitempty"` Initiated ContentTime `xml:"Initiated,omitempty"` }
type ListMultipartUploadPartItem ¶
type ListMultipartUploadPartItem struct { PartNumber int `xml:"PartNumber"` LastModified ContentTime `xml:"LastModified,omitempty"` ETag string `xml:"ETag,omitempty"` Size int64 `xml:"Size"` }
type ListMultipartUploadPartsResult ¶
type ListMultipartUploadPartsResult struct { XMLName xml.Name `xml:"ListPartsResult"` Bucket string `xml:"Bucket"` Key string `xml:"Key"` UploadID UploadID `xml:"UploadId"` StorageClass StorageClass `xml:"StorageClass,omitempty"` Initiator *UserInfo `xml:"Initiator,omitempty"` Owner *UserInfo `xml:"Owner,omitempty"` PartNumberMarker int `xml:"PartNumberMarker"` NextPartNumberMarker int `xml:"NextPartNumberMarker"` MaxParts int64 `xml:"MaxParts"` IsTruncated bool `xml:"IsTruncated,omitempty"` Parts []ListMultipartUploadPartItem `xml:"Part"` }
type ListMultipartUploadsResult ¶
type ListMultipartUploadsResult struct { Bucket string `xml:"Bucket"` // Together with upload-id-marker, this parameter specifies the multipart upload // after which listing should begin. KeyMarker string `xml:"KeyMarker,omitempty"` // Together with key-marker, specifies the multipart upload after which listing // should begin. If key-marker is not specified, the upload-id-marker parameter // is ignored. UploadIDMarker UploadID `xml:"UploadIdMarker,omitempty"` NextKeyMarker string `xml:"NextKeyMarker,omitempty"` NextUploadIDMarker UploadID `xml:"NextUploadIdMarker,omitempty"` // Sets the maximum number of multipart uploads, from 1 to 1,000, to return // in the response body. 1,000 is the maximum number of uploads that can be // returned in a response. MaxUploads int64 `xml:"MaxUploads,omitempty"` Delimiter string `xml:"Delimiter,omitempty"` // Lists in-progress uploads only for those keys that begin with the specified // prefix. Prefix string `xml:"Prefix,omitempty"` CommonPrefixes []CommonPrefix `xml:"CommonPrefixes,omitempty"` IsTruncated bool `xml:"IsTruncated,omitempty"` Uploads []ListMultipartUploadItem `xml:"Upload"` }
type Logger ¶
type Logger interface {
Print(level LogLevel, v ...interface{})
}
Logger provides a very minimal target for logging implementations to hit to allow arbitrary logging dependencies to be used with GoFakeS3.
Only an interface to the standard library's log package is provided with GoFakeS3, other libraries will require an adapter. Adapters are trivial to write.
For zap:
type LogrusLog struct { log *zap.Logger } func (l LogrusLog) Print(level LogLevel, v ...interface{}) { switch level { case gofakes3.LogErr: l.log.Error(fmt.Sprint(v...)) case gofakes3.LogWarn: l.log.Warn(fmt.Sprint(v...)) case gofakes3.LogInfo: l.log.Info(fmt.Sprint(v...)) default: panic("unknown level") } }
For logrus:
type LogrusLog struct { log *logrus.Logger } func (l LogrusLog) Print(level LogLevel, v ...interface{}) { switch level { case gofakes3.LogErr: l.log.Errorln(v...) case gofakes3.LogWarn: l.log.Warnln(v...) case gofakes3.LogInfo: l.log.Infoln(v...) default: panic("unknown level") } }
type MFADeleteStatus ¶
type MFADeleteStatus string
MFADeleteStatus is used by VersioningConfiguration.
const ( MFADeleteNone MFADeleteStatus = "" MFADeleteEnabled MFADeleteStatus = "Enabled" MFADeleteDisabled MFADeleteStatus = "Disabled" )
func (MFADeleteStatus) Enabled ¶
func (v MFADeleteStatus) Enabled() bool
func (*MFADeleteStatus) UnmarshalXML ¶
func (v *MFADeleteStatus) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
type MultiDeleteResult ¶
type MultiDeleteResult struct { XMLName xml.Name `xml:"DeleteResult"` Deleted []ObjectID `xml:"Deleted"` Error []ErrorResult `xml:",omitempty"` }
MultiDeleteResult contains the response from a multi delete operation.
func (MultiDeleteResult) AsError ¶
func (d MultiDeleteResult) AsError() error
type MultipartBackend ¶
type MultipartBackend interface { CreateMultipartUpload(ctx context.Context, bucket, object string, meta map[string]string) (UploadID, error) UploadPart(ctx context.Context, bucket, object string, id UploadID, partNumber int, contentLength int64, input io.Reader) (*UploadPartResult, error) ListMultipartUploads(ctx context.Context, bucket string, marker *UploadListMarker, prefix Prefix, limit int64) (*ListMultipartUploadsResult, error) ListParts(ctx context.Context, bucket, object string, uploadID UploadID, marker int, limit int64) (*ListMultipartUploadPartsResult, error) AbortMultipartUpload(ctx context.Context, bucket, object string, id UploadID) error CompleteMultipartUpload(ctx context.Context, bucket, object string, id UploadID, meta map[string]string, input *CompleteMultipartUploadRequest) (*CompleteMultipartUploadResult, error) }
MultipartBackend may be optionally implemented by a Backend in order to support S3 multiplart uploads. If you don't implement MultipartBackend, GoFakeS3 will fall back to an in-memory implementation which holds all parts in memory until the upload gets finalised and pushed to the backend.
type Object ¶
type Object struct { Name string Metadata map[string]string Size int64 Contents io.ReadCloser Hash []byte Range *ObjectRange // VersionID will be empty if bucket versioning has not been enabled. VersionID VersionID // If versioning is enabled for the bucket, this is true if this object version // is a delete marker. IsDeleteMarker bool }
Object contains the data retrieved from a backend for the specified bucket and object key.
You MUST always call Contents.Close() otherwise you may leak resources.
type ObjectDeleteResult ¶
type ObjectDeleteResult struct { // Specifies whether the versioned object that was permanently deleted was // (true) or was not (false) a delete marker. In a simple DELETE, this // header indicates whether (true) or not (false) a delete marker was // created. IsDeleteMarker bool // Returns the version ID of the delete marker created as a result of the // DELETE operation. If you delete a specific object version, the value // returned by this header is the version ID of the object version deleted. VersionID VersionID }
type ObjectList ¶
type ObjectList struct { CommonPrefixes []CommonPrefix Contents []*Content IsTruncated bool NextMarker string // contains filtered or unexported fields }
func NewObjectList ¶
func NewObjectList() *ObjectList
func (*ObjectList) Add ¶
func (b *ObjectList) Add(item *Content)
func (*ObjectList) AddPrefix ¶
func (b *ObjectList) AddPrefix(prefix string)
type ObjectRange ¶
type ObjectRange struct {
Start, Length int64
}
type ObjectRangeRequest ¶
func (*ObjectRangeRequest) Range ¶
func (o *ObjectRangeRequest) Range(size int64) (*ObjectRange, error)
type Option ¶
type Option func(g *GoFakeS3)
func WithAutoBucket ¶
WithAutoBucket instructs GoFakeS3 to create buckets that don't exist on first use, rather than returning ErrNoSuchBucket.
func WithGlobalLog ¶
func WithGlobalLog() Option
WithGlobalLog configures gofakes3 to use GlobalLog() for logging, which uses the standard library's log.Println() call to log messages.
func WithHostBucket ¶
WithHostBucket enables or disables bucket rewriting in the router. If active, the URL 'http://mybucket.localhost/object' will be routed as if the URL path was '/mybucket/object'.
This will apply to all requests. If you want to be more specific, provide WithHostBucketBase.
See https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html for details.
func WithHostBucketBase ¶
WithHostBucketBase enables or disables bucket rewriting in the router, but only if the host is a subdomain of the base.
If set to 'example.com', the URL 'http://mybucket.example.com/object' will be routed as if the URL path was '/mybucket/object', but 'http://example.com/bucket/object' will use path-based bucket routing instead.
You may pass multiple bases, they are tested in order.
See https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html for details.
func WithIntegrityCheck ¶
WithIntegrityCheck enables or disables Content-MD5 validation when putting an Object.
func WithLogger ¶
WithLogger allows you to supply a logger to GoFakeS3 for debugging/tracing. logger may be nil.
func WithMetadataSizeLimit ¶
WithMetadataSizeLimit allows you to reconfigure the maximum allowed metadata size.
See DefaultMetadataSizeLimit for the starting value, set to '0' to disable.
func WithRequestID ¶
WithRequestID sets the starting ID used to generate the "x-amz-request-id" header.
func WithTimeSkewLimit ¶
WithTimeSkewLimit allows you to reconfigure the allowed skew between the client's clock and the server's clock. The AWS client SDKs will send the "x-amz-date" header containing the time at the client, which is used to calculate the skew.
See DefaultSkewLimit for the starting value, set to '0' to disable.
func WithTimeSource ¶
func WithTimeSource(timeSource TimeSource) Option
WithTimeSource allows you to substitute the behaviour of time.Now() and time.Since() within GoFakeS3. This can be used to trigger time skew errors, or to ensure the output of the commands is deterministic.
See gofakes3.FixedTimeSource(), gofakes3.LocalTimeSource(tz).
func WithUnimplementedPageError ¶
func WithUnimplementedPageError() Option
WithUnimplementedPageError allows you to enable or disable the error that occurs if the Backend does not implement paging.
By default, GoFakeS3 will simply retry a request for a page of objects without the page if the Backend does not implement pagination. This can be used to enable an error in that condition instead.
func WithoutVersioning ¶
func WithoutVersioning() Option
WithoutVersioning disables versioning on the passed backend, if it supported it.
type Prefix ¶
func NewFolderPrefix ¶
func (Prefix) FilePrefix ¶
FilePrefix returns the path portion, then the remaining portion of the Prefix if the Delimiter is "/". If the Delimiter is not set, or not "/", ok will be false.
For example:
/foo/bar/ : path: /foo/bar remaining: "" /foo/bar/b : path: /foo/bar remaining: "b" /foo/bar : path: /foo remaining: "bar"
func (Prefix) Match ¶
func (p Prefix) Match(key string, match *PrefixMatch) (ok bool)
PrefixMatch checks whether key starts with prefix. If the prefix does not match, nil is returned.
It is a best-effort attempt to implement the prefix/delimiter matching found in S3.
To check whether the key belongs in Contents or CommonPrefixes, compare the result to key.
type PrefixMatch ¶
type PrefixMatch struct { // Input key passed to PrefixMatch. Key string // CommonPrefix indicates whether this key should be returned in the bucket // contents or the common prefixes part of the "list bucket" response. CommonPrefix bool // The longest matched part of the key. MatchedPart string }
func (*PrefixMatch) AsCommonPrefix ¶
func (match *PrefixMatch) AsCommonPrefix() CommonPrefix
type PutObjectResult ¶
type PutObjectResult struct { // If versioning is enabled on the bucket, this should be set to the // created version ID. If versioning is not enabled, this should be // empty. VersionID VersionID `xml:"VersionId,omitempty"` // ETag is the value of the ETag header returned by the backend. ETag string `xml:"ETag,omitempty"` }
PutObjectResult contains the response from a PutObject operation.
type StorageClass ¶
type StorageClass string
const (
StorageStandard StorageClass = "STANDARD"
)
func (StorageClass) MarshalXML ¶
func (s StorageClass) MarshalXML(e *xml.Encoder, start xml.StartElement) error
type TimeSource ¶
func DefaultTimeSource ¶
func DefaultTimeSource() TimeSource
type TimeSourceAdvancer ¶
type TimeSourceAdvancer interface { TimeSource Advance(by time.Duration) }
func FixedTimeSource ¶
func FixedTimeSource(at time.Time) TimeSourceAdvancer
FixedTimeSource provides a source of time that always returns the specified time.
type UploadID ¶
type UploadID string
UploadID uses a string as the underlying type, but the string should only represent a decimal integer. See uploader.uploadID for details.
type UploadListMarker ¶
type UploadListMarker struct { // Represents the key-marker query parameter. Together with 'uploadID', // this parameter specifies the multipart upload after which listing should // begin. // // If 'uploadID' is not specified, only the keys lexicographically greater // than the specified key-marker will be included in the list. // // If 'uploadID' is specified, any multipart uploads for a key equal to // 'object' might also be included, provided those multipart uploads have // upload IDs lexicographically greater than the specified uploadID. Object string // Represents the upload-id-marker query parameter to the // ListMultipartUploads operation. Together with 'object', specifies the // multipart upload after which listing should begin. If 'object' is not // specified, the 'uploadID' parameter is ignored. UploadID UploadID }
UploadListMarker is used to seek to the start of a page in a ListMultipartUploads operation.
type UploadPartResult ¶
type UploadPartResult struct {
ETag string `xml:"ETag,omitempty"`
}
type Version ¶
type Version struct { XMLName xml.Name `xml:"Version"` Key string `xml:"Key"` VersionID VersionID `xml:"VersionId"` IsLatest bool `xml:"IsLatest"` LastModified ContentTime `xml:"LastModified,omitempty"` Size int64 `xml:"Size"` // According to the S3 docs, this is always STANDARD for a Version: StorageClass StorageClass `xml:"StorageClass"` ETag string `xml:"ETag"` Owner *UserInfo `xml:"Owner,omitempty"` }
func (Version) GetVersionID ¶
type VersionItem ¶
type VersionItem interface { GetVersionID() VersionID // contains filtered or unexported methods }
type VersionedBackend ¶
type VersionedBackend interface { // VersioningConfiguration must return a gofakes3.ErrNoSuchBucket error if the bucket // does not exist. See gofakes3.BucketNotFound() for a convenient way to create one. // // If the bucket has never had versioning enabled, VersioningConfiguration MUST return // empty strings (S300001). VersioningConfiguration(ctx context.Context, bucket string) (VersioningConfiguration, error) // SetVersioningConfiguration must return a gofakes3.ErrNoSuchBucket error if the bucket // does not exist. See gofakes3.BucketNotFound() for a convenient way to create one. SetVersioningConfiguration(ctx context.Context, bucket string, v VersioningConfiguration) error // GetObject must return a gofakes3.ErrNoSuchKey error if the object does // not exist. See gofakes3.KeyNotFound() for a convenient way to create // one. // // If the returned Object is not nil, you MUST call Object.Contents.Close(), // otherwise you will leak resources. Implementers should return a no-op // implementation of io.ReadCloser. // // GetObject must return gofakes3.ErrNoSuchVersion if the version does not // exist. // // If versioning has been enabled on a bucket, but subsequently suspended, // GetObjectVersion should still return the object version (S300001). // // FIXME: s3assumer test; what happens when versionID is empty? Does it // return the latest? GetObjectVersion( ctx context.Context, bucketName, objectName string, versionID VersionID, rangeRequest *ObjectRangeRequest) (*Object, error) // HeadObjectVersion fetches the Object version from the backend, but the Contents will be // a no-op ReadCloser. // // If the returned Object is not nil, you MUST call Object.Contents.Close(), // otherwise you will leak resources. Implementers should return a no-op // implementation of io.ReadCloser. // // HeadObjectVersion should return a NotFound() error if the object does not // exist. HeadObjectVersion(ctx context.Context, bucketName, objectName string, versionID VersionID) (*Object, error) // DeleteObjectVersion permanently deletes a specific object version. // // DeleteObjectVersion must return a gofakes3.ErrNoSuchBucket error if the bucket // does not exist. See gofakes3.BucketNotFound() for a convenient way to create one. // // If the bucket exists and either the object does not exist (S300003) or // the version does not exist (S300002), you MUST return an empty // ObjectDeleteResult and a nil error. DeleteObjectVersion(ctx context.Context, bucketName, objectName string, versionID VersionID) (ObjectDeleteResult, error) // DeleteMultiVersions permanently deletes all of the specified Object Versions DeleteMultiVersions(ctx context.Context, bucketName string, objects ...ObjectID) (MultiDeleteResult, error) // Backend implementers can assume the ListBucketVersionsPage is valid: // KeyMarker and VersionIDMarker will either both be set, or both be unset. No // other combination will be present (S300004). // // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETVersion.html // // This MUST return the list of current versions with an empty VersionID // even if versioning has never been enabled for the bucket (S300005). // // The Backend MUST treat a nil prefix identically to a zero prefix, and a // nil page identically to a zero page. ListBucketVersions(ctx context.Context, bucketName string, prefix *Prefix, page *ListBucketVersionsPage) (*ListBucketVersionsResult, error) }
VersionedBackend may be optionally implemented by a Backend in order to support operations on S3 object versions.
If you don't implement VersionedBackend, requests to GoFakeS3 that attempt to make use of versions will return ErrNotImplemented if GoFakesS3 is unable to find another way to satisfy the request.
type VersioningConfiguration ¶
type VersioningConfiguration struct { XMLName xml.Name `xml:"VersioningConfiguration"` Status VersioningStatus `xml:"Status"` // When enabled, the bucket owner must include the x-amz-mfa request header // in requests to change the versioning state of a bucket and to // permanently delete a versioned object. MFADelete MFADeleteStatus `xml:"MfaDelete"` }
func (*VersioningConfiguration) Enabled ¶
func (v *VersioningConfiguration) Enabled() bool
func (*VersioningConfiguration) SetEnabled ¶
func (v *VersioningConfiguration) SetEnabled(enabled bool)
type VersioningStatus ¶
type VersioningStatus string
const ( VersioningNone VersioningStatus = "" VersioningEnabled VersioningStatus = "Enabled" VersioningSuspended VersioningStatus = "Suspended" )
func (*VersioningStatus) UnmarshalXML ¶
func (v *VersioningStatus) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error