@@ -765,21 +765,18 @@ def _init_sigv4(self, session: Session) -> None:
765765 from requests .adapters import HTTPAdapter
766766
767767 class _IcebergSigV4Auth (SigV4Auth ):
768- def canonical_request (self , request : Any ) -> str :
769- # Reuses the logic from botocore's SigV4Auth.canonical_request
770- # (https://github.com/boto/botocore/blob/develop/botocore/auth.py)
771- # but always uses self.payload(request) for the body checksum.
772- # Validated against botocore <= 1.42.x
773- # (https://github.com/boto/botocore/blob/1.42.85/botocore/auth.py#L622-L637)
768+ def canonical_request (self , request : AWSRequest ) -> str :
769+ # Override forces hex payload hash in the canonical request even when
770+ # x-amz-content-sha256 header is base64 (see body-hash block below).
771+ # Mirrors botocore <=1.42.x SigV4Auth.canonical_request layout:
772+ # https://github.com/boto/botocore/blob/1.42.85/botocore/auth.py#L622-L637
774773 cr = [request .method .upper ()]
775774 path = self ._normalize_url_path (parse .urlsplit (request .url ).path )
776775 cr .append (path )
777776 cr .append (self .canonical_query_string (request ))
778777 headers_to_sign = self .headers_to_sign (request )
779778 cr .append (self .canonical_headers (headers_to_sign ) + "\n " )
780779 cr .append (self .signed_headers (headers_to_sign ))
781- # Always use hex-encoded payload hash per SigV4 spec,
782- # regardless of the x-amz-content-sha256 header value (which may be base64).
783780 cr .append (self .payload (request ))
784781 return "\n " .join (cr )
785782
@@ -810,11 +807,20 @@ def add_headers(self, request: PreparedRequest, **kwargs: Any) -> None: # pylin
810807 if "connection" in request .headers :
811808 del request .headers ["connection" ]
812809
813- # Compute the x-amz-content-sha256 header to match Iceberg Java SDK:
814- # - empty body → hex (EMPTY_BODY_SHA256)
815- # - non-empty body → base64
810+ # Match Iceberg Java's AWS SDK v2 flexible-checksum signing:
811+ # x-amz-content-sha256 header is base64 for non-empty bodies, hex for empty.
812+ # The SigV4 canonical request still uses hex (enforced in _IcebergSigV4Auth above).
813+ # Ref: https://github.com/apache/iceberg/blob/main/aws/src/main/java/org/apache/iceberg/aws/RESTSigV4AuthSession.java
816814 if request .body :
817- body_bytes = request .body .encode ("utf-8" ) if isinstance (request .body , str ) else request .body
815+ if isinstance (request .body , str ):
816+ body_bytes = request .body .encode ("utf-8" )
817+ elif isinstance (request .body , (bytes , bytearray )):
818+ body_bytes = request .body
819+ else :
820+ raise TypeError (
821+ f"Unsupported request body type for SigV4 signing: "
822+ f"{ type (request .body ).__name__ } ; expected str or bytes."
823+ )
818824 content_sha256_header = base64 .b64encode (hashlib .sha256 (body_bytes ).digest ()).decode ()
819825 else :
820826 content_sha256_header = EMPTY_BODY_SHA256
0 commit comments