Documentation
¶
Overview ¶
Package objops implements the transport-agnostic object operations (Put/Get/Head/Delete) shared by the HTTP S3 handler and the native proto handler. It is the single place where:
- token-level authorization is applied (via auth.Authorize)
- bucket-policy deny overlays are evaluated (via auth.EvaluatePolicyDeny)
- metadata is written / read / deleted against meta.DB
- bytes are streamed to/from the physical store
Both transports must route through this package. Do not duplicate these rules in the handlers.
Index ¶
- Variables
- type Identity
- type PutOptions
- type PutResult
- type Service
- func (s *Service) DeleteObject(_ context.Context, token *meta.Token, bucketName, key string, ...) error
- func (s *Service) GetObject(_ context.Context, token *meta.Token, bucketName, key string, w io.Writer, ...) (*meta.Object, error)
- func (s *Service) HeadObject(_ context.Context, token *meta.Token, bucketName, key string, ...) (*meta.Object, error)
- func (s *Service) OpenObjectFile(obj *meta.Object) (*os.File, error)
- func (s *Service) PutObject(_ context.Context, token *meta.Token, bucketName, key, contentType string, ...) (*meta.Object, error)
Constants ¶
This section is empty.
Variables ¶
var ( // ErrBucketNotFound: the named bucket does not exist. ErrBucketNotFound = errors.New("objops: bucket not found") // ErrObjectNotFound: the named object does not exist in the bucket. ErrObjectNotFound = errors.New("objops: object not found") // ErrPolicyDenied: bucket-policy evaluator returned a deny match. This is // distinct from a token-level authorization failure (see ErrAccessDenied). ErrPolicyDenied = errors.New("objops: access denied by bucket policy") // ErrAccessDenied: token-level authorization failed. ErrAccessDenied = errors.New("objops: access denied") // ErrBadPolicy: the bucket policy JSON could not be unmarshalled. Treated // as deny (fail-closed) — never as allow. ErrBadPolicy = errors.New("objops: malformed bucket policy") )
Exported errors so handlers can map them to transport-specific status codes.
Functions ¶
This section is empty.
Types ¶
type Identity ¶
type Identity struct {
TokenID string
AccountID string
SourceIP string
// Action is the meta.Action* constant for the operation (e.g.
// meta.ActionObjectGet). This is what the bucket policy evaluator matches
// against — the actions field of policy statements uses the same strings.
Action string
}
Identity carries the authenticated caller context needed for policy evaluation. TokenID may be empty for anonymous reads on public-read buckets (the handler will not build an Identity in that case unless asked to).
type PutOptions ¶
type PutOptions struct {
// UserMetadata holds x-amz-meta-* headers (HTTP) or a decoded metadata map
// (native proto). Keys should already be lower-cased and sanitized.
UserMetadata map[string]string
}
PutOptions carry per-request metadata that doesn't fit in the required args.
type PutResult ¶
PutResult is returned by PutObject so both transports can produce the same response shape (ETag / checksum / size).
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service is the transport-agnostic object-operations service.
func (*Service) DeleteObject ¶
func (s *Service) DeleteObject( _ context.Context, token *meta.Token, bucketName, key string, identity Identity, ) error
DeleteObject marks the object deleted in metadata and GCs its physical file. Returns nil if the object did not exist (S3 semantics: DELETE is idempotent).
func (*Service) GetObject ¶
func (s *Service) GetObject( _ context.Context, token *meta.Token, bucketName, key string, w io.Writer, identity Identity, ) (*meta.Object, error)
GetObject resolves metadata + opens the stored file and streams it to w via io.Copy. On Linux, when w is a *net.TCPConn or an io.ReaderFrom that wraps one (e.g. api.statusWriter), the kernel's sendfile(2) takes over and the bytes never touch userspace. For that reason we do NOT re-hash on read here — the scrubber owns integrity verification (maintenance/scrub.go).
The object is returned so callers can set transport-specific response headers (ETag, Content-Length, Content-Type, Last-Modified, x-amz-meta-*).
If w is nil, GetObject returns the Object without streaming bytes — this is HEAD semantics. Callers should prefer HeadObject for clarity.
func (*Service) HeadObject ¶
func (s *Service) HeadObject( _ context.Context, token *meta.Token, bucketName, key string, identity Identity, ) (*meta.Object, error)
HeadObject returns object metadata only — no body stream.
func (*Service) OpenObjectFile ¶
OpenObjectFile opens the physical file at obj.LocationRef for direct transport use. The HTTP handler needs Seek for Range support; the proto handler needs a reader for its frame writer. Caller must Close the file.
This is the one place outside GetObject where the store is opened by location_ref — it skips the auth check (the caller already has an authorized *meta.Object in hand). Do NOT export this to callers that received the Object from an untrusted source.
func (*Service) PutObject ¶
func (s *Service) PutObject( _ context.Context, token *meta.Token, bucketName, key, contentType string, body io.Reader, opts PutOptions, identity Identity, ) (*meta.Object, error)
PutObject writes body to the store, commits metadata, and returns the new object. On overwrite the previous version's physical file is GC'd. On metadata commit failure the freshly-written file is cleaned up.
The caller is responsible for setting Content-Length / Content-Type headers on HTTP responses — PutObject only fills *meta.Object and returns it.