[ 
https://issues.apache.org/jira/browse/HDDS-17599?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Ritesh Shukla updated HDDS-17599:
---------------------------------
    Description: 
h3. Problem

An S3 {{DELETE}} on an object key means one of two things:
* {{DELETE /bucket/key?uploadId=<id>}} aborts a multipart upload 
(AbortMultipartUpload).
* {{DELETE /bucket/key}} deletes the object (DeleteObject).

When {{uploadId}} is present but empty, the S3 Gateway treats it as absent and 
deletes the committed object:

{code}
PUT    /bucket/key            -> 200, key created
DELETE /bucket/key?uploadId=  -> 204, key deleted
{code}

The request names an abort, so the client asked for no data to be removed, but 
the object is gone.

h3. Cause

{{MultipartKeyHandler#handleDeleteRequest}} returns {{null}} (not a multipart 
request, let the next handler run) when {{StringUtils.isEmpty(uploadId)}}. The 
chain then reaches {{ObjectEndpoint#handleDeleteRequest}}, which calls 
{{deleteKey}}.

The GET path in the same class already checks only for {{null}}, so {{GET 
/bucket/key?uploadId=}} is handled as ListParts rather than as a GetObject. The 
DELETE path is the inconsistent one. Ozone 2.0.0 had the same behaviour in the 
inline check in {{ObjectEndpoint#delete}}.

h3. Proposed fix

Treat only a missing {{uploadId}} as "not a multipart request". An empty 
{{uploadId}} names no upload, so fail with {{NoSuchUpload}}, recorded as a 
failed AbortMultipartUpload, and leave the key untouched.

h3. Testing

* Unit: {{TestObjectDelete}} puts a key, sends DELETE with an empty 
{{uploadId}}, and checks {{NoSuchUpload}} and that the key still exists. It 
fails before the fix, because the key is deleted.
* Integration: {{AbstractS3SDKV2Tests}} does the same through the AWS SDK v2 
client, which sends the empty upload ID as-is ({{DELETE ...?uploadId=}}). It 
fails before the fix (the abort returns success and the object is gone) and 
passes with it.

----
🤖 Generated with [Claude Code|https://claude.com/claude-code]


  was:
h3. Problem

An S3 {{DELETE}} on an object key means one of two things:
* {{DELETE /bucket/key?uploadId=<id>}} aborts a multipart upload 
(AbortMultipartUpload).
* {{DELETE /bucket/key}} deletes the object (DeleteObject).

When {{uploadId}} is present but empty, the S3 Gateway treats it as absent and 
deletes the committed object:

{code}
PUT    /bucket/key            -> 200, key created
DELETE /bucket/key?uploadId=  -> 204, key deleted
{code}

The request names an abort, so the client asked for no data to be removed, but 
the object is gone.

h3. Cause

{{MultipartKeyHandler#handleDeleteRequest}} returns {{null}} (not a multipart 
request, let the next handler run) when {{StringUtils.isEmpty(uploadId)}}. The 
chain then reaches {{ObjectEndpoint#handleDeleteRequest}}, which calls 
{{deleteKey}}.

The GET path in the same class already checks only for {{null}}, so {{GET 
/bucket/key?uploadId=}} is handled as ListParts rather than as a GetObject. The 
DELETE path is the inconsistent one. Ozone 2.0.0 had the same behaviour in the 
inline check in {{ObjectEndpoint#delete}}.

h3. Proposed fix

Treat only a missing {{uploadId}} as "not a multipart request". An empty 
{{uploadId}} names no upload, so fail with {{NoSuchUpload}}, recorded as a 
failed AbortMultipartUpload, and leave the key untouched.

h3. Testing

* Unit: {{TestObjectDelete}} puts a key, sends DELETE with an empty 
{{uploadId}}, and checks {{NoSuchUpload}} and that the key still exists. It 
fails before the fix, because the key is deleted.
* Acceptance: a new case in {{s3/objectdelete.robot}} does the same through a 
presigned AbortMultipartUpload URL ({{presigned_url_helper.py}} gains the 
helper; the AWS CLI rejects an empty upload ID). On the {{ozone}} compose 
cluster, it fails on master (the DELETE returns {{204 No Content}} and the 
object is gone) and passes with the fix.

----
🤖 Generated with [Claude Code|https://claude.com/claude-code]



> S3G: DELETE with an empty uploadId deletes the object instead of failing as 
> an abort
> ------------------------------------------------------------------------------------
>
>                 Key: HDDS-17599
>                 URL: https://issues.apache.org/jira/browse/HDDS-17599
>             Project: Apache Ozone
>          Issue Type: Bug
>          Components: S3
>            Reporter: Ritesh Shukla
>            Assignee: Ritesh Shukla
>            Priority: Major
>              Labels: pull-request-available
>
> h3. Problem
> An S3 {{DELETE}} on an object key means one of two things:
> * {{DELETE /bucket/key?uploadId=<id>}} aborts a multipart upload 
> (AbortMultipartUpload).
> * {{DELETE /bucket/key}} deletes the object (DeleteObject).
> When {{uploadId}} is present but empty, the S3 Gateway treats it as absent 
> and deletes the committed object:
> {code}
> PUT    /bucket/key            -> 200, key created
> DELETE /bucket/key?uploadId=  -> 204, key deleted
> {code}
> The request names an abort, so the client asked for no data to be removed, 
> but the object is gone.
> h3. Cause
> {{MultipartKeyHandler#handleDeleteRequest}} returns {{null}} (not a multipart 
> request, let the next handler run) when {{StringUtils.isEmpty(uploadId)}}. 
> The chain then reaches {{ObjectEndpoint#handleDeleteRequest}}, which calls 
> {{deleteKey}}.
> The GET path in the same class already checks only for {{null}}, so {{GET 
> /bucket/key?uploadId=}} is handled as ListParts rather than as a GetObject. 
> The DELETE path is the inconsistent one. Ozone 2.0.0 had the same behaviour 
> in the inline check in {{ObjectEndpoint#delete}}.
> h3. Proposed fix
> Treat only a missing {{uploadId}} as "not a multipart request". An empty 
> {{uploadId}} names no upload, so fail with {{NoSuchUpload}}, recorded as a 
> failed AbortMultipartUpload, and leave the key untouched.
> h3. Testing
> * Unit: {{TestObjectDelete}} puts a key, sends DELETE with an empty 
> {{uploadId}}, and checks {{NoSuchUpload}} and that the key still exists. It 
> fails before the fix, because the key is deleted.
> * Integration: {{AbstractS3SDKV2Tests}} does the same through the AWS SDK v2 
> client, which sends the empty upload ID as-is ({{DELETE ...?uploadId=}}). It 
> fails before the fix (the abort returns success and the object is gone) and 
> passes with it.
> ----
> 🤖 Generated with [Claude Code|https://claude.com/claude-code]



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to