552 Commits

Author SHA1 Message Date
Ben McClelland
efd1885d21 Merge pull request #2023 from versity/sis/move-versionid-validation-backend
fix: move versionId validation to backend
2026-04-10 11:23:20 -07:00
Luke McCrone
d7d9179db0 test: ListObjectsV1 updates, file code changes, multipart updates 2026-04-07 15:24:20 -03:00
niksis02
b473aa0545 fix: move versionId validation to backend
Closes #1813

We use a specific `versionId` format(`ulid` package) to generate versionIds in posix, which is not compatible to S3. The versionId validation was performed in frontend which is a potential source of failure for s3 proxy configured on an s3 service which doesn't use ulid for versionId generation(e.g. aws S3). These changes move the specific `ulid` versionId validation to posix to not force any specific versionId format in the gateway.
2026-04-07 01:56:51 +04:00
Ben McClelland
1fca33e738 Merge pull request #2006 from versity/ben/racing-put-delete
fix: retry link on ENOENT caused by racing DeleteObject
2026-04-02 09:57:48 -07:00
Ben McClelland
98a186cc4e Merge pull request #2008 from versity/sis/object-post-boundary-prefix
fix: remove POST object multipart boundary prefix trimming
2026-04-02 08:27:02 -07:00
Ben McClelland
71ae9bf045 Merge pull request #2005 from versity/sis/copyobject-expected-source-bucket-owner
feat: implement x-amz-source-expected-bucket-owner for CopyObject and UploadPartCopy
2026-04-02 08:25:50 -07:00
Ben McClelland
c26012905c fix: retry link on ENOENT caused by racing DeleteObject
A concurrent PutObject and DeleteObject on the same prefix directory
can race:
PutObject opens an O_TMPFILE in MetaTmpDir (not yet visible in the fs)
DeleteObject removes the last visible object in the prefix directory
and calls removeParents(), which rmdir's the now-empty prefix
directory
PutObject's link() tries to link the fd into a parent directory that
no longer exists

Fix by detecting ENOENT in the final link step (Linkat, Rename, and
MoveFile) and retrying after recreating the parent directory.

Also extract linkatOTmpfile() to consolidate the Linkat+EEXIST→Renameat
logic that was previously inline in link().

Fixes #1988
2026-04-02 08:14:44 -07:00
niksis02
a25408c225 fix: remove POST object multipart boundary prefix trimming
Fixes the [comment](https://github.com/versity/versitygw/issues/1648#issuecomment-4175425099)

Removes the unnecessary multipart/form-data boundary normalizing. The boundary prefix(`--`) was trimmed in `NewMultipartParser`, which caused incorrect boundary check for the boundaries starting with 2 dashes(e.g. `----WebKitFormBoundaryABC123`).
2026-04-02 17:20:23 +04:00
Luke McCrone
6b93190922 test: fix response code 2026-04-01 15:13:58 -03:00
niksis02
052f2364cc feat: implement x-amz-source-expected-bucket-owner for CopyObject and UploadPartCopy
Closes #1897

Extract the `X-Amz-Source-Expected-Bucket-Owner` header for CopyObject and UploadPartCopy. Verify the source bucket owner in the backend and if the provided access key id doesn't match, return an `AccessDenied` error.
2026-04-01 21:44:33 +04:00
Ben McClelland
89ab7a4f2b Merge pull request #1982 from versity/sis/POST-object
feat: add browser-based POST object upload support
2026-03-31 12:25:00 -07:00
niksis02
59002b2650 feat: implement integration tests for browser-based POST object 2026-03-31 22:47:04 +04:00
niksis02
285d130a47 feat: add browser-based POST object upload support
Closes #1648
Fixes #1980
Fixes #1981

This PR implements browser-based POST object uploads for S3-compatible form uploads. It adds support for handling `multipart/form-data` object uploads submitted from browsers, including streaming multipart parsing so file content is not buffered in memory, POST policy decoding and evaluation, SigV4-based form authorization, and integration with the existing `PutObject` backend flow. The implementation covers the full browser POST upload path, including validation of required form fields, credential scope and request date checks, signature verification, metadata extraction from `x-amz-meta-*` fields, checksum field parsing, object tagging conversion from XML into the query-string format expected by `PutObject`, and browser-compatible success handling through `success_action_status` and `success_action_redirect`. It also wires the new flow into the router and metrics layer and adds POST-specific error handling and debug logging across policy parsing, multipart parsing, and POST authorization. AWS S3 also accepts the `redirect` form field alongside `success_action_redirect`, but since AWS has marked `redirect` as deprecated and is planning to remove it, this gateway intentionally does not support it.
2026-03-31 22:44:54 +04:00
niksis02
3b17f05d17 feat: support response header overrides in HeadObject
Closes #1967

Add support for response header override query parameters(`response-cache-control`, `response-content-disposition`, `response-content-encoding`, `response-content-language`, `response-content-type`, `response-expires`) in `HeadObject`. Anonymous requests with override params are rejected with `ErrAnonymousResponseHeaders`.
2026-03-31 17:19:03 +04:00
Ben McClelland
2b12a5b81c Merge pull request #1989 from versity/test/rest_list_objects_encoding
test: REST ListObjects encoding
2026-03-30 14:43:12 -07:00
Luke McCrone
8feed3b333 test: ListObjects encoding-type tests 2026-03-30 10:24:03 -03:00
Ben McClelland
13b3dc5267 fix: serialize concurrent CompleteMultipartUpload calls via rename
When two requests raced to complete the same multipart upload, the first
caller to finish would remove the part files and upload directory. The
second caller, already past the initial existence check, would then fail
mid-flight with confusing errors such as ErrInvalidPart or an I/O error
when trying to open a part that no longer exists.

Fix this by atomically renaming the upload directory from <uploadID> to
<uploadID>.inprogress at the very start of CompleteMultipartUploadWithCopy,
before any part data is read. A concurrent caller will now find the
original directory absent and receive a clean NoSuchUpload error. A
deferred rename restores the original name if the complete does not
succeed, allowing the client to retry.

ListMultipartUploads is updated to skip any directories whose name ends
in .inprogress so in-flight completes do not appear as pending uploads.
2026-03-27 16:14:20 -07:00
Luke McCrone
ccd0ba2762 test: remove eval, go command generation overhaul 2026-03-27 15:00:56 -03:00
Luke McCrone
a96def085d test: test_common.sh updates, bucket/file creation updates, hardcode fixes 2026-03-20 14:09:00 -03:00
Luke McCrone
7975b9bbaa test: listobjects delimiter/prefix test, skips removal, go query improvement 2026-03-17 16:07:47 -03:00
Luke McCrone
7308c65591 test: ListBuckets - bucket region, more default param tests 2026-03-13 09:30:39 -03:00
Ben McClelland
97cc6bf23b chore: run go modernize tool
This is a fixup of the codebase using:
go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest -fix ./...

This has no bahvior changes, and only updates safe changes for
modern go features.
2026-03-10 09:47:37 -07:00
Ben McClelland
6c79f26625 Merge pull request #1931 from versity/sis/object-metadata-limits
fix: add request headers and metadata headers limit
2026-03-06 13:17:14 -08:00
niksis02
21a636b3b5 fix: add request headers and metadata headers limit
Fixes #1606

According to AWS documentation:
> *“The PUT request header is limited to 8 KB in size. 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.”*

Based on this, object metadata size is now limited to **2 KB** for all object upload operations (`PutObject`, `CopyObject`, and `CreateMultipartUpload`).

Fixes handling of metadata HTTP headers when the same header appears multiple times with different casing or even if they are identical. According to S3 behavior, these headers must be merged into a single lower-cased metadata key, with values concatenated using commas.

Example:

```
x-amz-meta-Key: value1
x-amz-meta-kEy: value2
x-amz-meta-keY: value3
```

Translated to:

```
key: value1,value2,value3
```

This PR also introduces an **8 KB limit for request headers**. Although the S3 documentation explicitly mentions the 8 KB limit only for **PUT requests**, in practice this limit applies to **all requests**.

To enforce the header size limit, the Fiber configuration option `ReadBufferSize` is used. This parameter defines the maximum number of bytes read when parsing an incoming request. Note that this limit does not apply strictly to request headers only, since request parsing also includes other parts of the request line (e.g., the HTTP method, protocol string, and version such as `HTTP/1.1`). So `ReadBufferSize` is effectively a limit for request headers size, but not the exact limit.
2026-03-06 23:25:49 +04:00
Ben McClelland
bcb7bc5f9a Merge pull request #1922 from versity/test/update_remove_some_utils
test: some util file updates, changes, removals
2026-03-05 17:07:25 -08:00
Ben McClelland
6281391bb9 Merge pull request #1920 from versity/sis/posix-object-metadata
fix: change the way object metadata is stored in posix
2026-03-05 17:07:05 -08:00
niksis02
97bb70509f fix: change the way object metadata is stored in posix
Fixes #1909

Previously, the mapping between object metadata and posix object was as follows: for each metadata key, we stored a separate xattr with the `user.X-Amz-Meta.<key>` prefix. This resulted in syscall overhead when storing and deleting large numbers of metadata keys.
In addition, very long metadata keys caused failures because most posix filesystems limit xattr key lengths to 127–255 bytes, while S3 does not enforce such a per-key limit.

The logic has now been changed so that all object metadata is stored in a single xattr, `user.metadata`, as a JSON key/value object. For backward compatibility, metadata GET operations still fall back to the old mechanism (`metadata key -> xattr key`) when `user.metadata` is not present.

A new CLI utility has been added to convert all legacy object metadata to the new metadata format within the provided directory.

**Example usage:**

```
versitygw utils convert-xattr-metadata path/to/bucket
```

or

```
versitygw utils cxm path/to/bucket
```

It is recommended to run this command on bucket directories to convert all legacy metadata for every object in the bucket.
2026-03-06 01:44:14 +04:00
Luke McCrone
038ae5e1ea test: update functions, transfer/remove some utils files 2026-03-04 14:15:00 -03:00
Luke McCrone
7b201777c3 test: CORS response header tests 2026-03-03 10:54:21 -03:00
Ben McClelland
8c648b5294 Merge pull request #1911 from versity/sis/revert-acl-headers-validation
feat: revert ignore object ACL behavior
2026-03-02 13:10:27 -08:00
niksis02
5c918f3682 feat: revert ignore object ACL behavior
The logic to return a `NotImplemented` error on object upload operations, when any ACL header is present has been removed. Now all object ACL headers are by default ignored. The `-noacl` flag is preserved to disabled bucket ACLs.

**Testing**
The Put/Get object ACL tests are moved to `NotImplemented` integration tests group as a default gateway behavior. The existing `_acl_not_supported` tests are modified to expect no error, when ACLs are used on object uploads.
2026-03-02 19:30:57 +04:00
niksis02
8550dba36f feat: add tagging support for directory objects in posix
Closes #1857

Adds object Tagging support for directory objects in `PutObject` posix. Updates the integration tests to test object metadata and tagging both for file and directory objects.
2026-03-02 18:56:50 +04:00
Ben McClelland
da82e5e247 fix: add missing tests to group-tests map
These tests were missing in the tests map to run the individual
tests:
ListBuckets_empty_success
CompleteMultipartUpload_incorrect_part_number
2026-02-28 16:39:43 -08:00
Ben McClelland
98acad9c99 Merge pull request #1887 from versity/sis/complete-mp-checksum
fix: store final checksum on CompleteMultipartUpload
2026-02-28 09:54:55 -08:00
Ben McClelland
0ad928a4d8 Merge pull request #1894 from versity/sis/getobject-directory-object-checksum
feat: adds checksums for directory objects in posix
2026-02-28 09:39:51 -08:00
Ben McClelland
1e5f803cab Merge pull request #1875 from versity/sis/disable-acl-option
feat: configuration option to disable ACLs
2026-02-28 09:32:23 -08:00
niksis02
5ae791b154 feat: configuration option to disable ACLs
Closes #1847

This PR introduces a global optional gateway CLI flag `--disable-acl` (`VGW_DISABLE_ACL`) to disable ACL handling. When this flag is enabled, the gateway ignores all ACL-related headers, particularly in `CreateBucket`, `PutObject`, `CopyObject`, and `CreateMultipartUpload`.

`GetBucketAcl` behavior is unchanged simply returning the bucket ACL config.
There's no change in object ACL actions(`PutObjectACL`, `GetObjectACL`). They return a`NotImplemented` error as before.

A new custom error is added for PutBucketAcl calls when ACLs are disabled at the gateway level. Its HTTP status code and error code match AWS S3’s behavior, with only a slightly different error message.

In the access-control checker, ACL evaluation is fully bypassed. If ACLs are disabled only the bucket owner gets access to the bucket and all grantee checks are ignored.

The PR also includes minor refactoring of the S3 API server and router. The growing list of parameters passed to the router’s Init method has been consolidated into fields within the router struct, initialized during router construction. Parameters not needed by the S3 server are no longer stored in the server configuration and are instead forwarded directly to the router.
2026-02-27 20:04:13 +04:00
niksis02
4ebe40829e fix: store final checksum on CompleteMultipartUpload
Previously, if no object checksum type/algorithm was specified when initiating a multipart upload, the CompleteMultipartUpload request would compute the final object’s CRC64NVME checksum but not persist it. This logic has now been fixed, and in the scenario described above the checksum is stored on the final object. There should no longer be any case where a CompleteMultipartUpload request finishes without persisting the final object checksum.
2026-02-27 15:12:57 +04:00
niksis02
24364754fd feat: adds checksums for directory objects in posix
Add data-integrity checksum support in `PutObject` in the POSIX backend for directory objects. Since the only way to upload a directory object is via `PutObject`, this logic validates and stores the checksum of the empty payload. Support for `GetObject` has also been added to retrieve and return directory-object checksums.
2026-02-26 22:36:56 +04:00
Luke McCrone
05ace90683 test: README, some test updates 2026-02-25 19:26:34 -03:00
Luke McCrone
2bd5ffe8bc test: remove obsolete recording code 2026-02-24 15:15:06 -03:00
niksis02
6fafc15d08 fix: fixes PutBucketCors CORSRules validation
Fixes #1870
Fixes #1863

A validation has been added to **PutBucketCors** for `CORSRule.AllowedOrigins`. The `AllowedOrigins` list can no longer be empty—otherwise a **MalformedXML** error is returned. Additionally, each origin is now validated to ensure it does not contain more than one wildcard.

A similar validation has been added for `AllowedMethods`. The list must not be empty, or a **MalformedXML** error is returned. Previously, empty method values (e.g., `[]string{""}`) were incorrectly treated as valid. This has been fixed, and an **UnsupportedCORSMethod** error is now returned.
2026-02-24 16:59:38 +04:00
Ben McClelland
ab80ac6e26 Merge pull request #1876 from versity/sis/create-bucket-response
feat: adds `Location`, `x-amz-bucket-arn` response headers in CreateBucket
2026-02-23 12:34:05 -08:00
niksis02
7fb3dedecc feat: adds Location, x-amz-bucket-arn response headers in CreateBucket
Closes #1873
2026-02-20 13:02:51 +04:00
Luke McCrone
5fc7357a03 test: REST CORS - initial tests 2026-02-19 20:19:05 -03:00
Ben McClelland
a81f9e5152 Merge pull request #1871 from versity/sis/create-bucket-private-canned-acl
fix: correct private canned ACL behavior on bucket creation
2026-02-18 09:55:36 -08:00
niksis02
f1577fd00b fix: correct private canned ACL behavior on bucket creation
Fixes #1869

Generally, when object ownership is not explicitly specified during bucket creation, it defaults to `BucketOwnerEnforced`. With `BucketOwnerEnforced`, ACLs are disabled and any attempt to set one results in an `InvalidBucketAclWithObjectOwnership` error.

However, there is an edge case. When the `private` canned ACL is used during bucket creation—which is effectively the default ACL for all buckets—`BucketOwnerEnforced` is still permitted. Moreover, if no explicit object ownership is specified together with the `private` canned ACL, the ownership defaults to `BucketOwnerPreferred`.

This fix also resolves the issue with rclone bucket creation, since rclone sends `x-amz-acl: private` by default:

```
rclone mkdir vgw:test
```
2026-02-18 20:32:05 +04:00
niksis02
46bcc8af35 fix: fixes object default Content-Type
Fixes #1849

If no `Content-Type` is provided during object upload, S3 defaults it to `application/octet-stream`. This behavior was missing in the gateway, causing backends to persist an empty `Content-Type`, which Fiber then overrides with its default `text/plain`. The behavior has now been corrected for the object upload operations: `PutObject`, `CreateMultipartUpload`, and `CopyObject`.
2026-02-18 01:44:52 +04:00
Luke McCrone
e810d4204d test: not-implemented type test, first template usage 2026-02-11 16:52:20 -03:00
Ben McClelland
3e26175265 feat: replace aws-sdk-go-v2 s3 manager with transfermanager
The latest version of the go sdk has deprecate the s3 manager in
favor of the new transfermanager. This updates to the new
transfermanager functionality for the two places we were using
the manager, iam s3 and integration tests.

This also removes the pinning of nats nkeys since they have fixed
the tags in their repo now. And general cleanup of the go.mod.
2026-02-11 09:58:15 -08:00