1313# under the License.
1414
1515from dataclasses import dataclass
16- from datetime import datetime
1716from typing import Any , Callable , Final
18- from urllib .parse import quote , unquote
19-
20- from dateutil .parser import isoparse
2117
2218from cloudevents .core .base import BaseCloudEvent
19+ from cloudevents .core .bindings .common import (
20+ CONTENT_TYPE_HEADER ,
21+ DATACONTENTTYPE_ATTR ,
22+ decode_header_value ,
23+ encode_header_value ,
24+ )
2325from cloudevents .core .formats .base import Format
2426
2527CE_PREFIX : Final [str ] = "ce-"
26- CONTENT_TYPE_HEADER : Final [str ] = "content-type"
2728
2829
2930@dataclass (frozen = True )
@@ -44,44 +45,6 @@ class HTTPMessage:
4445 body : bytes
4546
4647
47- def _encode_header_value (value : Any ) -> str :
48- """
49- Encode a CloudEvent attribute value for use in an HTTP header.
50-
51- Handles special encoding for datetime objects (ISO 8601 with 'Z' suffix for UTC)
52- and applies percent-encoding for non-ASCII and special characters per RFC 3986.
53-
54- :param value: The attribute value to encode
55- :return: Percent-encoded string suitable for HTTP headers
56- """
57- if isinstance (value , datetime ):
58- str_value = value .isoformat ()
59- if str_value .endswith ("+00:00" ):
60- str_value = str_value [:- 6 ] + "Z"
61- return quote (str_value , safe = "" )
62-
63- return quote (str (value ), safe = "" )
64-
65-
66- def _decode_header_value (attr_name : str , value : str ) -> Any :
67- """
68- Decode a CloudEvent attribute value from an HTTP header.
69-
70- Applies percent-decoding and special parsing for the 'time' attribute
71- (converts to datetime object using RFC 3339 parsing).
72-
73- :param attr_name: The name of the CloudEvent attribute
74- :param value: The percent-encoded header value
75- :return: Decoded value (datetime for 'time' attribute, string otherwise)
76- """
77- decoded = unquote (value )
78-
79- if attr_name == "time" :
80- return isoparse (decoded )
81-
82- return decoded
83-
84-
8548def to_binary (event : BaseCloudEvent , event_format : Format ) -> HTTPMessage :
8649 """
8750 Convert a CloudEvent to HTTP binary content mode.
@@ -113,14 +76,14 @@ def to_binary(event: BaseCloudEvent, event_format: Format) -> HTTPMessage:
11376 if attr_value is None :
11477 continue
11578
116- if attr_name == "datacontenttype" :
79+ if attr_name == DATACONTENTTYPE_ATTR :
11780 headers [CONTENT_TYPE_HEADER ] = str (attr_value )
11881 else :
11982 header_name = f"{ CE_PREFIX } { attr_name } "
120- headers [header_name ] = _encode_header_value (attr_value )
83+ headers [header_name ] = encode_header_value (attr_value )
12184
12285 data = event .get_data ()
123- datacontenttype = attributes .get ("datacontenttype" )
86+ datacontenttype = attributes .get (DATACONTENTTYPE_ATTR )
12487 body = event_format .write_data (data , datacontenttype )
12588
12689 return HTTPMessage (headers = headers , body = body )
@@ -163,11 +126,11 @@ def from_binary(
163126
164127 if normalized_name .startswith (CE_PREFIX ):
165128 attr_name = normalized_name [len (CE_PREFIX ) :]
166- attributes [attr_name ] = _decode_header_value (attr_name , header_value )
129+ attributes [attr_name ] = decode_header_value (attr_name , header_value )
167130 elif normalized_name == CONTENT_TYPE_HEADER :
168- attributes ["datacontenttype" ] = header_value
131+ attributes [DATACONTENTTYPE_ATTR ] = header_value
169132
170- datacontenttype = attributes .get ("datacontenttype" )
133+ datacontenttype = attributes .get (DATACONTENTTYPE_ATTR )
171134 data = event_format .read_data (message .body , datacontenttype )
172135
173136 return event_factory (attributes , data )
0 commit comments