@@ -769,21 +769,18 @@ def _init_sigv4(self, session: Session) -> None:
769769 from requests .adapters import HTTPAdapter
770770
771771 class _IcebergSigV4Auth (SigV4Auth ):
772- def canonical_request (self , request : Any ) -> str :
773- # Reuses the logic from botocore's SigV4Auth.canonical_request
774- # (https://github.com/boto/botocore/blob/develop/botocore/auth.py)
775- # but always uses self.payload(request) for the body checksum.
776- # Validated against botocore <= 1.42.x
777- # (https://github.com/boto/botocore/blob/1.42.85/botocore/auth.py#L622-L637)
772+ def canonical_request (self , request : AWSRequest ) -> str :
773+ # Override forces hex payload hash in the canonical request even when
774+ # x-amz-content-sha256 header is base64 (see body-hash block below).
775+ # Mirrors botocore <=1.42.x SigV4Auth.canonical_request layout:
776+ # https://github.com/boto/botocore/blob/1.42.85/botocore/auth.py#L622-L637
778777 cr = [request .method .upper ()]
779778 path = self ._normalize_url_path (parse .urlsplit (request .url ).path )
780779 cr .append (path )
781780 cr .append (self .canonical_query_string (request ))
782781 headers_to_sign = self .headers_to_sign (request )
783782 cr .append (self .canonical_headers (headers_to_sign ) + "\n " )
784783 cr .append (self .signed_headers (headers_to_sign ))
785- # Always use hex-encoded payload hash per SigV4 spec,
786- # regardless of the x-amz-content-sha256 header value (which may be base64).
787784 cr .append (self .payload (request ))
788785 return "\n " .join (cr )
789786
@@ -814,11 +811,20 @@ def add_headers(self, request: PreparedRequest, **kwargs: Any) -> None: # pylin
814811 if "connection" in request .headers :
815812 del request .headers ["connection" ]
816813
817- # Compute the x-amz-content-sha256 header to match Iceberg Java SDK:
818- # - empty body → hex (EMPTY_BODY_SHA256)
819- # - non-empty body → base64
814+ # Match Iceberg Java's AWS SDK v2 flexible-checksum signing:
815+ # x-amz-content-sha256 header is base64 for non-empty bodies, hex for empty.
816+ # The SigV4 canonical request still uses hex (enforced in _IcebergSigV4Auth above).
817+ # Ref: https://github.com/apache/iceberg/blob/main/aws/src/main/java/org/apache/iceberg/aws/RESTSigV4AuthSession.java
820818 if request .body :
821- body_bytes = request .body .encode ("utf-8" ) if isinstance (request .body , str ) else request .body
819+ if isinstance (request .body , str ):
820+ body_bytes = request .body .encode ("utf-8" )
821+ elif isinstance (request .body , (bytes , bytearray )):
822+ body_bytes = request .body
823+ else :
824+ raise TypeError (
825+ f"Unsupported request body type for SigV4 signing: "
826+ f"{ type (request .body ).__name__ } ; expected str or bytes."
827+ )
822828 content_sha256_header = base64 .b64encode (hashlib .sha256 (body_bytes ).digest ()).decode ()
823829 else :
824830 content_sha256_header = EMPTY_BODY_SHA256
0 commit comments