From 849211381c9e388357644cea5647bd7954cbaa58 Mon Sep 17 00:00:00 2001 From: shirady <57721533+shirady@users.noreply.github.com> Date: Tue, 10 Sep 2024 07:54:22 +0300 Subject: [PATCH] NC | NSFS | Versioning | Fix Bug | Return 405 for get/head specific delete-marker 1. In namespace_fs add the case of specific version to the error that is thrown with additional information that we will use to set headers in the http response. To support it I added the params argument to the function _throw_if_delete_marker. 2. In s3_error add the mapping between the rpc that we used in namespace_fs and the S3 error that we want it to be mapped. 3. In s3_rest change the s3err.rpc_data to err.rpc_data since the object s3error does not have the rpc_data as a property inside it. Add the case to set http header for the delete-marker, reuse this change in a refactored function _prepare_error. Signed-off-by: shirady <57721533+shirady@users.noreply.github.com> --- src/endpoint/s3/s3_errors.js | 1 + src/endpoint/s3/s3_rest.js | 46 ++++++++----------- src/sdk/namespace_fs.js | 16 +++++-- .../unit_tests/test_bucketspace_versioning.js | 27 +++++++++++ 4 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/endpoint/s3/s3_errors.js b/src/endpoint/s3/s3_errors.js index 82446ab2fe..6a31359a98 100644 --- a/src/endpoint/s3/s3_errors.js +++ b/src/endpoint/s3/s3_errors.js @@ -609,6 +609,7 @@ S3Error.RPC_ERRORS_TO_S3 = Object.freeze({ NO_SUCH_TAG: S3Error.NoSuchTagSet, INVALID_ENCODING_TYPE: S3Error.InvalidEncodingType, INVALID_TARGET_BUCKET: S3Error.InvalidTargetBucketForLogging, + METHOD_NOT_ALLOWED: S3Error.MethodNotAllowed, }); exports.S3Error = S3Error; diff --git a/src/endpoint/s3/s3_rest.js b/src/endpoint/s3/s3_rest.js index e07d3fb50d..6189546aca 100755 --- a/src/endpoint/s3/s3_rest.js +++ b/src/endpoint/s3/s3_rest.js @@ -397,7 +397,7 @@ function parse_op_name(req) { return `${method}_object`; } -function handle_error(req, res, err) { +function _prepare_error(req, res, err) { let s3err = ((err instanceof S3Error) && err) || new S3Error(S3Error.RPC_ERRORS_TO_S3[err.rpc_code] || S3Error.InternalError); @@ -407,19 +407,26 @@ function handle_error(req, res, err) { s3err.detail = err.rpc_data.detail; } - if (s3err.rpc_data) { - if (s3err.rpc_data.etag) { + if (err.rpc_data) { + if (err.rpc_data.etag) { if (res.headersSent) { dbg.log0('Sent reply in body, bit too late for Etag header'); } else { - res.setHeader('ETag', s3err.rpc_data.etag); + res.setHeader('ETag', err.rpc_data.etag); } } - if (s3err.rpc_data.last_modified) { + if (err.rpc_data.last_modified) { if (res.headersSent) { dbg.log0('Sent reply in body, bit too late for Last-Modified header'); } else { - res.setHeader('Last-Modified', time_utils.format_http_header_date(new Date(s3err.rpc_data.last_modified))); + res.setHeader('Last-Modified', time_utils.format_http_header_date(new Date(err.rpc_data.last_modified))); + } + } + if (err.rpc_data.delete_marker) { + if (res.headersSent) { + dbg.log0('Sent reply in body, bit too late for x-amz-delete-marker header'); + } else { + res.setHeader('x-amz-delete-marker', String(err.rpc_data.delete_marker)); } } } @@ -432,6 +439,12 @@ function handle_error(req, res, err) { usage_report.s3_errors_info.total_errors += 1; usage_report.s3_errors_info[s3err.code] = (usage_report.s3_errors_info[s3err.code] || 0) + 1; + return s3err; +} + +function handle_error(req, res, err) { + const s3err = _prepare_error(req, res, err); + const reply = s3err.reply(req.originalUrl, req.request_id); dbg.error('S3 ERROR', reply, req.method, req.originalUrl, @@ -450,26 +463,7 @@ function handle_error(req, res, err) { } async function _handle_html_response(req, res, err) { - let s3err = - ((err instanceof S3Error) && err) || - new S3Error(S3Error.RPC_ERRORS_TO_S3[err.rpc_code] || S3Error.InternalError); - - if (s3err.rpc_data) { - if (s3err.rpc_data.etag) { - res.setHeader('ETag', s3err.rpc_data.etag); - } - if (s3err.rpc_data.last_modified) { - res.setHeader('Last-Modified', time_utils.format_http_header_date(new Date(s3err.rpc_data.last_modified))); - } - } - - // md_conditions used for PUT/POST/DELETE should return PreconditionFailed instead of NotModified - if (s3err.code === 'NotModified' && req.method !== 'HEAD' && req.method !== 'GET') { - s3err = new S3Error(S3Error.PreconditionFailed); - } - - usage_report.s3_errors_info.total_errors += 1; - usage_report.s3_errors_info[s3err.code] = (usage_report.s3_errors_info[s3err.code] || 0) + 1; + const s3err = _prepare_error(req, res, err); const reply = ` \