Skip to content

Conversation

@cneira
Copy link

@cneira cneira commented Sep 11, 2025

Add an S3 compatibility layer to manta-buckets-api that maps S3 bucket and object requests to manta-buckets-api requests. This layer will perform the following:

  • Support S3 requests for buckets: HEAD, GET, PUT, DELETE

  • Support S3 request for objects: HEAD, GET, PUT, DELETE

  • Support S3 multipart uploads

  • Support third-party S3 clients (s3cmd)

  • Basic ACL (public/private)

  • Multipart uploads

Tests included in the ticket

Co-Authored-By: Claude [email protected]

@cneira cneira requested a review from danmcd October 28, 2025 20:46
Copy link
Contributor

@danmcd danmcd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checkpointing the incremental changes. Will need to set myself up for another full pass on the code files, probably the doc files too, and maybe the teset files.

lib/server.js Outdated

res.write(s3XmlError, 'utf8');
res.end();
next(false); // Stop route processing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This next(false); // Stop route processing and the one in the else case... can't they just be pulled out into one line after the if, and the else{} on 990-991 just goes away?

@cneira cneira requested a review from danmcd November 3, 2025 11:58
Copy link
Contributor

@danmcd danmcd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incremental check.

npm install -g json
```

#### SmartOS (pkgsrc)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pkgsrc also works for MacOS.

// Response headers
var sh = shark.headers;
var isAwsCli = req.headers['user-agent'] &&
req.headers['user-agent'].indexOf('aws-cli') !== -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-ping. I expect this to be, "actually more than there should be, but you know how lazy other implementers are, Dan." :)


// Get target sharks for final object placement
var targetSharks = getTargetSharks(req, uploadRecord, partPaths);
if (!targetSharks) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, sorry I missed this earlier.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the 'aws-cli' user-agent check, I removed those from common.js, as those were not needed as we are just processing header ranges, other clients as well could send/require those.

@cneira cneira requested a review from danmcd November 5, 2025 17:35
cneira and others added 7 commits November 8, 2025 03:19
  Implement complete Cross-Origin Resource Sharing functionality:
  - AWS S3 CORS API compatibility (PutBucketCors, GetBucketCors,
  DeleteBucketCors)
  - Object-level CORS via metadata headers with m-access-control-*
  prefix
  - CORS preflight OPTIONS request handling for browser compliance
  - Presigned URL CORS support for direct browser access
  - Comprehensive testing with HTML pages for real-world scenarios
  - Documentation with AWS S3 feature comparison matrix

  Technical implementation:
  - XML and JSON CORS configuration parsing with validation
  - Bucket-level CORS stored as .cors-configuration metadata objects
  - Refactor XML utilities to eliminate code duplication

  Generated with https://claude.ai/code

  Co-Authored-By: Claude mailto:[email protected]
Enhanced lib/auth.js to detect MPU operations via uploadId and partNumber
query parameters in convertS3PresignedToManta(). Added operation detection
for UploadPart requests and preserved MPU-specific parameters in S3 request
object for proper authentication pipeline integration.

Generated with https://claude.ai/code

Co-Authored-By: Claude <[email protected]>
Add CORS headers support for all MPU operations to enable browser-based
multipart uploads using AWS SDK for JavaScript.

- Add tryBucketLevelCors to MPU handlers (UploadPart, CompleteMultipartUpload, ListParts,
ListMultipartUploads)
- Add CORS support to ListBucketObjects handler
- Fix SigV4 signature verification for browser AWS SDK by detecting x-amz-user-agent header
- Update MPU handlers to load bucket object for CORS processing
- Update test CORS config to include required exposed headers

All MPU operations now apply bucket-level CORS configuration set via
put-bucket-cors, enabling browser compatibility while maintaining
existing authentication for non-browser clients.

Generated with https://claude.ai/code

Co-Authored-By: Claude <[email protected]>
Copy link
Contributor

@danmcd danmcd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incremental review, and not yet done becuase of large diffs or new files: s3-compat-awscli-test.sh, boto3-tests.py, cors-middleware.js, cors.js.

This is a big incremental, even not including the aforementioned not-yet-files. I'm going to assume CORS buys us a lot here, not just more green checkmarks? :)

| **GET BUCKET CORS** | ✅ Supported | ✅ Supported | **IMPLEMENTED** | Returns S3 compatible XML response |
| **DELETE BUCKET CORS** | ✅ Supported | ✅ Supported | **IMPLEMENTED** | Removes bucket-level CORS configuration |
| **CORS Preflight (OPTIONS)** | ✅ Supported | ✅ Supported | **IMPLEMENTED** | Full CORS specification compliance |
| **Object-level CORS** | ❌ Not Supported | ✅ Supported | **ENHANCED** | CORS via object metadata (m-access-control-*) |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, this is something we have above&beyond S3?

|---------|--------|------------------|----------------------|
| **Configuration Scope** | | | |
| Bucket-level CORS rules | ✅ Supported | ✅ Supported | Identical AWS S3 API compatibility |
| Object-level CORS rules | ❌ Not Available | ✅ Supported | **Manta Enhancement**: via `m-access-control-*` metadata |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here?

res.setHeader('ETag', '"' + finalETag + '"');
res.send(200);
next(false);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it just me or are all replies in s3UploadPartHandler() now going to perform CORS ? Or am I missing (maybe from new files or large-changes I've not yet read yet) something?

req.metadata = { headers: {} };
}

// Add CORS headers from bucket CORS configuration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question here.

res.send(xml);
next(false); // Stop processing

// Add CORS headers from bucket CORS configuration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here.


// CORS processing is handled in addCustomHeaders function in common.js
// for both object-level metadata and bucket-level CORS configuration

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may answer my confused-about-mandatory-CORS above.


// Log each metadata key individually to see exact names
mdKeys.forEach(function (k) {
if (k.toLowerCase().includes('control') || k.toLowerCase().
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of these checks will yield false-positives for CORS?

headerName = k.substring(2); // Remove 'm-' prefix
}

var isCorsHeader = CORS_RES_HDRS.indexOf(headerName) !== -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this why we always do cors processing elsewhere? We can catch/avoid it here if there are none?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants