@@ -773,21 +773,18 @@ def _init_sigv4(self, session: Session) -> None:
773773 from requests .adapters import HTTPAdapter
774774
775775 class _IcebergSigV4Auth (SigV4Auth ):
776- def canonical_request (self , request : Any ) -> str :
777- # Reuses the logic from botocore's SigV4Auth.canonical_request
778- # (https://github.com/boto/botocore/blob/develop/botocore/auth.py)
779- # but always uses self.payload(request) for the body checksum.
780- # Validated against botocore <= 1.42.x
781- # (https://github.com/boto/botocore/blob/1.42.85/botocore/auth.py#L622-L637)
776+ def canonical_request (self , request : AWSRequest ) -> str :
777+ # Override forces hex payload hash in the canonical request even when
778+ # x-amz-content-sha256 header is base64 (see body-hash block below).
779+ # Mirrors botocore <=1.42.x SigV4Auth.canonical_request layout:
780+ # https://github.com/boto/botocore/blob/1.42.85/botocore/auth.py#L622-L637
782781 cr = [request .method .upper ()]
783782 path = self ._normalize_url_path (parse .urlsplit (request .url ).path )
784783 cr .append (path )
785784 cr .append (self .canonical_query_string (request ))
786785 headers_to_sign = self .headers_to_sign (request )
787786 cr .append (self .canonical_headers (headers_to_sign ) + "\n " )
788787 cr .append (self .signed_headers (headers_to_sign ))
789- # Always use hex-encoded payload hash per SigV4 spec,
790- # regardless of the x-amz-content-sha256 header value (which may be base64).
791788 cr .append (self .payload (request ))
792789 return "\n " .join (cr )
793790
@@ -818,11 +815,20 @@ def add_headers(self, request: PreparedRequest, **kwargs: Any) -> None: # pylin
818815 if "connection" in request .headers :
819816 del request .headers ["connection" ]
820817
821- # Compute the x-amz-content-sha256 header to match Iceberg Java SDK:
822- # - empty body → hex (EMPTY_BODY_SHA256)
823- # - non-empty body → base64
818+ # Match Iceberg Java's AWS SDK v2 flexible-checksum signing:
819+ # x-amz-content-sha256 header is base64 for non-empty bodies, hex for empty.
820+ # The SigV4 canonical request still uses hex (enforced in _IcebergSigV4Auth above).
821+ # Ref: https://github.com/apache/iceberg/blob/main/aws/src/main/java/org/apache/iceberg/aws/RESTSigV4AuthSession.java
824822 if request .body :
825- body_bytes = request .body .encode ("utf-8" ) if isinstance (request .body , str ) else request .body
823+ if isinstance (request .body , str ):
824+ body_bytes = request .body .encode ("utf-8" )
825+ elif isinstance (request .body , (bytes , bytearray )):
826+ body_bytes = request .body
827+ else :
828+ raise TypeError (
829+ f"Unsupported request body type for SigV4 signing: "
830+ f"{ type (request .body ).__name__ } ; expected str or bytes."
831+ )
826832 content_sha256_header = base64 .b64encode (hashlib .sha256 (body_bytes ).digest ()).decode ()
827833 else :
828834 content_sha256_header = EMPTY_BODY_SHA256
0 commit comments