282 Commits

Author SHA1 Message Date
Ben McClelland
f835ef1772 Merge pull request #1719 from versity/sis/putbucketpolicy-status
fix: fixes the PutBucketPolicy response status
2025-12-31 00:29:33 -08:00
niksis02
39ee175484 fix: fixes the PutBucketPolicy response status
Fixes #1712

A successful `PutBucketPolicy` call returns `204`(No Content) http status. This PR fixes the response status code, by sending correct `204`, insted of `200`.
2025-12-29 21:10:52 +04:00
niksis02
f467b896d8 feat: adds Location in CompleteMultipartUpload response
Closes #1714

There is a `Location` field in the `CompleteMultipartUpload` result that represents the newly created object URL. This PR adds this property to the `CompleteMultipartUpload` response, generating it dynamically in either host-style or path-style format, depending on the gateway configuration.
2025-12-29 13:39:54 +04:00
niksis02
05f8225577 feat: adds missing versioning-related bucket policy actions
Closes #1635

Some S3 actions have dedicated bucket policy actions and require explicit policy permissions when operating on object versions. These actions were missing in the gateway: `GetObjectVersionTagging`, `PutObjectVersionTagging`, `DeleteObjectVersionTagging`, `DeleteObjectVersion`, and `GetObjectVersionAttributes`.

The logic for these actions is straightforward — if the incoming request includes the `versionId` query parameter, S3 enforces the corresponding bucket policy action that includes `version`.

This PR adds support for these missing actions in the gateway.
2025-11-12 23:53:27 +04:00
niksis02
eae11b44c5 fix: adds versionId validation for object level actions
Fixes #1630

S3 returns `InvalidArgument: Invalid version id specified` for invalid version IDs in object-level actions that accept `versionId` as a query parameter. The `versionId` in S3 follows a specific structure, and if the input string doesn’t match this structure, the error is returned. In the gateway, the `versionId` is generated using the `ulid` package, which also has a defined structure. This PR adds validation for object-level operations that work with object versions by using the ULID parser.

These actions include: `HeadObject`, `GetObject`, `PutObjectTagging`, `GetObjectTagging`, `DeleteObjectTagging`, `PutObjectLegalHold`, `GetObjectLegalHold`, `PutObjectRetention`, `GetObjectRetention`, `DeleteObject`, `CopyObject`, `UploadPartCopy`, and `GetObjectAttributes`.
2025-11-11 22:23:50 +04:00
niksis02
5c3cef65e2 fix: fixes s3 event and access logs sending in ProcessController
Fixes #1620

S3 events were not correctly sent by the gateway. For example, actions that don’t include a response payload caused the event emission to be skipped. This has now been fixed — S3 events are sent regardless of whether the response has a payload or if any parsing issues occur later in the `ProcessController` during body parsing.

The fix also ensures that S3 events are sent **only** for specific actions, as intended, instead of being sent for all actions.

Additionally, this update improves server access log handling by covering cases where errors occur during response payload parsing, ensuring such errors are properly reflected in the access logs.
2025-11-06 20:20:18 +04:00
niksis02
77459720ba feat: adds x-amz-tagging-count support for HeadObject
Closes #1346

`GetObject` and `HeadObject` return the `x-amz-tagging-count` header in the response, which specifies the number of tags associated with the object. This was already supported for `GetObject`, but missing for `HeadObject`. This implementation adds support for `HeadObject` in `azure` and `posix` and updates the integration tests to cover this functionality for `GetObject`.
2025-11-05 20:30:50 +04:00
niksis02
8d2eeebce3 feat: adds tagging support for object versions in posix
Closes #1343

Object version tagging support was previously missing in the gateway. The support is added with this PR. If versioning is not enabled at the gateway level and a user attempts to put, get, or delete object version tags, the gateway returns an `InvalidArgument`(Invalid versionId)
2025-11-04 23:51:22 +04:00
Ben McClelland
efe4ccb5ec Merge pull request #1613 from versity/sis/copyobject-non-empty-body
fix: adds request body check for CopyObject and UploadPartCopy
2025-11-04 11:39:56 -08:00
niksis02
9a01185be9 fix: adds request body check for CopyObject and UploadPartCopy
Fixes #1242

S3 returns a specific error for actions that expect an empty request body but receive a non-empty one. Such actions include **CopyObject** and **UploadPartCopy**, which are HTTP PUT requests with no request body. This implementation adds a check for these actions and returns the corresponding error.
2025-11-04 00:22:33 +04:00
niksis02
7744dacced fix: adds validation for bucket canned ACL
Fixes #1379

Adds validation for bucket canned ACLs in `CreateBucket` and `PutBucketAcl`. The gateway supports three values: `private`, `public-read`, and `public-read-write`. All other values (including `authenticated-read`, which is not supported) are considered invalid and result in an `InvalidArgument` error with an empty error message.
2025-11-03 22:59:06 +04:00
niksis02
9bde1ddb3a feat: implements tagging support for CreateBucket
Closes #1595

This implementation diverges from AWS S3 behavior. The `CreateBucket` request body is no longer ignored. Based on the S3 request body schema, the gateway parses only the `LocationConstraint` and `Tags` fields. If the `LocationConstraint` does not match the gateway’s region, it returns an `InvalidLocationConstraint` error.

In AWS S3, tagging during bucket creation is supported only for directory buckets. The gateway extends this support to general-purpose buckets.

If the request body is malformed, the gateway returns a `MalformedXML` error.
2025-10-31 00:59:56 +04:00
Ben McClelland
326de3b010 Merge pull request #1505 from versity/ben/head-bucket-err
fix: head object should set X-Amz-Bucket-Region on access denied
2025-10-28 14:41:48 -07:00
Ben McClelland
ee67b41a98 fix: head object should set X-Amz-Bucket-Region on access denied
The HeadObject API states that the x-amz-bucket-region header
will still get set for an access denied error to correctly indicate
region of bucket. This is needed due to the way polices work
across regions in aws, and some apps rely on this behavior.

See notes in GetBucketLocation:
In a bucket's home Region, calls to the GetBucketLocation operation
are governed by the bucket's policy. In other Regions, the bucket
policy doesn't apply, which means that cross-account access won't
be authorized. However, calls to the HeadBucket operation always
return the bucket’s location through an HTTP response header,
whether access to the bucket is authorized or not. Therefore, we
recommend using the HeadBucket operation for bucket Region
discovery and to avoid using the GetBucketLocation operation.

Fixes #1500
2025-10-28 19:50:01 +04:00
niksis02
12f4920c8d feat: implements checksum calculation for all actions
Closes #1549
Fixes #1593
Fixes #1521
Fixes #1427
Fixes #1311
Fixes #1301
Fixes #1040

This PR primarily focuses on checksum calculation within the gateway, but it also includes several related fixes and improvements.

It introduces a middleware responsible for handling and calculating checksums for the `x-amz-checksum-*` headers and `Content-MD5`. The middleware is applied only to actions that expect a request body or checksum headers. It also enforces validation for actions that require a non-empty request body, returning an error if the body is missing. Similarly, it returns an error for actions where at least one checksum header (`Content-MD5` or `x-amz-checksum-*`) is required but none is provided.
The implementation is based on [https://gist.github.com/niksis02/eec3198f03e561a0998d67af75c648d7](the reference table), tested directly against S3:

It also fixes the error case where the `x-amz-sdk-checksum-algorithm` header is present but no corresponding `x-amz-checksum-*` or `x-amz-trailer` header is included.

Additionally, the PR improves validation for the `x-amz-content-sha256` header. For actions that require this header, an error is now returned when it’s missing. For actions that don’t require it, the middleware no longer enforces its presence. Following the common S3 pattern, the header remains mandatory for admin routes.

Finally, the `x-amz-content-sha256` header is now optional for anonymous requests, as it is not required in that case.
2025-10-25 01:58:03 +04:00
niksis02
24679a82ac fix: fixes the composite checksums in CompleteMultipartUpload
Fixes #1359

The composite checksums in **CompleteMultipartUpload** generally follow the format `checksum-<number_of_parts>`. Previously, the gateway treated composite checksums as regular checksums without distinguishing between the two formats.

In S3, the `x-amz-checksum-*` headers accept both plain checksum values and the `checksum-<number_of_parts>` format. However, after a successful `CompleteMultipartUpload` request, the final checksum is always stored with the part number included.

This implementation adds support for parsing both formats—checksums with and without the part number. From now on, composite checksums are consistently stored with the part number included.

Additionally, two integration tests are added:

* One verifies the final composite checksum with part numbers.
* Another ensures invalid composite checksums are correctly rejected.
2025-10-17 16:45:07 +04:00
niksis02
d15d348226 fix: fixes the response header names normalizing
Fixes #1484

Removes response header name normalization to prevent Fiber from converting them to camel case. Also fixes the `HeadBucket` response headers by changing their capital letters to lowercase and corrects the `x-amz-meta` headers to use lowercase instead of camel case.
2025-10-15 01:27:53 +04:00
Ben McClelland
e2534afafe Merge pull request #1576 from versity/ben/cleanup
chore: cleanup unused constants
2025-10-10 09:54:02 -07:00
niksis02
707af47769 feat: prevents locked objects overwrite with CopyObject and CompleteMultipartUpload
Closes #1566

When an object is locked and bucket versioning is not configured at the gateway level, any object overwrite request should be rejected with an object locked error. The `PutObject` operation already follows this behavior, but `CopyObject` and `CompleteMultipartUpload` were missing this check. This change introduces the locking mechanism for `CopyObject` and `CompleteMultipartUpload` operations.
2025-10-10 00:39:12 +04:00
Ben McClelland
40da4a31d3 chore: cleanup unused constants
We have some leftover constants from some previous changes. This
just cleans up all that are no longer needed.
2025-10-09 12:19:00 -07:00
niksis02
5c084b8452 fix: fixes locked objects overwrite in versioning-enabled buckets
Fixes #1574

When versioning is enabled at the gateway level and object lock is enabled for a bucket, any overwrite request on a locked object should succeed since it results in the creation of a new object version. This PR fixes the logic by adding a bucket versioning status check in `CheckObjectAccess`.
2025-10-09 01:01:18 +04:00
Ben McClelland
62ca9b6ff3 Merge pull request #1560 from versity/sis/object-retention-err
fix: fixes PutObjectRetention error cases and object lock error code/message.
2025-09-25 15:12:14 -07:00
niksis02
068b04ec62 fix: fixes PutObjectRetention error cases and object lock error code/message.
Fixes #1559
Fixes #1330

This PR focuses on three main changes:

1. **Fix object lock error codes and descriptions**
   When an object was WORM-protected and delete/overwrite was disallowed due to object lock configurations, the gateway incorrectly returned the `s3.ErrObjectLocked` error code and description. These have now been corrected.
2. **Update `PutObjectRetention` behavior**
   Previously, when an object already had a retention mode set, the gateway only allowed modifications if the mode was changed from `GOVERNANCE` to `COMPLIANCE`, and only when the user had the `s3:BypassGovernanceRetention` permission.
   The logic has been updated: if the existing retention mode is the same as the one being applied, the operation is now allowed regardless of other factors.
3. **Fix error checks in integration tests (AWS SDK regression)**
   Due to an AWS SDK regression, integration tests were previously limited to checking partial error descriptions. This issue seems to be resolved for some actions (though the ticket is still open: https://github.com/aws/aws-sdk-go-v2/issues/2921). Error checks have been reverted back to full description comparisons where possible.
2025-09-25 01:41:41 +04:00
niksis02
caa7ca0f90 feat: implements fiber panic recovery
Fiber includes a built-in panic recovery middleware that catches panics in route handlers and middlewares, preventing the server from crashing and allowing it to recover. Alongside this, a stack trace handler has been implemented to store system panics in the context locals (stack).

Both the S3 API server and the Admin server use a global error handler to catch unexpected exceptions and recovered panics. The middleware’s logic is to log the panic or internal error and return an S3-style internal server error response.

Additionally, dedicated **Panic** and **InternalError** loggers have been added to the `s3api` debug logger to record system panics and internal errors in the console.
2025-09-23 22:55:38 +04:00
niksis02
ca6a92bb84 fix: changes empty mp parts error on CompleteMultipartUpload
Fixes #1328

If `CompleteMultipartUpload` is attempted with empty `Parts` list, the gateway used to return `InvalidRequest`. Now it's changed to `MalformedXML`.
2025-09-18 16:09:02 +04:00
Nick Stephen
18e30127d5 fix: #1527 - case-insensitive x-amz-checksum-mode header value 2025-09-12 11:04:19 +02:00
Ben McClelland
406161ba10 Merge pull request #1524 from versity/sis/object-get-part-number
fix: NotImplemented for GetObject/HeadObject PartNumber
2025-09-10 08:54:54 -07:00
niksis02
2bb8a1eeb7 fix: NotImplemented for GetObject/HeadObject PartNumber
Fixes #1520

Removes the incorrect logic for HeadObject returning successful response, when querying an incomplete multipart upload.

Implements the logic to return `NotImplemented` error if `GetObject`/`HeadObject` is attempted with `partNumber` in azure and posix backends. The front-end part is preserved to be used in s3 proxy backend.
2025-09-09 22:40:36 +04:00
niksis02
7a098b925f feat: implement conditional writes
Closes #821

**Implements conditional operations across object APIs:**

* **PutObject** and **CompleteMultipartUpload**:
  Supports conditional writes with `If-Match` and `If-None-Match` headers (ETag comparisons).
  Evaluation is based on an existing object with the same key in the bucket. The operation is allowed only if the preconditions are satisfied. If no object exists for the key, these headers are ignored.

* **CopyObject** and **UploadPartCopy**:
  Adds conditional reads on the copy source object with the following headers:

  * `x-amz-copy-source-if-match`
  * `x-amz-copy-source-if-none-match`
  * `x-amz-copy-source-if-modified-since`
  * `x-amz-copy-source-if-unmodified-since`
    The first two are ETag comparisons, while the latter two compare against the copy source’s `LastModified` timestamp.

* **AbortMultipartUpload**:
  Supports the `x-amz-if-match-initiated-time` header, which is true only if the multipart upload’s initialization time matches.

* **DeleteObject**:
  Adds support for:

  * `If-Match` (ETag comparison)
  * `x-amz-if-match-last-modified-time` (LastModified comparison)
  * `x-amz-if-match-size` (object size comparison)

Additionally, this PR updates precondition date parsing logic to support both **RFC1123** and **RFC3339** formats. Dates set in the future are ignored, matching AWS S3 behavior.
2025-09-09 01:55:38 +04:00
niksis02
818e91ebde feat: adds x-amz-object-size in PutObject response headers
Closes #1518

Adds the `x-amz-object-size` header to the `PutObject` response, indicating the size of the uploaded object. This change is applied to the POSIX, Azure, and S3 proxy backends.
2025-09-05 21:40:46 +04:00
Ben McClelland
24b1c45db3 cleanup: move debuglogger to top level for full project access
The debuglogger should be a top level module since we expect
all modules within the project to make use of this. If its
hidden in s3api, then contributors are less likely to make
use of this outside of s3api.
2025-09-01 20:02:02 -07:00
niksis02
b3ed7639f0 feat: implements conditional reads for GetObject and HeadObject
Closes #882

Implements conditional reads for `GetObject` and `HeadObject` in the gateway for both POSIX and Azure backends. The behavior is controlled by the `If-Match`, `If-None-Match`, `If-Modified-Since`, and `If-Unmodified-Since` request headers, where the first two perform ETag comparisons and the latter two compare against the object’s `LastModified` date. No validation is performed for invalid ETags or malformed date formats, and precondition date headers are expected to follow RFC1123; otherwise, they are ignored.

The Integration tests cover all possible combinations of conditional headers, ensuring the feature is 100% AWS S3–compatible.
2025-09-01 18:33:01 -07:00
Ben McClelland
a4091fd61c fix: previous pr was not rebased before merging and caused a build error
There was a change to the auth.VerifyAccess that changed
IsPublicBucket to IsPublicRequest, but another PR
(GetBucketLocation) that was merged at the same time
(and not rebased) was using the old version.

Update this to fix the build.
2025-09-01 17:31:56 -07:00
Ben McClelland
0bf49872cf Merge pull request #1507 from versity/ben/get-object-overrides
feat: add response header overrides for GetObject
2025-09-01 14:17:28 -07:00
Ben McClelland
8cad7fd6d9 feat: add response header overrides for GetObject
GetObject allows overriding response headers with the following
paramters:
response-cache-control
response-content-disposition
response-content-encoding
response-content-language
response-content-type
response-expires

This is only valid for signed (and pre-singed) requests. An error
is returned for anonymous requests if these are set.

More info on the GetObject overrides can be found in the GetObject
API reference.

This also clarifies the naming of the AccessOptions IsPublicBucket
to IsPublicRequest to indicate this is a public access request
and not just accessing a bucket that allows public access.

Fixes #1501
2025-08-30 14:13:20 -07:00
Ben McClelland
58117c011a feat: add get bucket location frontend handlers
GetBucketLocation is being deprecated by AWS, but is still used
by some clients. We don't need any backend handlers for this since
the region is managed by the frontend. All we need is to test for
bucket existence, so we can use HeadBucket for this.

Fixes #1499
2025-08-30 12:29:26 -07:00
niksis02
3d20a63f75 fix: adds Acces-Control-Allow-Headers to cors responses
Fixes #1486

* Adds the `Access-Control-Allow-Headers` response header to CORS responses for both **OPTIONS preflight requests** and any request containing an `Origin` header.
* The `Access-Control-Allow-Headers` response includes only the headers specified in the `Access-Control-Request-Headers` request header, always returned in lowercase.
* Fixes an issue with allow headers comparison in cors evaluation by making it case-insensitive.
* Adds missing unit tests for the **OPTIONS controller**.
2025-08-27 00:31:47 +04:00
niksis02
d90944afd1 feat: implementes GetBucketPolicyStatus s3 action
Closes #1454

Adds the implementation of [S3 GetBucketPolicyStatus action](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketPolicyStatus.html). The implementation goes to front-end. Front-End loads the bucket policy and checks if it grants public access to all users.

A bucket policy document `is public` only when `Principal` contains `*`(all users): only when it grants access to `ALL` users.
2025-08-25 21:48:06 +04:00
niksis02
09031a30e5 feat: bucket cors implementation
Closes #1003

**Changes Introduced:**

1. **S3 Bucket CORS Actions**

   * Implemented the following S3 bucket CORS APIs:

     * `PutBucketCors` – Configure CORS rules for a bucket.
     * `GetBucketCors` – Retrieve the current CORS configuration for a bucket.
     * `DeleteBucketCors` – Remove CORS configuration from a bucket.

2. **CORS Preflight Handling**

   * Added an `OPTIONS` endpoint to handle browser preflight requests.
   * The endpoint evaluates incoming requests against bucket CORS rules and returns the appropriate `Access-Control-*` headers.

3. **CORS Middleware**

   * Implemented middleware that:

     * Checks if a bucket has CORS configured.
     * Detects the `Origin` header in the request.
     * Adds the necessary `Access-Control-*` headers to the response when the request matches the bucket CORS configuration.
2025-08-20 20:45:09 +04:00
Ben McClelland
3842253962 Merge pull request #1417 from versity/sis/ignore-special-checksum-headers
fix: ignores special checksum headers when parsing x-amz-checksum-x headers
2025-07-25 22:20:34 -07:00
Ben McClelland
fb372e497d Merge pull request #1415 from versity/sis/listbuckets-region
fix: adds bucket region in ListBuckets result
2025-07-25 14:42:23 -07:00
niksis02
e18c4f4080 fix: ignores special checksum headers when parsing x-amz-checksum-x headers
Fixes #1345

The previous implementation incorrectly parsed the `x-amz-sdk-checksum-algorithm` header for the `CompleteMultipartUpload` operation, even though this header is not expected and should be ignored. It also mistakenly treated the `x-amz-checksum-algorithm` header as an invalid value for `x-amz-checksum-x`.

The updated implementation only parses the `x-amz-sdk-checksum-algorithm` header for `PutObject` and `UploadPart` operations. Additionally, `x-amz-checksum-algorithm` and `x-amz-checksum-type` headers are now correctly ignored when parsing the precalculated checksum headers (`x-amz-checksum-x`).
2025-07-26 01:33:00 +04:00
niksis02
7dc213e68e fix: adds bucket region in ListBuckets result
Fixes #1374

Hardcodes the gateway region for each bucket entry in `ListBuckets` result as bucket region.
2025-07-26 00:45:18 +04:00
niksis02
3363988206 fix: makes checksum type and algorithm case insensitive in CreateMultipartUpload
Fixes #1339

`x-amz-checksum-type` and `x-amz-checksum-algorithm` request headers should be case insensitive in `CreateMultipartUpload`.

The changes include parsing the header values to upper case before validating and passing to back-end. `x-amz-checksum-type` response header was added in`CreateMultipartUpload`, which was missing before.
2025-07-25 20:35:26 +04:00
niksis02
891672bf7e fix: fixes the HeadObject version access control with policies.
Fixes #1385

When accessing a specific object version, the user must have the `s3:GetObjectVersion` permission in the bucket policy. The `s3:GetObject` permission alone is not sufficient for a regular user to query object versions using `HeadObject`.

This PR fixes the issue and adds integration tests for both `HeadObject` and `GetObject`. It also includes cleanup in the integration tests by refactoring the creation of user S3 clients, and moves some test user data to the package level to avoid repetition across tests.
2025-07-24 01:04:45 +04:00
niksis02
e5850ff11f feat: adds copy source validation for x-amz-copy-source header.
Fixes #1388
Fixes #1389
Fixes #1390
Fixes #1401

Adds the `x-amz-copy-source` header validation for `CopyObject` and `UploadPartCopy` in front-end.
The error:
```
	ErrInvalidCopySource: {
		Code:           "InvalidArgument",
		Description:    "Copy Source must mention the source bucket and key: sourcebucket/sourcekey.",
		HTTPStatusCode: http.StatusBadRequest,
	},
```
is now deprecated.

The conditional read/write headers validation in `CopyObject` should come with #821 and #822.
2025-07-22 14:40:11 -07:00
niksis02
e74d2c0d19 fix: fixes the invalid x-amz-mp-object-size header error in CompleteMultipartUpload.
Fixes #1398

The `x-amz-mp-object-size` request header can have two erroneous states: an invalid value or a negative integer. AWS returns different error descriptions for each case. This PR fixes the error description for the invalid header value case.

The invalid case can't be integration tested as SDK expects `int64` as the header value.
2025-07-22 21:01:32 +04:00
niksis02
dc16c0448f feat: implements integration tests for the new advanced router 2025-07-22 21:00:24 +04:00
niksis02
394675a5a8 feat: implements unit tests for controller utilities 2025-07-22 20:55:23 +04:00
niksis02
ab571a6571 feat: implements unit tests for admin controllers 2025-07-22 20:55:22 +04:00