@@ -16,13 +16,15 @@ use crate::FreshnessEpoch;
1616use crate :: freshness_delivery:: {
1717 FreshnessReasonCode , FreshnessRetry , GenerationDelta , GenerationDeltaTerminalReceipt ,
1818 GenerationFileIdentity , MAX_DELIVERY_ID_BYTES , MAX_DELIVERY_TIMESTAMP_BYTES ,
19+ MAX_GENERATION_DELTA_METADATA_BYTES ,
1920} ;
2021
2122pub const GENERATION_TRANSPORT_FORMAT_VERSION : u16 = 1 ;
2223pub const GENERATION_TRANSPORT_READER_VERSION : u16 = 1 ;
2324pub const MAX_GENERATION_TRANSPORT_CAPABILITIES_BYTES : usize = 4 * 1024 ;
2425pub const MAX_GENERATION_TRANSPORT_REQUEST_BYTES : usize = 16 * 1024 ;
2526pub const MAX_GENERATION_DELIVERY_POLL_RESPONSE_BYTES : usize = 64 * 1024 * 1024 ;
27+ pub const GENERATION_DELIVERY_POLL_ENVELOPE_HEADROOM_BYTES : usize = 1024 * 1024 ;
2628pub const MAX_GENERATION_BODY_WINDOW_METADATA_BYTES : usize = 16 * 1024 ;
2729pub const MAX_GENERATION_BODY_WINDOW_BYTES : u64 = 4 * 1024 * 1024 ;
2830pub const GENERATION_DELIVERY_POLL_CONTENT_TYPE : & str = "application/json" ;
@@ -37,6 +39,24 @@ pub const MAX_OPAQUE_DEVICE_SCOPE_ID_BYTES: usize = 128;
3739pub const MAX_OPAQUE_PIN_LEASE_ID_BYTES : usize = 256 ;
3840pub const MAX_GENERATION_PIN_OPERATION_ID_BYTES : usize = 128 ;
3941
42+ const MAX_ESCAPED_DELIVERY_ID_BYTES : usize = 6 * MAX_DELIVERY_ID_BYTES ;
43+ const MAX_ESCAPED_DELIVERY_TIMESTAMP_BYTES : usize = 6 * MAX_DELIVERY_TIMESTAMP_BYTES ;
44+ // Deliberately overcounts V1's identifiers, timestamps, fixed JSON syntax, and
45+ // numeric/enum fields in addition to the independently bounded capabilities.
46+ const MAX_GENERATION_DELIVERY_POLL_ENVELOPE_REQUIRED_BYTES : usize =
47+ MAX_GENERATION_TRANSPORT_CAPABILITIES_BYTES
48+ + 16 * MAX_ESCAPED_DELIVERY_ID_BYTES
49+ + 4 * MAX_ESCAPED_DELIVERY_TIMESTAMP_BYTES
50+ + 64 * 1024 ;
51+ const _: ( ) = assert ! (
52+ MAX_GENERATION_DELTA_METADATA_BYTES + GENERATION_DELIVERY_POLL_ENVELOPE_HEADROOM_BYTES
53+ <= MAX_GENERATION_DELIVERY_POLL_RESPONSE_BYTES
54+ ) ;
55+ const _: ( ) = assert ! (
56+ MAX_GENERATION_DELIVERY_POLL_ENVELOPE_REQUIRED_BYTES
57+ <= GENERATION_DELIVERY_POLL_ENVELOPE_HEADROOM_BYTES
58+ ) ;
59+
4060pub const GENERATION_TRANSPORT_CAPABILITIES_V1_GOLDEN_JSON : & [ u8 ] =
4161 include_bytes ! ( "../fixtures/generation-transport-capabilities-v1.json" ) ;
4262pub const GENERATION_DELIVERY_REQUEST_V1_GOLDEN_JSON : & [ u8 ] =
@@ -367,9 +387,10 @@ impl GenerationDeliveryPollResponse {
367387 _ => return Err ( GenerationTransportContractError :: AmbiguousPollResponse ) ,
368388 }
369389
370- let encoded = serde_json:: to_vec ( self )
371- . expect ( "serializing a typed generation delivery poll response cannot fail" ) ;
372- validate_encoding_length_against ( encoded. len ( ) , MAX_GENERATION_DELIVERY_POLL_RESPONSE_BYTES )
390+ validate_encoding_length_against (
391+ serialized_json_len ( self ) ,
392+ MAX_GENERATION_DELIVERY_POLL_RESPONSE_BYTES ,
393+ )
373394 }
374395}
375396
@@ -1461,6 +1482,32 @@ fn validate_encoding_length_against(
14611482 }
14621483}
14631484
1485+ #[ derive( Default ) ]
1486+ struct JsonLengthWriter {
1487+ len : usize ,
1488+ }
1489+
1490+ impl std:: io:: Write for JsonLengthWriter {
1491+ fn write ( & mut self , bytes : & [ u8 ] ) -> std:: io:: Result < usize > {
1492+ self . len = self
1493+ . len
1494+ . checked_add ( bytes. len ( ) )
1495+ . ok_or_else ( || std:: io:: Error :: other ( "JSON length overflow" ) ) ?;
1496+ Ok ( bytes. len ( ) )
1497+ }
1498+
1499+ fn flush ( & mut self ) -> std:: io:: Result < ( ) > {
1500+ Ok ( ( ) )
1501+ }
1502+ }
1503+
1504+ fn serialized_json_len ( value : & impl Serialize ) -> usize {
1505+ let mut writer = JsonLengthWriter :: default ( ) ;
1506+ serde_json:: to_writer ( & mut writer, value)
1507+ . expect ( "serializing a typed generation transport value cannot fail" ) ;
1508+ writer. len
1509+ }
1510+
14641511fn validate_body_frame_length ( actual : usize ) -> Result < ( ) , GenerationTransportContractError > {
14651512 let maximum = GENERATION_BODY_WINDOW_METADATA_LENGTH_BYTES
14661513 + MAX_GENERATION_BODY_WINDOW_METADATA_BYTES
0 commit comments