ivandika3 commented on code in PR #9815:
URL: https://github.com/apache/ozone/pull/9815#discussion_r3019841629


##########
hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java:
##########
@@ -281,21 +299,24 @@ Response handlePutRequest(ObjectRequestContext context, 
String keyPath, InputStr
           getCustomMetadataFromHeaders(getHeaders().getRequestHeaders());
       Map<String, String> tags = getTaggingFromHeaders(getHeaders());
 
+      boolean hasConditionalHeaders = ifNoneMatch != null || ifMatch != null;
       long putLength;
       final String md5Hash;
-      if (isDatastreamEnabled() && !enableEC && length > 
getDatastreamMinLength()) {
+      if (isDatastreamEnabled() && !enableEC
+          && length > getDatastreamMinLength() && !hasConditionalHeaders) {
         perf.appendStreamMode();
         Pair<String, Long> keyWriteResult = ObjectEndpointStreaming
             .put(bucket, keyPath, length, replicationConfig, getChunkSize(),
-                customMetadata, tags, multiDigestInputStream, getHeaders(), 
signatureInfo.isSignPayload(), perf);
+                customMetadata, tags, multiDigestInputStream, getHeaders(),
+                signatureInfo.isSignPayload(), perf);

Review Comment:
   PutObject using streaming write should be able to handle conditional request 
since the OpenKey and CommitKey operations are the same as the non-streaming 
put.
   
   We can then remove the `hasConditionalHeaders` boolean.



##########
hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java:
##########
@@ -271,6 +280,15 @@ Response handlePutRequest(ObjectRequestContext context, 
String keyPath, InputStr
         return Response.ok().status(HttpStatus.SC_OK).build();
       }
 
+      String ifNoneMatch = getHeaders().getHeaderString(
+          S3Consts.IF_NONE_MATCH_HEADER);
+      String ifMatch = getHeaders().getHeaderString(
+          S3Consts.IF_MATCH_HEADER);
+
+      if (ifNoneMatch != null && ifMatch != null) {
+        throw newError(INVALID_REQUEST, keyPath);
+      }

Review Comment:
   Can put an error message here since the `INVALID_REQUEST` is used in a lot 
of places.
   
   Also we can do more validation
   - Fail for blank header
   - Fail if `If-None-Match` is not "*" 



##########
hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java:
##########
@@ -1127,7 +1148,48 @@ private CopyObjectResponse copyObject(OzoneVolume volume,
       }
     }
   }
-  
+
+  /**
+   * Opens a key for put, applying conditional write logic based on
+   * If-None-Match and If-Match headers.
+   */
+  @SuppressWarnings("checkstyle:ParameterNumber")
+  private OzoneOutputStream openKeyForPut(String volumeName, String bucketName,
+      OzoneBucket bucket, String keyPath, long length,
+      ReplicationConfig replicationConfig, Map<String, String> customMetadata,
+      Map<String, String> tags, String ifNoneMatch, String ifMatch)
+      throws IOException {
+    if (ifNoneMatch != null && "*".equals(ifNoneMatch.trim())) {
+      return getClientProtocol().createKeyIfNotExists(
+          volumeName, bucketName, keyPath, length, replicationConfig,
+          customMetadata, tags);
+    } else if (ifMatch != null) {
+      String expectedETag = parseETag(ifMatch);
+      return getClientProtocol().rewriteKeyIfMatch(
+          volumeName, bucketName, keyPath, length, expectedETag,
+          replicationConfig, customMetadata, tags);
+    } else {

Review Comment:
   This seems to be valid behavior based on the 
https://datatracker.ietf.org/doc/html/rfc7232#section-3.1. Should we implement 
this?



##########
hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java:
##########
@@ -1127,7 +1148,43 @@ private CopyObjectResponse copyObject(OzoneVolume volume,
       }
     }
   }
-  
+
+  /**
+   * Opens a key for put, applying conditional write logic based on
+   * If-None-Match and If-Match headers.
+   */
+  @SuppressWarnings("checkstyle:ParameterNumber")
+  private OzoneOutputStream openKeyForPut(String volumeName, String 
bucketName, String keyPath, long length,
+      ReplicationConfig replicationConfig, Map<String, String> customMetadata,
+      Map<String, String> tags, String ifNoneMatch, String ifMatch)
+      throws IOException {
+    if (ifNoneMatch != null && "*".equals(stripQuotes(ifNoneMatch.trim()))) {
+      return getClientProtocol().createKeyIfNotExists(
+          volumeName, bucketName, keyPath, length, replicationConfig,
+          customMetadata, tags);
+    } else if (ifMatch != null) {
+      String expectedETag = parseETag(ifMatch);
+      return getClientProtocol().rewriteKeyIfMatch(
+          volumeName, bucketName, keyPath, length, expectedETag,
+          replicationConfig, customMetadata, tags);
+    } else {
+      return getClientProtocol().createKey(
+          volumeName, bucketName, keyPath, length, replicationConfig,
+          customMetadata, tags);
+    }
+  }
+
+  /**
+   * Parses an ETag from a conditional header value, removing surrounding
+   * quotes if present.
+   */
+  static String parseETag(String headerValue) {
+    if (headerValue == null) {
+      return null;
+    }
+    return stripQuotes(headerValue.trim());
+  }

Review Comment:
   Can move this to `S3Utils`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to