Commit Graph

385 Commits

Author SHA1 Message Date
Ben McClelland
69a3483269 Merge pull request #1592 from versity/sis/bucket-object-tag-validation
fix: fixes the bucket/object tagging key/value name validation
2025-10-20 12:21:01 -07:00
Ben McClelland
d256ea5929 Merge pull request #1589 from versity/sis/complete-mp-composite-checksum
fix: fixes the composite checksums in CompleteMultipartUpload
2025-10-20 09:25:17 -07:00
niksis02
ebf7a030cc fix: fixes the bucket/object tagging key/value name validation
Fixes #1579

S3 enforces a specific rule for validating bucket and object tag key/value names. This PR integrates the regexp pattern used by S3 for tag validation.
Official S3 documentation for tag validation rules: [AWS S3 Tag](https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_Tag.html)

There are two types of tagging inputs for buckets and objects:

1. **On existing buckets/objects** — used in the `PutObjectTagging` and `PutBucketTagging` actions, where tags are provided in the request body.
2. **On object creation** — used in the `PutObject`, `CreateMultipartUpload`, and `CopyObject` actions, where tags are provided in the request headers and must be URL-encoded.

This implementation ensures correct validation for both types of tag inputs.
2025-10-20 15:19:38 +04:00
niksis02
27dc84b5fd fix: implements proper error handling for malformed http requests
Fixes #1364

When a completely malformed request is sent to the gateway, Fiber/Fasthttp fails to parse the request, and the code execution never reaches the routers or handlers. Instead, the error is caught by the global error handler. These kinds of errors (malformed requests that fail during request parsing) are prefixed with **"error when reading request headers"** in Fiber. The implementation adds a check in the global error handler for this specific error message and returns an S3-like XML **BadRequest** error instead.
2025-10-17 19:19:47 +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
Ben McClelland
bfe090df38 Merge pull request #1585 from versity/sis/expected-bucket-owner
feat: adds the x-amz-expected-bucket-owner check in the gateway
2025-10-15 14:35:07 -07:00
niksis02
d39685947d feat: adds the x-amz-expected-bucket-owner check in the gateway
Fixes #1428

The `x-amz-expected-bucket-owner` header in S3 specifies the account ID of the expected bucket owner. If the account ID provided does not match the actual owner of the bucket, the request fails with an HTTP 403 Forbidden (AccessDenied) error. If the provided account ID is not 12 characters long, S3 returns a 400 Bad Request error.

In our case, we expect the header to contain the bucket owner’s access key ID, and we skip validation errors related to the access key ID, since there is no validation mechanism for user access key IDs. If the provided value does not match the bucket owner’s access key ID, the gateway returns an AccessDenied error.

A few integration tests are added for random actions, as this feature applies to all actions, but it is unnecessary to add test cases for every single one.
2025-10-15 19:20:04 +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
niksis02
64f50cc504 feat: gracul shutdown of s3api and admin servers
Implements graceful shutdown for the admin and s3api servers. They are shut down before other components (IAM, s3logger, etc.) to allow the servers to properly handle any pending requests while dependencies are still active. The shutdown process is controlled by a context with a 10-second timeout. If it exceeds this duration, all remaining requests are forcefully terminated and the servers are closed.
2025-10-10 22:10:56 +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
Ben McClelland
874165cdcf Merge pull request #1575 from versity/sis/locked-objects-overwrite
fix: fixes locked objects overwrite in versioning-enabled buckets
2025-10-09 10:55:47 -07:00
Ben McClelland
4c3965d87e feat: add option to disable strict bucket name checks
Some systems may choose to allow non-aws compliant bucket names
and/or handle the bucket naem validation in the backend instead.
This adds the option to turn off the strict bucket name validation
checks in the frontend API handlers.

When frontend bucket name validation is disabled, we need to do
sanity checks for posix compliant names in the posix/scoutfs
backends. This is automatically enabled when strict bucket
name validation is disabled.

Fixes #1564
2025-10-08 14:34:52 -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
54e2c39df1 fix: fixes the invalid Content-Length error
Fixes #1426

Fiber returns a custom error, if it fails to parse the `Content-Length` header. This implementation adds a check in the fiber global error handler to return an empty `400` Bad Request error, if fiber fails to parse the `Content-Length` header.
2025-09-23 23:22:51 +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
df74e7fde6 fix: adds checks for x-amz-content-sha256 in anonymous requests
Fixes #1554
Fixes #1423

The gateway previously ignored the `x-amz-content-sha256` header for anonymous unsigned requests to public buckets. This PR adds hash calculation for this header and correctly handles special payload types.

It also fixes the case where a signed streaming payload (`STREAMING-AWS4-HMAC-SHA256-PAYLOAD...`) is used with anonymous requests. In this scenario, the gateway now returns a specific "not supported" error, consistent with S3 behavior.
2025-09-23 00:44:14 +04:00
Ben McClelland
6a34f3a848 Merge pull request #1550 from versity/sis/content-md5-actions
fix: removes content-md5 check from the actions where it's unnecessary
2025-09-22 10:46:30 -07:00
Ben McClelland
6b64783db7 Merge pull request #1548 from versity/sis/host-style-trailing-slash
fix: removes trailing / for bucket operations in host-style parser
2025-09-22 10:45:53 -07:00
Ben McClelland
b5b823c47b Merge pull request #1546 from versity/sis/incorrect-md5
fix: adds BadDigest error for incorrect Content-Md5 s
2025-09-22 10:44:56 -07:00
niksis02
a057a254c1 fix: removes content-md5 check from the actions where it's unnecessary
Fixes #1545

`Content-Md5` should be validated/calculated only for the actions containing request body, which are:
* All bucket `PUT` operations(PutBucketTagging, PutBucketVersioning ...)
* All object `PUT` operations(PutObject, UploadPart ...) except for object copy ones(CopyObject, UploadPartCopy)
* Object `POST` operations(CompleteMultipartUpload, RestoreObject ...), but not for `CreateMultipartUpload`, as it doesn't have request body.
* Bucket `POST` operation(DeleteObjects).

The PR removes the `Content-Md5` check from bucket/object GET/HEAD operations and from `PUT`/`POST` operations not expecting request body.
2025-09-19 21:52:11 +04:00
niksis02
f435880fe8 fix: removes trailing / for bucket operations in host-style parser
For bucket operations a typical host-style request looks like `bucket.host/`. `HostStyleParser` parses the bucket from host header and appends in the path, by changing the requests to `path-styled`. For bucket operations the original request path is `bucket.host/`, after reconsturction it looks like `/bucket/`: a trailing `/` is added at the end.

The PR adds a check to not append this trailing `/` at the end for bucket operations, to keep consistency with path-style requests.
2025-09-19 20:53:00 +04:00
niksis02
ebdda06633 fix: adds BadDigest error for incorrect Content-Md5 s
Closes #1525

* Adds validation for the `Content-MD5` header.
  * If the header value is invalid, the gateway now returns an `InvalidDigest` error.
  * If the value is valid but does not match the payload, it returns a `BadDigest` error.
* Adds integration test cases for `PutBucketCors` with `Content-MD5`.
2025-09-19 19:51:23 +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
niksis02
6176d9eb46 fix: fixes sigv4 and presigned url auth errors.
Fixes #1540
Fixes #1538
Fixes #1513
Fixes #1425

Fixes SigV4 authentication and presigned URL error handling. Adds two sets of errors in the `s3err` package for these authentication mechanisms.

* Adds a check to return a custom "not supported" error when `X-Amz-Security-Token` is present in presigned URLs.
* Adds a check to return a custom "not supported" error when the `AWS4-ECDSA-P256-SHA256` algorithm is used in presigned URLs.
2025-09-18 00:11:12 +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
743707b9ae Merge pull request #1509 from versity/ben/chunk-panic
fix: panic in signed-chunk-reader with incorrect debug string
2025-09-02 14:06:34 -07:00
Ben McClelland
488a9ac1bb fix: panic in signed-chunk-reader with incorrect debug string
The following panic was triggered when mc client (that uses
chunked uploads) would upload a 171164 byte file. This likely
could have been hit with other sizes as well, but this size
was able to reliably reproduce the issue.

panic: runtime error: slice bounds out of range [:2] with capacity 1

goroutine 66 [running]:
github.com/versity/versitygw/s3api/utils.(*ChunkReader).parseChunkHeaderBytes(0x14000276200, {0x14000167fff?, 0x14000103180?, 0x200000003?})
	versitygw/s3api/utils/signed-chunk-reader.go:372 +0xe54
github.com/versity/versitygw/s3api/utils.(*ChunkReader).parseAndRemoveChunkInfo(0x14000276200, {0x14000167fff, 0x1, 0x1})
	versitygw/s3api/utils/signed-chunk-reader.go:251 +0x50
github.com/versity/versitygw/s3api/utils.(*ChunkReader).Read(0x14000276200, {0x14000160000, 0x14000056c00?, 0x8000})
	versitygw/s3api/utils/signed-chunk-reader.go:126 +0x188
io.(*teeReader).Read(0x140000b09c0, {0x14000160000, 0x105e7b368?, 0x8000})
	/usr/local/go/src/io/io.go:628 +0x34
...

The reproducer is:
% truncate -s 171764 testfile
% mc cp testfile gwtest/mybucket/testfile
mc: <ERROR> Failed to copy `/Users/ben/repo/s3perf/tools/testfile`. Put "http://127.0.0.1:7070/mybucket/testfile": dial tcp 127.0.0.1:7070: connect: connection refused

The panic can happen because the capacity of header ([]byte) at
the point of the debuglog line can be less than 2, but we were
trying to always send the first 2 bytes to the debug log.
2025-09-02 08:30:03 -07: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
14a2984d59 feat: adds not implemented routes for bucket website actions
Closes #1450

Adds `NotImplemented` routes for bucket website S3 actions:
- `PutBucketWebsite`
- `GetBucketWebsite`
- `DeleteBucketWebsite`
2025-08-22 19:56:51 +04:00
niksis02
0895ada9ed feat: adds not implemented routes for bucket accelerate configuration actions
Closes #1452

Adds `NotImplemented` routes for bucket accelerate configuration S3 actions:
- `PutBucketAccelerateConfiguration`
- `GetBucketAccelerateConfiguration`
2025-08-22 14:45:42 +04:00
niksis02
d784c0a841 feat: adds not implemented routes for bucket notification configuration actions
Closes #1453

Adds `NotImplemented` routes for bucket notification configuration S3 actions:
- `PutBucketNotificationConfiguration`
- `GetBucketNotificationConfiguration`
2025-08-21 20:40:18 +04:00
niksis02
be79fc249d feat: adds not implemented routes for bucket public access block actions
Closes #1451

Adds `NotImplemented` routes for bucket public access block S3 actions:
- `PutPublicAccessBlock`
- `GetPublicAccessBlock`
- `DeletePublicAccessBlock`
2025-08-21 20:10:29 +04:00
niksis02
88f84bfd89 feat: adds not implemented routes for bucket replication actions
Closes #1449

Adds `NotImplemented` routes for bucket replication S3 actions:
- `PutBucketReplication`
- `GetBucketReplication`
- `DeleteBucketReplication`

Adds missing actions in metrics `ActionMap`
2025-08-21 16:44:29 +04:00
niksis02
45a1f7ae7c feat: adds not implemented routes for bucket metrics configuration actions
Closes #1445

Adds `NotImplemented` routes for bucket metrics configuration S3 actions:
- `PutBucketMetricsConfiguration`
- `GetBucketMetricsConfiguration`
- `ListBucketMetricsConfigurations`
- `DeleteBucketMetricsConfiguration`

Adds the missing bucket actions to `supportedActionList` in bucket policy supported actions list.
2025-08-21 16:05:06 +04:00
Ben McClelland
be1708b1df Merge pull request #1476 from versity/sis/bucket-request-payment-actions-not-implemented
feat: adds not implemented routes for bucket request payment actions
2025-08-20 17:10:54 -07:00