Skip to main content

GetObject

GetObject downloads an object. Without anything extra it returns the current version, whole; Range or partNumber returns part of it, and versionId returns an earlier version. When only the metadata is needed, HeadObject answers the same question without the body.

Someone without an access key can download an object too, in one of two ways: through a presigned URL - Sharing an object with a presigned URL shows how - or from a bucket whose Bucket Protection is switched off, which makes every object in it readable without credentials, as Reading from a public bucket describes.

Good to know on STRG
  • An unsigned read of a public bucket can be answered from a cache for up to 5 minutes - less if the object's own Cache-Control asks for less. That keeps popular public files quick, and it also means that for up to 5 minutes after an object is overwritten or deleted, Bucket Protection is switched back on, or the bucket's CORS rules change, unsigned readers can still get the earlier answer. Signed requests always read the stored object. Caching of unsigned reads has the details.
  • response-content-disposition and the other response-* values are Latin-1 text; a value with other characters is answered 500 InternalError. The filename*=UTF-8''… form carries a file name in any script.
  • A key with a . or .. path segment (a/../b) cannot travel in a URL intact, so STRG answers 400 InvalidURI to a request for one, signed or unsigned.
  • x-amz-expected-bucket-owner is welcome and has nothing to check: a key only ever reaches buckets of its own account.

When you'd use it​

  • Downloads in an app. A web app lets its users download their invoices or photos. The server makes a presigned GetObject URL with response-content-disposition, and the browser fetches the file straight from STRG and saves it under a friendly name.
  • Streaming and seeking. A video player or a tool reading a large archive asks for just the bytes it needs with Range, so seeking to minute 40 does not mean downloading the first 39.
  • Restoring an earlier version. Every STRG bucket keeps versions, so a backup job or a person who overwrote a file by mistake can read the version from yesterday by its versionId.
  • Public files and agents. A website serves its images from a public bucket with no credentials at all, and an agent that keeps its notes in a bucket reads them back at the start of every session.

Request​

GET /photos/2024/cat.jpg HTTP/1.1
Host: my-bucket.s3.eu-central-1.strg.com
Authorization: AWS4-HMAC-SHA256 Credential=...
x-amz-date: 20260926T120000Z
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Range: bytes=0-1023

The path-style form is GET /my-bucket/photos/2024/cat.jpg on s3.eu-central-1.strg.com, which a bucket name containing a dot needs - Addressing explains both.

Permissions​

The access key needs Read objects (objects:read), and the same permission reads the current version and every earlier one. For a key limited to certain buckets or to a key prefix, the bucket and the object key are within them. Access keys has the details.

An unsigned request needs no access key at all, and is answered for a bucket whose Bucket Protection is off. For a protected bucket the answer is 403 AccessDenied.

URI parameters​

NameTypeRequiredDescription
BucketStringYesThe bucket holding the object.
KeyStringYesThe object key. A key containing a . or .. path segment is answered 400 InvalidURI.
versionIdStringNoThe version to read; without it, the current version. Version IDs come from ListObjectVersions and from the x-amz-version-id response header, and are opaque strings.
partNumberIntegerNoReturns just this part of an object uploaded with multipart upload, 1-10,000. The response is 206 Partial Content.
response-cache-controlStringNoSets Cache-Control on the response.
response-content-dispositionStringNoSets Content-Disposition on the response - attachment; filename="cat.jpg", for example, makes a browser save the file. The value is Latin-1 text; the filename*=UTF-8''… form carries other characters.
response-content-encodingStringNoSets Content-Encoding on the response.
response-content-languageStringNoSets Content-Language on the response.
response-content-typeStringNoSets Content-Type on the response.
response-expiresStringNoSets Expires on the response.

The response-* parameters apply to a 200 or 206 answer, never to a 304 or an error. They belong to signed requests and presigned URLs: an unsigned request carrying one is answered 400 InvalidRequest, just as on Amazon S3. Any other query parameter - a presigned URL's own X-Amz-* parameters aside - is answered 501 NotImplemented, so a client learns straight away that it has no effect here.

Request headers​

NameTypeRequiredDescription
RangeStringNoOne byte range per request, as on Amazon S3: bytes=<first>-<last>, bytes=<first>- or bytes=-<suffix length>. The response is 206 Partial Content.
If-MatchStringNoReturns the object only if its ETag matches; otherwise 412 Precondition Failed.
If-None-MatchStringNoReturns the object only if its ETag differs; otherwise 304 Not Modified.
If-Modified-SinceTimestampNoReturns the object only if it changed after this time; otherwise 304 Not Modified.
If-Unmodified-SinceTimestampNoReturns the object only if it has not changed since this time; otherwise 412 Precondition Failed.
x-amz-server-side-encryption-customer-algorithmStringFor SSE-CAES256, for an object stored with a customer-provided key (SSE-C).
x-amz-server-side-encryption-customer-keyStringFor SSE-CThe base64-encoded 256-bit key the object was stored with.
x-amz-server-side-encryption-customer-key-MD5StringFor SSE-CThe base64-encoded MD5 digest of that key.
x-amz-checksum-modeStringNoENABLED asks for the object's stored checksum in the response.
x-amz-expected-bucket-ownerStringNoWelcome, with nothing to check: an access key only ever reaches its own account's buckets.
x-amz-request-payerStringNoHas no effect: STRG has no Requester Pays buckets.

On a signed request, every x-amz-* header is part of the signature - Authentication explains how.

Request body​

None.

Response​

A successful read answers 200 OK with the object as the body, or 206 Partial Content for a Range or partNumber request.

Response headers​

These headers describe the object and the part of it the body holds.

NameDescription
Content-LengthThe size of the body in bytes.
Content-TypeThe object's media type, or the response-content-type value.
Content-RangeFor a 206: the bytes returned and the object's total size, bytes 0-1023/52431.
Accept-Rangesbytes.
ETagThe object's entity tag.
Last-ModifiedWhen this version was written.
Cache-Control, Content-Disposition, Content-Encoding, Content-Language, ExpiresAs stored with the object, or the matching response-* value.
x-amz-meta-*The object's user-defined metadata.
x-amz-version-idThe version returned.
x-amz-delete-markertrue, on a 404, when the object's current version is a delete marker.
x-amz-mp-parts-countWith partNumber: how many parts the object has.
x-amz-checksum-crc32, x-amz-checksum-crc32c, x-amz-checksum-crc64nvme, x-amz-checksum-sha1, x-amz-checksum-sha256, x-amz-checksum-typeThe object's stored checksum, where one was stored. Never sent with a 304, which has no body to check.
x-amz-server-side-encryptionAES256 for an object encrypted with STRG-managed keys.
x-amz-server-side-encryption-customer-algorithm, x-amz-server-side-encryption-customer-key-MD5For an SSE-C object, confirming the key that was sent.
x-amz-object-lock-mode, x-amz-object-lock-retain-until-dateThe version's retention, included when the access key also has Read retention. Object Lock explains retention.
x-amz-object-lock-legal-holdThe version's legal hold, included when the access key also has Read legal holds.
x-amz-request-id, x-amz-id-2The request ID, useful when asking support about a request.
Access-Control-Allow-Origin, Access-Control-Allow-Credentials, Access-Control-Expose-Headers, VaryFor a browser request whose Origin the bucket's CORS rules allow, signed or unsigned. CORS rules has the details.

x-amz-storage-class is absent or STANDARD: every object is STANDARD. Some other S3 response headers have nothing to describe on STRG, so they never appear: x-amz-tagging-count (objects carry no tags), x-amz-website-redirect-location, x-amz-replication-status, x-amz-restore, x-amz-missing-meta, x-amz-request-charged, x-amz-checksum-md5, x-amz-checksum-sha512 and x-amz-checksum-xxhash3, -xxhash64 and -xxhash128 (uploads store the five checksum algorithms listed above), the SSE-KMS headers (x-amz-server-side-encryption-aws-kms-key-id, x-amz-server-side-encryption-bucket-key-enabled) and the Object Lock event hold headers (x-amz-object-lock-event-hold*). x-amz-expiration is not a dependable guide to when an object expires; the bucket's lifecycle rules are.

Response body​

The object's bytes, exactly as stored - or the requested range or part of them.

Caching of unsigned reads​

An unsigned GetObject of a public bucket's object can be answered from an edge cache rather than from storage, which makes popular public files quick to fetch. A signed request or a presigned URL always reads the stored object. This is how the cache decides:

What is cachedA 200 answer whose Cache-Control lets a shared cache keep it: s-maxage - or, without one, max-age - greater than 0, and none of no-store, no-cache or private. An object stored without such a Cache-Control is never cached. The Cache-Control header of PutObject sets it
For how longThe shorter of that lifetime and 5 minutes. The response still carries the object's own Cache-Control, which browsers and other caches follow
From the cacheRange requests (206), and If-None-Match and If-Modified-Since (304)
Always from storageA request carrying If-Match, If-Unmodified-Since, If-Range or any x-amz-* header, or a query parameter other than versionId
After a changeThe cache is never cleared early. For up to 5 minutes - or the object's shorter lifetime - unsigned readers can still get the earlier answer after the object is overwritten or deleted, after Bucket Protection is switched back on, or after the bucket's CORS rules change. An object that changes often does well with a short max-age or s-maxage

Errors​

These are the answers a read can get instead of the object, and the situation behind each.

CodeHTTP statusWhen
-304If-None-Match or If-Modified-Since did not match. Not an error: the SDKs report it as not modified.
PreconditionFailed412If-Match or If-Unmodified-Since did not match.
InvalidRange416The Range starts beyond the end of the object.
NoSuchKey404No object has this key, or its current version is a delete marker.
NoSuchBucket404The bucket does not exist, it is in a region other than the endpoint's, or the account has no storage in this endpoint's region. An unsigned request can also get it for a few seconds after a bucket is created.
AccessDenied403The access key lacks Read objects, or the bucket or key is outside its buckets or prefix. Also an expired presigned URL, an unsigned x-amz-* header, and an unsigned request to a bucket whose Bucket Protection is on.
InvalidRequest400An unsigned request carries a response-* parameter.
InvalidURI400The object key contains a . or .. path segment, signed or unsigned.
InvalidAccessKeyId403The access key does not exist, has expired or been revoked - or it was created moments ago and is not usable yet in a region where the account already stores data, in which case the same request works shortly afterwards. Until then the dashboard's Access Keys page shows Setting up in … for that region, and Ready in … once it is done.
SignatureDoesNotMatch403The request signature does not match.
RequestTimeTooSkewed403The request time is more than 15 minutes from the server's.
AuthorizationHeaderMalformed400The signature's credential scope names a region other than the endpoint's.
NotImplemented501The request carries a query parameter GetObject does not take.
InternalError500A response-* value contains characters outside Latin-1.
SlowDown503Too many requests. The Retry-After header says when a retry is welcome; the AWS SDKs retry on their own.
ServiceUnavailable503A temporary failure; the same request can be retried.

Differences from Amazon S3​

The table lists each place where STRG behaves differently, and what that means for a client.

AspectAmazon S3STRG
Unsigned reads of a public objectRead from storageCan be served from a cache for up to 5 minutes, or the object's shorter Cache-Control lifetime - including after it was overwritten or deleted, Bucket Protection was switched on, or the CORS rules changed. A signed request always reads the stored object
response-* valuesAny value S3 acceptsLatin-1 text; other characters are answered 500 InternalError. filename*=UTF-8''… in response-content-disposition carries any file name
Bucket in another region301 redirect with x-amz-bucket-region404 NoSuchBucket. A bucket is reached through its own regional endpoint
Keys with . or .. segmentsAllowed400 InvalidURI
Unknown query parametersIgnored501 NotImplemented, so a client learns straight away that the parameter has no effect
x-amz-expected-bucket-ownerChecked against the bucket ownerWelcome, with nothing to check
Object Lock headersReturned with s3:GetObjectRetention / s3:GetObjectLegalHoldReturned with Read retention / Read legal holds

Examples​

Downloading photos/2024/cat.jpg to a local file:

aws s3api get-object \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1 \
cat.jpg

Reading a byte range​

The first 1,024 bytes of the object:

aws s3api get-object \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--range bytes=0-1023 \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1 \
cat-head.bin

Reading an earlier version​

Here the version ID, from ListObjectVersions, is in VERSION_ID:

aws s3api get-object \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--version-id "$VERSION_ID" \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1 \
cat-previous.jpg

Reading from a public bucket​

Once a bucket's Bucket Protection is off, anyone can read its objects without credentials, at https://s3.eu-central-1.strg.com/my-bucket/photos/2024/cat.jpg or https://my-bucket.s3.eu-central-1.strg.com/photos/2024/cat.jpg:

curl -O https://my-bucket.s3.eu-central-1.strg.com/photos/2024/cat.jpg

The SDKs send an unsigned request when they are configured not to sign:

aws s3api get-object \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--no-sign-request \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1 \
cat.jpg

Sharing an object with a presigned URL​

A presigned URL lets anyone who has it download the object until it expires, with no access key of their own. It carries the permissions of the key that signed it, so that key needs Read objects. The expiry can be anything from 1 second to 7 days (604,800 seconds), and revoking the signing key stops the URL working within 60 seconds.

This URL is valid for one hour and makes a browser save the file as cat.jpg:

aws s3 presign s3://my-bucket/photos/2024/cat.jpg \
--expires-in 3600 \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1

The AWS CLI's presign has no option for response-* parameters; the SDKs, in the other two tabs, can add them.

View as Markdown