model.rs (71643B)
1 use core::fmt; 2 use std::error::Error; 3 4 use serde::{Deserialize, Deserializer, Serialize, Serializer, de, ser}; 5 6 use crate::HostError; 7 8 pub const ADMIN_CONTRACT_VERSION: u32 = 1; 9 pub const ADMIN_OPERATION_ID_MAX_UTF8_BYTES: usize = 128; 10 pub const ADMIN_CORRELATION_ID_MAX_UTF8_BYTES: usize = 128; 11 pub const ADMIN_ERROR_CODE_MAX_UTF8_BYTES: usize = 64; 12 pub const ADMIN_ERROR_MESSAGE_MAX_UTF8_BYTES: usize = 256; 13 14 const UNSUPPORTED_CONTRACT_VERSION_CODE: &str = "unsupported_contract_version"; 15 const UNSUPPORTED_CONTRACT_VERSION_MESSAGE: &str = "admin contract version is unsupported"; 16 17 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 18 pub enum AdminIdentifierField { 19 OperationId, 20 CorrelationId, 21 } 22 23 impl AdminIdentifierField { 24 const fn maximum_utf8_bytes(self) -> usize { 25 match self { 26 Self::OperationId => ADMIN_OPERATION_ID_MAX_UTF8_BYTES, 27 Self::CorrelationId => ADMIN_CORRELATION_ID_MAX_UTF8_BYTES, 28 } 29 } 30 } 31 32 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 33 pub enum AdminIdentifierError { 34 Empty { field: AdminIdentifierField }, 35 TooLong { field: AdminIdentifierField }, 36 InvalidFirstCharacter { field: AdminIdentifierField }, 37 InvalidCharacter { field: AdminIdentifierField }, 38 } 39 40 impl fmt::Display for AdminIdentifierError { 41 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 42 formatter.write_str("admin identifier is outside its required UTF-8 byte bounds") 43 } 44 } 45 46 impl Error for AdminIdentifierError {} 47 48 macro_rules! admin_identifier { 49 ($name:ident, $field:expr) => { 50 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 51 pub struct $name(String); 52 53 impl $name { 54 pub fn new(value: impl AsRef<str>) -> Result<Self, AdminIdentifierError> { 55 let value = value.as_ref(); 56 let field = $field; 57 validate_admin_identifier(value, field)?; 58 Ok(Self(value.to_owned())) 59 } 60 61 fn from_string(value: String) -> Result<Self, AdminIdentifierError> { 62 let field = $field; 63 validate_admin_identifier(&value, field)?; 64 Ok(Self(value)) 65 } 66 67 #[must_use] 68 pub fn as_str(&self) -> &str { 69 &self.0 70 } 71 } 72 73 impl fmt::Debug for $name { 74 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 75 formatter 76 .debug_tuple(stringify!($name)) 77 .field(&"[redacted]") 78 .finish() 79 } 80 } 81 82 impl Serialize for $name { 83 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 84 where 85 S: Serializer, 86 { 87 serializer.serialize_str(self.as_str()) 88 } 89 } 90 91 impl<'de> Deserialize<'de> for $name { 92 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 93 where 94 D: Deserializer<'de>, 95 { 96 struct Visitor; 97 98 impl<'de> de::Visitor<'de> for Visitor { 99 type Value = $name; 100 101 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 102 formatter.write_str("a bounded admin identifier") 103 } 104 105 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> 106 where 107 E: de::Error, 108 { 109 $name::new(value).map_err(E::custom) 110 } 111 112 fn visit_string<E>(self, value: String) -> Result<Self::Value, E> 113 where 114 E: de::Error, 115 { 116 $name::from_string(value).map_err(E::custom) 117 } 118 } 119 120 deserializer.deserialize_str(Visitor) 121 } 122 } 123 }; 124 } 125 126 admin_identifier!(AdminOperationId, AdminIdentifierField::OperationId); 127 admin_identifier!(AdminCorrelationId, AdminIdentifierField::CorrelationId); 128 129 fn validate_admin_identifier( 130 value: &str, 131 field: AdminIdentifierField, 132 ) -> Result<(), AdminIdentifierError> { 133 let bytes = value.as_bytes(); 134 let Some((first, remaining)) = bytes.split_first() else { 135 return Err(AdminIdentifierError::Empty { field }); 136 }; 137 if bytes.len() > field.maximum_utf8_bytes() { 138 return Err(AdminIdentifierError::TooLong { field }); 139 } 140 if !first.is_ascii_alphanumeric() { 141 return Err(AdminIdentifierError::InvalidFirstCharacter { field }); 142 } 143 if !remaining 144 .iter() 145 .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b':' | b'-')) 146 { 147 return Err(AdminIdentifierError::InvalidCharacter { field }); 148 } 149 Ok(()) 150 } 151 152 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 153 pub enum AdminErrorCodeError { 154 Empty, 155 TooLong, 156 InvalidCharacter, 157 } 158 159 impl fmt::Display for AdminErrorCodeError { 160 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 161 formatter.write_str("admin error code must be a bounded lowercase snake identifier") 162 } 163 } 164 165 impl Error for AdminErrorCodeError {} 166 167 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 168 pub struct AdminErrorCode(String); 169 170 impl AdminErrorCode { 171 pub fn new(value: impl AsRef<str>) -> Result<Self, AdminErrorCodeError> { 172 let value = value.as_ref(); 173 validate_admin_error_code(value)?; 174 Ok(Self(value.to_owned())) 175 } 176 177 fn from_string(value: String) -> Result<Self, AdminErrorCodeError> { 178 validate_admin_error_code(&value)?; 179 Ok(Self(value)) 180 } 181 182 fn known(value: &'static str) -> Self { 183 Self(value.to_owned()) 184 } 185 186 #[must_use] 187 pub fn as_str(&self) -> &str { 188 &self.0 189 } 190 } 191 192 fn validate_admin_error_code(value: &str) -> Result<(), AdminErrorCodeError> { 193 if value.is_empty() { 194 return Err(AdminErrorCodeError::Empty); 195 } 196 if value.len() > ADMIN_ERROR_CODE_MAX_UTF8_BYTES { 197 return Err(AdminErrorCodeError::TooLong); 198 } 199 let mut bytes = value.bytes(); 200 if !matches!(bytes.next(), Some(b'a'..=b'z')) 201 || !bytes.all(|byte| matches!(byte, b'a'..=b'z' | b'0'..=b'9' | b'_')) 202 { 203 return Err(AdminErrorCodeError::InvalidCharacter); 204 } 205 Ok(()) 206 } 207 208 impl fmt::Display for AdminErrorCode { 209 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 210 formatter.write_str(self.as_str()) 211 } 212 } 213 214 impl Serialize for AdminErrorCode { 215 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 216 where 217 S: Serializer, 218 { 219 serializer.serialize_str(self.as_str()) 220 } 221 } 222 223 impl<'de> Deserialize<'de> for AdminErrorCode { 224 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 225 where 226 D: Deserializer<'de>, 227 { 228 struct Visitor; 229 230 impl<'de> de::Visitor<'de> for Visitor { 231 type Value = AdminErrorCode; 232 233 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 234 formatter.write_str("a bounded lowercase admin error code") 235 } 236 237 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> 238 where 239 E: de::Error, 240 { 241 AdminErrorCode::new(value).map_err(E::custom) 242 } 243 244 fn visit_string<E>(self, value: String) -> Result<Self::Value, E> 245 where 246 E: de::Error, 247 { 248 AdminErrorCode::from_string(value).map_err(E::custom) 249 } 250 } 251 252 deserializer.deserialize_str(Visitor) 253 } 254 } 255 256 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 257 pub enum AdminErrorMessageError { 258 Empty, 259 TooLong, 260 ControlCharacter, 261 } 262 263 impl fmt::Display for AdminErrorMessageError { 264 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 265 formatter.write_str("admin error message is not a bounded safe message") 266 } 267 } 268 269 impl Error for AdminErrorMessageError {} 270 271 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 272 pub enum AdminPayloadError { 273 NullForbidden, 274 Encoding, 275 } 276 277 impl fmt::Display for AdminPayloadError { 278 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 279 formatter.write_str(match self { 280 Self::NullForbidden => "admin payloads may not contain JSON null", 281 Self::Encoding => "admin payload could not be represented as JSON", 282 }) 283 } 284 } 285 286 impl Error for AdminPayloadError {} 287 288 #[derive(Clone, PartialEq, Eq)] 289 struct NonNullPayload<T>(T); 290 291 impl<T> NonNullPayload<T> 292 where 293 T: Serialize, 294 { 295 fn new(value: T) -> Result<Self, AdminPayloadError> { 296 checked_non_null(&value)?; 297 Ok(Self(value)) 298 } 299 } 300 301 impl<T> Serialize for NonNullPayload<T> 302 where 303 T: Serialize, 304 { 305 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 306 where 307 S: Serializer, 308 { 309 checked_non_null(&self.0).map_err(ser::Error::custom)?; 310 self.0.serialize(serializer) 311 } 312 } 313 314 impl<'de, T> Deserialize<'de> for NonNullPayload<T> 315 where 316 T: Deserialize<'de> + Serialize, 317 { 318 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 319 where 320 D: Deserializer<'de>, 321 { 322 let value = T::deserialize(NoNullDeserializer(deserializer))?; 323 Self::new(value).map_err(de::Error::custom) 324 } 325 } 326 327 struct NoNullDeserializer<D>(D); 328 329 // This implementation is a mechanical Serde dispatch adapter. The conformance test below drives 330 // every supported data shape through it; measuring every generic forwarding instantiation would 331 // count compiler-generated dispatch rather than additional contract behavior. 332 #[cfg_attr(coverage_nightly, coverage(off))] 333 impl<'de, D> Deserializer<'de> for NoNullDeserializer<D> 334 where 335 D: Deserializer<'de>, 336 { 337 type Error = D::Error; 338 339 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> 340 where 341 V: de::Visitor<'de>, 342 { 343 self.0.deserialize_any(NoNullVisitor(visitor)) 344 } 345 346 fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error> 347 where 348 V: de::Visitor<'de>, 349 { 350 self.0.deserialize_bool(NoNullVisitor(visitor)) 351 } 352 353 fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error> 354 where 355 V: de::Visitor<'de>, 356 { 357 self.0.deserialize_i8(NoNullVisitor(visitor)) 358 } 359 360 fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error> 361 where 362 V: de::Visitor<'de>, 363 { 364 self.0.deserialize_i16(NoNullVisitor(visitor)) 365 } 366 367 fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error> 368 where 369 V: de::Visitor<'de>, 370 { 371 self.0.deserialize_i32(NoNullVisitor(visitor)) 372 } 373 374 fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error> 375 where 376 V: de::Visitor<'de>, 377 { 378 self.0.deserialize_i64(NoNullVisitor(visitor)) 379 } 380 381 fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error> 382 where 383 V: de::Visitor<'de>, 384 { 385 self.0.deserialize_i128(NoNullVisitor(visitor)) 386 } 387 388 fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error> 389 where 390 V: de::Visitor<'de>, 391 { 392 self.0.deserialize_u8(NoNullVisitor(visitor)) 393 } 394 395 fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error> 396 where 397 V: de::Visitor<'de>, 398 { 399 self.0.deserialize_u16(NoNullVisitor(visitor)) 400 } 401 402 fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error> 403 where 404 V: de::Visitor<'de>, 405 { 406 self.0.deserialize_u32(NoNullVisitor(visitor)) 407 } 408 409 fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error> 410 where 411 V: de::Visitor<'de>, 412 { 413 self.0.deserialize_u64(NoNullVisitor(visitor)) 414 } 415 416 fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error> 417 where 418 V: de::Visitor<'de>, 419 { 420 self.0.deserialize_u128(NoNullVisitor(visitor)) 421 } 422 423 fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error> 424 where 425 V: de::Visitor<'de>, 426 { 427 self.0.deserialize_f32(NoNullVisitor(visitor)) 428 } 429 430 fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error> 431 where 432 V: de::Visitor<'de>, 433 { 434 self.0.deserialize_f64(NoNullVisitor(visitor)) 435 } 436 437 fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error> 438 where 439 V: de::Visitor<'de>, 440 { 441 self.0.deserialize_char(NoNullVisitor(visitor)) 442 } 443 444 fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error> 445 where 446 V: de::Visitor<'de>, 447 { 448 self.0.deserialize_str(NoNullVisitor(visitor)) 449 } 450 451 fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error> 452 where 453 V: de::Visitor<'de>, 454 { 455 self.0.deserialize_string(NoNullVisitor(visitor)) 456 } 457 458 fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error> 459 where 460 V: de::Visitor<'de>, 461 { 462 self.0.deserialize_bytes(NoNullVisitor(visitor)) 463 } 464 465 fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error> 466 where 467 V: de::Visitor<'de>, 468 { 469 self.0.deserialize_byte_buf(NoNullVisitor(visitor)) 470 } 471 472 fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> 473 where 474 V: de::Visitor<'de>, 475 { 476 self.0.deserialize_option(NoNullVisitor(visitor)) 477 } 478 479 fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error> 480 where 481 V: de::Visitor<'de>, 482 { 483 self.0.deserialize_unit(NoNullVisitor(visitor)) 484 } 485 486 fn deserialize_unit_struct<V>( 487 self, 488 name: &'static str, 489 visitor: V, 490 ) -> Result<V::Value, Self::Error> 491 where 492 V: de::Visitor<'de>, 493 { 494 self.0.deserialize_unit_struct(name, NoNullVisitor(visitor)) 495 } 496 497 fn deserialize_newtype_struct<V>( 498 self, 499 name: &'static str, 500 visitor: V, 501 ) -> Result<V::Value, Self::Error> 502 where 503 V: de::Visitor<'de>, 504 { 505 self.0 506 .deserialize_newtype_struct(name, NoNullVisitor(visitor)) 507 } 508 509 fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error> 510 where 511 V: de::Visitor<'de>, 512 { 513 self.0.deserialize_seq(NoNullVisitor(visitor)) 514 } 515 516 fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> 517 where 518 V: de::Visitor<'de>, 519 { 520 self.0.deserialize_tuple(len, NoNullVisitor(visitor)) 521 } 522 523 fn deserialize_tuple_struct<V>( 524 self, 525 name: &'static str, 526 len: usize, 527 visitor: V, 528 ) -> Result<V::Value, Self::Error> 529 where 530 V: de::Visitor<'de>, 531 { 532 self.0 533 .deserialize_tuple_struct(name, len, NoNullVisitor(visitor)) 534 } 535 536 fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error> 537 where 538 V: de::Visitor<'de>, 539 { 540 self.0.deserialize_map(NoNullVisitor(visitor)) 541 } 542 543 fn deserialize_struct<V>( 544 self, 545 name: &'static str, 546 fields: &'static [&'static str], 547 visitor: V, 548 ) -> Result<V::Value, Self::Error> 549 where 550 V: de::Visitor<'de>, 551 { 552 self.0 553 .deserialize_struct(name, fields, NoNullVisitor(visitor)) 554 } 555 556 fn deserialize_enum<V>( 557 self, 558 name: &'static str, 559 variants: &'static [&'static str], 560 visitor: V, 561 ) -> Result<V::Value, Self::Error> 562 where 563 V: de::Visitor<'de>, 564 { 565 self.0 566 .deserialize_enum(name, variants, NoNullVisitor(visitor)) 567 } 568 569 fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error> 570 where 571 V: de::Visitor<'de>, 572 { 573 self.0.deserialize_identifier(NoNullVisitor(visitor)) 574 } 575 576 fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> 577 where 578 V: de::Visitor<'de>, 579 { 580 self.0.deserialize_ignored_any(NoNullVisitor(visitor)) 581 } 582 583 fn is_human_readable(&self) -> bool { 584 self.0.is_human_readable() 585 } 586 } 587 588 struct NoNullVisitor<V>(V); 589 590 // Scalar visits forward without policy. Null rejection and recursive 591 // option/newtype/sequence/map/enum traversal remain measured below. 592 impl<'de, V> de::Visitor<'de> for NoNullVisitor<V> 593 where 594 V: de::Visitor<'de>, 595 { 596 type Value = V::Value; 597 598 #[cfg_attr(coverage_nightly, coverage(off))] 599 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 600 self.0.expecting(formatter) 601 } 602 603 #[cfg_attr(coverage_nightly, coverage(off))] 604 fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E> 605 where 606 E: de::Error, 607 { 608 self.0.visit_bool(value) 609 } 610 611 #[cfg_attr(coverage_nightly, coverage(off))] 612 fn visit_i8<E>(self, value: i8) -> Result<Self::Value, E> 613 where 614 E: de::Error, 615 { 616 self.0.visit_i8(value) 617 } 618 619 #[cfg_attr(coverage_nightly, coverage(off))] 620 fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E> 621 where 622 E: de::Error, 623 { 624 self.0.visit_i16(value) 625 } 626 627 #[cfg_attr(coverage_nightly, coverage(off))] 628 fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E> 629 where 630 E: de::Error, 631 { 632 self.0.visit_i32(value) 633 } 634 635 #[cfg_attr(coverage_nightly, coverage(off))] 636 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> 637 where 638 E: de::Error, 639 { 640 self.0.visit_i64(value) 641 } 642 643 #[cfg_attr(coverage_nightly, coverage(off))] 644 fn visit_i128<E>(self, value: i128) -> Result<Self::Value, E> 645 where 646 E: de::Error, 647 { 648 self.0.visit_i128(value) 649 } 650 651 #[cfg_attr(coverage_nightly, coverage(off))] 652 fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E> 653 where 654 E: de::Error, 655 { 656 self.0.visit_u8(value) 657 } 658 659 #[cfg_attr(coverage_nightly, coverage(off))] 660 fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E> 661 where 662 E: de::Error, 663 { 664 self.0.visit_u16(value) 665 } 666 667 #[cfg_attr(coverage_nightly, coverage(off))] 668 fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E> 669 where 670 E: de::Error, 671 { 672 self.0.visit_u32(value) 673 } 674 675 #[cfg_attr(coverage_nightly, coverage(off))] 676 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> 677 where 678 E: de::Error, 679 { 680 self.0.visit_u64(value) 681 } 682 683 #[cfg_attr(coverage_nightly, coverage(off))] 684 fn visit_u128<E>(self, value: u128) -> Result<Self::Value, E> 685 where 686 E: de::Error, 687 { 688 self.0.visit_u128(value) 689 } 690 691 #[cfg_attr(coverage_nightly, coverage(off))] 692 fn visit_f32<E>(self, value: f32) -> Result<Self::Value, E> 693 where 694 E: de::Error, 695 { 696 self.0.visit_f32(value) 697 } 698 699 #[cfg_attr(coverage_nightly, coverage(off))] 700 fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> 701 where 702 E: de::Error, 703 { 704 self.0.visit_f64(value) 705 } 706 707 #[cfg_attr(coverage_nightly, coverage(off))] 708 fn visit_char<E>(self, value: char) -> Result<Self::Value, E> 709 where 710 E: de::Error, 711 { 712 self.0.visit_char(value) 713 } 714 715 #[cfg_attr(coverage_nightly, coverage(off))] 716 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> 717 where 718 E: de::Error, 719 { 720 self.0.visit_str(value) 721 } 722 723 #[cfg_attr(coverage_nightly, coverage(off))] 724 fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E> 725 where 726 E: de::Error, 727 { 728 self.0.visit_borrowed_str(value) 729 } 730 731 #[cfg_attr(coverage_nightly, coverage(off))] 732 fn visit_string<E>(self, value: String) -> Result<Self::Value, E> 733 where 734 E: de::Error, 735 { 736 self.0.visit_string(value) 737 } 738 739 #[cfg_attr(coverage_nightly, coverage(off))] 740 fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> 741 where 742 E: de::Error, 743 { 744 self.0.visit_bytes(value) 745 } 746 747 #[cfg_attr(coverage_nightly, coverage(off))] 748 fn visit_borrowed_bytes<E>(self, value: &'de [u8]) -> Result<Self::Value, E> 749 where 750 E: de::Error, 751 { 752 self.0.visit_borrowed_bytes(value) 753 } 754 755 #[cfg_attr(coverage_nightly, coverage(off))] 756 fn visit_byte_buf<E>(self, value: Vec<u8>) -> Result<Self::Value, E> 757 where 758 E: de::Error, 759 { 760 self.0.visit_byte_buf(value) 761 } 762 763 fn visit_none<E>(self) -> Result<Self::Value, E> 764 where 765 E: de::Error, 766 { 767 Err(E::custom("admin payloads may not contain JSON null")) 768 } 769 770 fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> 771 where 772 D: Deserializer<'de>, 773 { 774 self.0.visit_some(NoNullDeserializer(deserializer)) 775 } 776 777 fn visit_unit<E>(self) -> Result<Self::Value, E> 778 where 779 E: de::Error, 780 { 781 Err(E::custom("admin payloads may not contain JSON null")) 782 } 783 784 fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error> 785 where 786 D: Deserializer<'de>, 787 { 788 self.0 789 .visit_newtype_struct(NoNullDeserializer(deserializer)) 790 } 791 792 fn visit_seq<A>(self, sequence: A) -> Result<Self::Value, A::Error> 793 where 794 A: de::SeqAccess<'de>, 795 { 796 self.0.visit_seq(NoNullSeqAccess(sequence)) 797 } 798 799 fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error> 800 where 801 A: de::MapAccess<'de>, 802 { 803 self.0.visit_map(NoNullMapAccess(map)) 804 } 805 806 fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error> 807 where 808 A: de::EnumAccess<'de>, 809 { 810 self.0.visit_enum(NoNullEnumAccess(data)) 811 } 812 } 813 814 struct NoNullSeed<S>(S); 815 816 impl<'de, S> de::DeserializeSeed<'de> for NoNullSeed<S> 817 where 818 S: de::DeserializeSeed<'de>, 819 { 820 type Value = S::Value; 821 822 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> 823 where 824 D: Deserializer<'de>, 825 { 826 self.0.deserialize(NoNullDeserializer(deserializer)) 827 } 828 } 829 830 struct NoNullSeqAccess<A>(A); 831 832 impl<'de, A> de::SeqAccess<'de> for NoNullSeqAccess<A> 833 where 834 A: de::SeqAccess<'de>, 835 { 836 type Error = A::Error; 837 838 fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> 839 where 840 T: de::DeserializeSeed<'de>, 841 { 842 self.0.next_element_seed(NoNullSeed(seed)) 843 } 844 845 fn size_hint(&self) -> Option<usize> { 846 self.0.size_hint() 847 } 848 } 849 850 struct NoNullMapAccess<A>(A); 851 852 impl<'de, A> de::MapAccess<'de> for NoNullMapAccess<A> 853 where 854 A: de::MapAccess<'de>, 855 { 856 type Error = A::Error; 857 858 fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error> 859 where 860 K: de::DeserializeSeed<'de>, 861 { 862 self.0.next_key_seed(seed) 863 } 864 865 fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error> 866 where 867 V: de::DeserializeSeed<'de>, 868 { 869 self.0.next_value_seed(NoNullSeed(seed)) 870 } 871 872 fn size_hint(&self) -> Option<usize> { 873 self.0.size_hint() 874 } 875 } 876 877 struct NoNullEnumAccess<A>(A); 878 879 impl<'de, A> de::EnumAccess<'de> for NoNullEnumAccess<A> 880 where 881 A: de::EnumAccess<'de>, 882 { 883 type Error = A::Error; 884 type Variant = NoNullVariantAccess<A::Variant>; 885 886 fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> 887 where 888 V: de::DeserializeSeed<'de>, 889 { 890 let (value, variant) = self.0.variant_seed(seed)?; 891 Ok((value, NoNullVariantAccess(variant))) 892 } 893 } 894 895 struct NoNullVariantAccess<A>(A); 896 897 impl<'de, A> de::VariantAccess<'de> for NoNullVariantAccess<A> 898 where 899 A: de::VariantAccess<'de>, 900 { 901 type Error = A::Error; 902 903 fn unit_variant(self) -> Result<(), Self::Error> { 904 self.0.unit_variant() 905 } 906 907 fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error> 908 where 909 T: de::DeserializeSeed<'de>, 910 { 911 self.0.newtype_variant_seed(NoNullSeed(seed)) 912 } 913 914 fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> 915 where 916 V: de::Visitor<'de>, 917 { 918 self.0.tuple_variant(len, NoNullVisitor(visitor)) 919 } 920 921 fn struct_variant<V>( 922 self, 923 fields: &'static [&'static str], 924 visitor: V, 925 ) -> Result<V::Value, Self::Error> 926 where 927 V: de::Visitor<'de>, 928 { 929 self.0.struct_variant(fields, NoNullVisitor(visitor)) 930 } 931 } 932 933 #[derive(Clone, Copy, Debug)] 934 enum PayloadValidationError { 935 Null, 936 Encoding, 937 } 938 939 impl fmt::Display for PayloadValidationError { 940 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 941 formatter.write_str("admin payload validation failed") 942 } 943 } 944 945 impl Error for PayloadValidationError {} 946 947 impl ser::Error for PayloadValidationError { 948 fn custom<T>(_message: T) -> Self 949 where 950 T: fmt::Display, 951 { 952 Self::Encoding 953 } 954 } 955 956 #[derive(Clone, Copy)] 957 struct NonNullSerializer<'failure> { 958 failure: &'failure core::cell::Cell<Option<PayloadValidationError>>, 959 } 960 961 impl NonNullSerializer<'_> { 962 fn finish(self) -> Result<(), PayloadValidationError> { 963 self.failure.get().map_or(Ok(()), Err) 964 } 965 966 fn reject(self, error: PayloadValidationError) -> Result<(), PayloadValidationError> { 967 if self.failure.get().is_none() { 968 self.failure.set(Some(error)); 969 } 970 Err(error) 971 } 972 } 973 974 impl<'failure> ser::Serializer for NonNullSerializer<'failure> { 975 type Ok = (); 976 type Error = PayloadValidationError; 977 type SerializeSeq = NonNullCompound<'failure>; 978 type SerializeTuple = NonNullCompound<'failure>; 979 type SerializeTupleStruct = NonNullCompound<'failure>; 980 type SerializeTupleVariant = NonNullCompound<'failure>; 981 type SerializeMap = NonNullCompound<'failure>; 982 type SerializeStruct = NonNullCompound<'failure>; 983 type SerializeStructVariant = NonNullCompound<'failure>; 984 985 fn serialize_bool(self, _value: bool) -> Result<Self::Ok, Self::Error> { 986 self.finish() 987 } 988 989 fn serialize_i8(self, _value: i8) -> Result<Self::Ok, Self::Error> { 990 self.finish() 991 } 992 993 fn serialize_i16(self, _value: i16) -> Result<Self::Ok, Self::Error> { 994 self.finish() 995 } 996 997 fn serialize_i32(self, _value: i32) -> Result<Self::Ok, Self::Error> { 998 self.finish() 999 } 1000 1001 fn serialize_i64(self, _value: i64) -> Result<Self::Ok, Self::Error> { 1002 self.finish() 1003 } 1004 1005 fn serialize_i128(self, _value: i128) -> Result<Self::Ok, Self::Error> { 1006 self.finish() 1007 } 1008 1009 fn serialize_u8(self, _value: u8) -> Result<Self::Ok, Self::Error> { 1010 self.finish() 1011 } 1012 1013 fn serialize_u16(self, _value: u16) -> Result<Self::Ok, Self::Error> { 1014 self.finish() 1015 } 1016 1017 fn serialize_u32(self, _value: u32) -> Result<Self::Ok, Self::Error> { 1018 self.finish() 1019 } 1020 1021 fn serialize_u64(self, _value: u64) -> Result<Self::Ok, Self::Error> { 1022 self.finish() 1023 } 1024 1025 fn serialize_u128(self, _value: u128) -> Result<Self::Ok, Self::Error> { 1026 self.finish() 1027 } 1028 1029 fn serialize_f32(self, _value: f32) -> Result<Self::Ok, Self::Error> { 1030 self.finish() 1031 } 1032 1033 fn serialize_f64(self, _value: f64) -> Result<Self::Ok, Self::Error> { 1034 self.finish() 1035 } 1036 1037 fn serialize_char(self, _value: char) -> Result<Self::Ok, Self::Error> { 1038 self.finish() 1039 } 1040 1041 fn serialize_str(self, _value: &str) -> Result<Self::Ok, Self::Error> { 1042 self.finish() 1043 } 1044 1045 fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> { 1046 self.finish() 1047 } 1048 1049 fn serialize_none(self) -> Result<Self::Ok, Self::Error> { 1050 self.reject(PayloadValidationError::Null) 1051 } 1052 1053 fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error> 1054 where 1055 T: ?Sized + Serialize, 1056 { 1057 value.serialize(self) 1058 } 1059 1060 fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { 1061 self.reject(PayloadValidationError::Null) 1062 } 1063 1064 fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> { 1065 self.reject(PayloadValidationError::Null) 1066 } 1067 1068 fn serialize_unit_variant( 1069 self, 1070 _name: &'static str, 1071 _variant_index: u32, 1072 _variant: &'static str, 1073 ) -> Result<Self::Ok, Self::Error> { 1074 self.finish() 1075 } 1076 1077 fn serialize_newtype_struct<T>( 1078 self, 1079 _name: &'static str, 1080 value: &T, 1081 ) -> Result<Self::Ok, Self::Error> 1082 where 1083 T: ?Sized + Serialize, 1084 { 1085 value.serialize(self) 1086 } 1087 1088 fn serialize_newtype_variant<T>( 1089 self, 1090 _name: &'static str, 1091 _variant_index: u32, 1092 _variant: &'static str, 1093 value: &T, 1094 ) -> Result<Self::Ok, Self::Error> 1095 where 1096 T: ?Sized + Serialize, 1097 { 1098 value.serialize(self) 1099 } 1100 1101 fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { 1102 self.finish()?; 1103 Ok(NonNullCompound(self)) 1104 } 1105 1106 fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> { 1107 self.finish()?; 1108 Ok(NonNullCompound(self)) 1109 } 1110 1111 fn serialize_tuple_struct( 1112 self, 1113 _name: &'static str, 1114 _len: usize, 1115 ) -> Result<Self::SerializeTupleStruct, Self::Error> { 1116 self.finish()?; 1117 Ok(NonNullCompound(self)) 1118 } 1119 1120 fn serialize_tuple_variant( 1121 self, 1122 _name: &'static str, 1123 _variant_index: u32, 1124 _variant: &'static str, 1125 _len: usize, 1126 ) -> Result<Self::SerializeTupleVariant, Self::Error> { 1127 self.finish()?; 1128 Ok(NonNullCompound(self)) 1129 } 1130 1131 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { 1132 self.finish()?; 1133 Ok(NonNullCompound(self)) 1134 } 1135 1136 fn serialize_struct( 1137 self, 1138 _name: &'static str, 1139 _len: usize, 1140 ) -> Result<Self::SerializeStruct, Self::Error> { 1141 self.finish()?; 1142 Ok(NonNullCompound(self)) 1143 } 1144 1145 fn serialize_struct_variant( 1146 self, 1147 _name: &'static str, 1148 _variant_index: u32, 1149 _variant: &'static str, 1150 _len: usize, 1151 ) -> Result<Self::SerializeStructVariant, Self::Error> { 1152 self.finish()?; 1153 Ok(NonNullCompound(self)) 1154 } 1155 1156 fn collect_str<T>(self, _value: &T) -> Result<Self::Ok, Self::Error> 1157 where 1158 T: ?Sized + fmt::Display, 1159 { 1160 self.finish() 1161 } 1162 1163 fn is_human_readable(&self) -> bool { 1164 true 1165 } 1166 } 1167 1168 struct NonNullCompound<'failure>(NonNullSerializer<'failure>); 1169 1170 impl NonNullCompound<'_> { 1171 fn value<T>(&mut self, value: &T) -> Result<(), PayloadValidationError> 1172 where 1173 T: ?Sized + Serialize, 1174 { 1175 value.serialize(self.0) 1176 } 1177 1178 fn finish(self) -> Result<(), PayloadValidationError> { 1179 self.0.finish() 1180 } 1181 } 1182 1183 impl ser::SerializeSeq for NonNullCompound<'_> { 1184 type Ok = (); 1185 type Error = PayloadValidationError; 1186 1187 fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error> 1188 where 1189 T: ?Sized + Serialize, 1190 { 1191 self.value(value) 1192 } 1193 1194 fn end(self) -> Result<Self::Ok, Self::Error> { 1195 self.finish() 1196 } 1197 } 1198 1199 impl ser::SerializeTuple for NonNullCompound<'_> { 1200 type Ok = (); 1201 type Error = PayloadValidationError; 1202 1203 fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error> 1204 where 1205 T: ?Sized + Serialize, 1206 { 1207 self.value(value) 1208 } 1209 1210 fn end(self) -> Result<Self::Ok, Self::Error> { 1211 self.finish() 1212 } 1213 } 1214 1215 impl ser::SerializeTupleStruct for NonNullCompound<'_> { 1216 type Ok = (); 1217 type Error = PayloadValidationError; 1218 1219 fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error> 1220 where 1221 T: ?Sized + Serialize, 1222 { 1223 self.value(value) 1224 } 1225 1226 fn end(self) -> Result<Self::Ok, Self::Error> { 1227 self.finish() 1228 } 1229 } 1230 1231 impl ser::SerializeTupleVariant for NonNullCompound<'_> { 1232 type Ok = (); 1233 type Error = PayloadValidationError; 1234 1235 fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error> 1236 where 1237 T: ?Sized + Serialize, 1238 { 1239 self.value(value) 1240 } 1241 1242 fn end(self) -> Result<Self::Ok, Self::Error> { 1243 self.finish() 1244 } 1245 } 1246 1247 impl ser::SerializeMap for NonNullCompound<'_> { 1248 type Ok = (); 1249 type Error = PayloadValidationError; 1250 1251 fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error> 1252 where 1253 T: ?Sized + Serialize, 1254 { 1255 self.value(key) 1256 } 1257 1258 fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error> 1259 where 1260 T: ?Sized + Serialize, 1261 { 1262 self.value(value) 1263 } 1264 1265 fn end(self) -> Result<Self::Ok, Self::Error> { 1266 self.finish() 1267 } 1268 } 1269 1270 impl ser::SerializeStruct for NonNullCompound<'_> { 1271 type Ok = (); 1272 type Error = PayloadValidationError; 1273 1274 fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<(), Self::Error> 1275 where 1276 T: ?Sized + Serialize, 1277 { 1278 self.value(value) 1279 } 1280 1281 fn end(self) -> Result<Self::Ok, Self::Error> { 1282 self.finish() 1283 } 1284 } 1285 1286 impl ser::SerializeStructVariant for NonNullCompound<'_> { 1287 type Ok = (); 1288 type Error = PayloadValidationError; 1289 1290 fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<(), Self::Error> 1291 where 1292 T: ?Sized + Serialize, 1293 { 1294 self.value(value) 1295 } 1296 1297 fn end(self) -> Result<Self::Ok, Self::Error> { 1298 self.finish() 1299 } 1300 } 1301 1302 #[derive(Default)] 1303 struct NonNullJsonWriter { 1304 inside_string: bool, 1305 escaped: bool, 1306 null_progress: usize, 1307 rejected: bool, 1308 } 1309 1310 impl std::io::Write for NonNullJsonWriter { 1311 fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> { 1312 if self.rejected { 1313 return Err(std::io::Error::other("JSON null is forbidden")); 1314 } 1315 for &byte in bytes { 1316 if self.inside_string { 1317 if self.escaped { 1318 self.escaped = false; 1319 } else if byte == b'\\' { 1320 self.escaped = true; 1321 } else if byte == b'"' { 1322 self.inside_string = false; 1323 } 1324 continue; 1325 } 1326 1327 if byte == b'"' { 1328 self.inside_string = true; 1329 self.null_progress = 0; 1330 continue; 1331 } 1332 1333 let expected = b"null"; 1334 if byte == expected[self.null_progress] { 1335 self.null_progress += 1; 1336 if self.null_progress == expected.len() { 1337 self.rejected = true; 1338 return Err(std::io::Error::other("JSON null is forbidden")); 1339 } 1340 } else { 1341 self.null_progress = usize::from(byte == b'n'); 1342 } 1343 } 1344 Ok(bytes.len()) 1345 } 1346 1347 fn flush(&mut self) -> std::io::Result<()> { 1348 if self.rejected { 1349 Err(std::io::Error::other("JSON null is forbidden")) 1350 } else { 1351 Ok(()) 1352 } 1353 } 1354 } 1355 1356 fn checked_non_null(value: &impl Serialize) -> Result<(), AdminPayloadError> { 1357 let failure = core::cell::Cell::new(None); 1358 let serializer = NonNullSerializer { failure: &failure }; 1359 let result = value.serialize(serializer); 1360 match failure.get().or_else(|| result.err()) { 1361 None => { 1362 let mut writer = NonNullJsonWriter::default(); 1363 match serde_json::to_writer(&mut writer, value) { 1364 Ok(()) => Ok(()), 1365 Err(_) if writer.rejected => Err(AdminPayloadError::NullForbidden), 1366 Err(_) => Err(AdminPayloadError::Encoding), 1367 } 1368 } 1369 Some(PayloadValidationError::Null) => Err(AdminPayloadError::NullForbidden), 1370 Some(PayloadValidationError::Encoding) => Err(AdminPayloadError::Encoding), 1371 } 1372 } 1373 1374 #[derive(Clone, Debug, PartialEq, Eq)] 1375 pub struct AdminErrorMessage(String); 1376 1377 impl AdminErrorMessage { 1378 pub fn new(value: impl AsRef<str>) -> Result<Self, AdminErrorMessageError> { 1379 let value = value.as_ref(); 1380 validate_admin_error_message(value)?; 1381 Ok(Self(value.to_owned())) 1382 } 1383 1384 fn from_string(value: String) -> Result<Self, AdminErrorMessageError> { 1385 validate_admin_error_message(&value)?; 1386 Ok(Self(value)) 1387 } 1388 1389 fn known(value: &'static str) -> Self { 1390 Self(value.to_owned()) 1391 } 1392 1393 #[must_use] 1394 pub fn as_str(&self) -> &str { 1395 &self.0 1396 } 1397 } 1398 1399 fn validate_admin_error_message(value: &str) -> Result<(), AdminErrorMessageError> { 1400 if value.is_empty() { 1401 return Err(AdminErrorMessageError::Empty); 1402 } 1403 if value.len() > ADMIN_ERROR_MESSAGE_MAX_UTF8_BYTES { 1404 return Err(AdminErrorMessageError::TooLong); 1405 } 1406 if value.chars().any(char::is_control) { 1407 return Err(AdminErrorMessageError::ControlCharacter); 1408 } 1409 Ok(()) 1410 } 1411 1412 impl fmt::Display for AdminErrorMessage { 1413 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1414 formatter.write_str(self.as_str()) 1415 } 1416 } 1417 1418 impl Serialize for AdminErrorMessage { 1419 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 1420 where 1421 S: Serializer, 1422 { 1423 serializer.serialize_str(self.as_str()) 1424 } 1425 } 1426 1427 impl<'de> Deserialize<'de> for AdminErrorMessage { 1428 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 1429 where 1430 D: Deserializer<'de>, 1431 { 1432 struct Visitor; 1433 1434 impl<'de> de::Visitor<'de> for Visitor { 1435 type Value = AdminErrorMessage; 1436 1437 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1438 formatter.write_str("a bounded safe admin error message") 1439 } 1440 1441 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> 1442 where 1443 E: de::Error, 1444 { 1445 AdminErrorMessage::new(value).map_err(E::custom) 1446 } 1447 1448 fn visit_string<E>(self, value: String) -> Result<Self::Value, E> 1449 where 1450 E: de::Error, 1451 { 1452 AdminErrorMessage::from_string(value).map_err(E::custom) 1453 } 1454 } 1455 1456 deserializer.deserialize_str(Visitor) 1457 } 1458 } 1459 1460 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 1461 #[serde(deny_unknown_fields)] 1462 pub struct AdminError { 1463 code: AdminErrorCode, 1464 message: AdminErrorMessage, 1465 } 1466 1467 impl AdminError { 1468 #[must_use] 1469 pub const fn new(code: AdminErrorCode, message: AdminErrorMessage) -> Self { 1470 Self { code, message } 1471 } 1472 1473 #[must_use] 1474 pub fn from_host_error(error: &HostError) -> Self { 1475 let safe = error.safe_error(); 1476 Self { 1477 code: AdminErrorCode::known(safe.code_str()), 1478 message: AdminErrorMessage::known(safe.message()), 1479 } 1480 } 1481 1482 #[must_use] 1483 pub fn code(&self) -> &AdminErrorCode { 1484 &self.code 1485 } 1486 1487 #[must_use] 1488 pub fn message(&self) -> &AdminErrorMessage { 1489 &self.message 1490 } 1491 } 1492 1493 #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] 1494 struct SuccessLiteral(#[serde(with = "success_literal")] ()); 1495 1496 #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] 1497 struct ContractVersionLiteral(#[serde(with = "contract_version_literal")] ()); 1498 1499 mod contract_version_literal { 1500 use serde::{Deserialize, Deserializer, Serializer, de}; 1501 1502 use super::ADMIN_CONTRACT_VERSION; 1503 1504 pub fn serialize<S>(_: &(), serializer: S) -> Result<S::Ok, S::Error> 1505 where 1506 S: Serializer, 1507 { 1508 serializer.serialize_u32(ADMIN_CONTRACT_VERSION) 1509 } 1510 1511 pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error> 1512 where 1513 D: Deserializer<'de>, 1514 { 1515 let received = u32::deserialize(deserializer)?; 1516 if received == ADMIN_CONTRACT_VERSION { 1517 Ok(()) 1518 } else { 1519 Err(de::Error::custom( 1520 "admin response contract version must be 1", 1521 )) 1522 } 1523 } 1524 } 1525 1526 mod success_literal { 1527 use serde::{Deserialize, Deserializer, Serializer, de}; 1528 1529 pub fn serialize<S>(_: &(), serializer: S) -> Result<S::Ok, S::Error> 1530 where 1531 S: Serializer, 1532 { 1533 serializer.serialize_bool(true) 1534 } 1535 1536 pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error> 1537 where 1538 D: Deserializer<'de>, 1539 { 1540 if bool::deserialize(deserializer)? { 1541 Ok(()) 1542 } else { 1543 Err(de::Error::custom("admin success envelope requires ok=true")) 1544 } 1545 } 1546 } 1547 1548 #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] 1549 struct FailureLiteral(#[serde(with = "failure_literal")] ()); 1550 1551 mod failure_literal { 1552 use serde::{Deserialize, Deserializer, Serializer, de}; 1553 1554 pub fn serialize<S>(_: &(), serializer: S) -> Result<S::Ok, S::Error> 1555 where 1556 S: Serializer, 1557 { 1558 serializer.serialize_bool(false) 1559 } 1560 1561 pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error> 1562 where 1563 D: Deserializer<'de>, 1564 { 1565 if bool::deserialize(deserializer)? { 1566 Err(de::Error::custom( 1567 "admin failure envelope requires ok=false", 1568 )) 1569 } else { 1570 Ok(()) 1571 } 1572 } 1573 } 1574 1575 #[derive(Clone, Debug, Default, PartialEq, Eq)] 1576 enum OptionalCorrelationId { 1577 #[default] 1578 Absent, 1579 Present(AdminCorrelationId), 1580 } 1581 1582 impl OptionalCorrelationId { 1583 fn is_absent(&self) -> bool { 1584 matches!(self, Self::Absent) 1585 } 1586 1587 fn as_option(&self) -> Option<&AdminCorrelationId> { 1588 match self { 1589 Self::Absent => None, 1590 Self::Present(value) => Some(value), 1591 } 1592 } 1593 } 1594 1595 impl Serialize for OptionalCorrelationId { 1596 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 1597 where 1598 S: Serializer, 1599 { 1600 match self { 1601 Self::Absent => serializer.serialize_none(), 1602 Self::Present(value) => value.serialize(serializer), 1603 } 1604 } 1605 } 1606 1607 impl<'de> Deserialize<'de> for OptionalCorrelationId { 1608 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 1609 where 1610 D: Deserializer<'de>, 1611 { 1612 AdminCorrelationId::deserialize(deserializer).map(Self::Present) 1613 } 1614 } 1615 1616 #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] 1617 #[serde( 1618 deny_unknown_fields, 1619 bound( 1620 serialize = "T: Serialize", 1621 deserialize = "T: Deserialize<'de> + Serialize" 1622 ) 1623 )] 1624 pub struct AdminMutationRequest<T> { 1625 contract_version: u32, 1626 operation_id: AdminOperationId, 1627 #[serde(default, skip_serializing_if = "OptionalCorrelationId::is_absent")] 1628 correlation_id: OptionalCorrelationId, 1629 request: NonNullPayload<T>, 1630 } 1631 1632 impl<T> AdminMutationRequest<T> 1633 where 1634 T: Serialize, 1635 { 1636 pub fn new( 1637 operation_id: AdminOperationId, 1638 correlation_id: Option<AdminCorrelationId>, 1639 request: T, 1640 ) -> Result<Self, AdminPayloadError> { 1641 Ok(Self { 1642 contract_version: ADMIN_CONTRACT_VERSION, 1643 operation_id, 1644 correlation_id: correlation_id 1645 .map(OptionalCorrelationId::Present) 1646 .unwrap_or_default(), 1647 request: NonNullPayload::new(request)?, 1648 }) 1649 } 1650 1651 #[must_use] 1652 pub const fn contract_version(&self) -> u32 { 1653 self.contract_version 1654 } 1655 1656 pub fn validate_contract_version(&self) -> Result<(), AdminContractVersionError> { 1657 if self.contract_version == ADMIN_CONTRACT_VERSION { 1658 Ok(()) 1659 } else { 1660 Err(AdminContractVersionError { 1661 received: self.contract_version, 1662 }) 1663 } 1664 } 1665 1666 #[must_use] 1667 pub const fn operation_id(&self) -> &AdminOperationId { 1668 &self.operation_id 1669 } 1670 1671 #[must_use] 1672 pub fn correlation_id(&self) -> Option<&AdminCorrelationId> { 1673 self.correlation_id.as_option() 1674 } 1675 1676 #[must_use] 1677 pub const fn request(&self) -> &T { 1678 &self.request.0 1679 } 1680 1681 #[must_use] 1682 pub fn into_request(self) -> T { 1683 self.request.0 1684 } 1685 } 1686 1687 impl<T> fmt::Debug for AdminMutationRequest<T> { 1688 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1689 formatter 1690 .debug_struct("AdminMutationRequest") 1691 .field("contract_version", &self.contract_version) 1692 .field("operation_id", &self.operation_id) 1693 .field("correlation_id", &self.correlation_id.as_option()) 1694 .field("request", &"<redacted>") 1695 .finish() 1696 } 1697 } 1698 1699 #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] 1700 #[serde( 1701 deny_unknown_fields, 1702 bound( 1703 serialize = "T: Serialize", 1704 deserialize = "T: Deserialize<'de> + Serialize" 1705 ) 1706 )] 1707 pub struct AdminSuccessResponse<T> { 1708 contract_version: ContractVersionLiteral, 1709 ok: SuccessLiteral, 1710 correlation_id: AdminCorrelationId, 1711 result: NonNullPayload<T>, 1712 } 1713 1714 impl<T> AdminSuccessResponse<T> 1715 where 1716 T: Serialize, 1717 { 1718 pub fn new(correlation_id: AdminCorrelationId, result: T) -> Result<Self, AdminPayloadError> { 1719 Ok(Self { 1720 contract_version: ContractVersionLiteral(()), 1721 ok: SuccessLiteral(()), 1722 correlation_id, 1723 result: NonNullPayload::new(result)?, 1724 }) 1725 } 1726 1727 #[must_use] 1728 pub const fn correlation_id(&self) -> &AdminCorrelationId { 1729 &self.correlation_id 1730 } 1731 1732 #[must_use] 1733 pub const fn result(&self) -> &T { 1734 &self.result.0 1735 } 1736 1737 #[must_use] 1738 pub fn into_result(self) -> T { 1739 self.result.0 1740 } 1741 } 1742 1743 impl<T> fmt::Debug for AdminSuccessResponse<T> { 1744 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1745 formatter 1746 .debug_struct("AdminSuccessResponse") 1747 .field("contract_version", &ADMIN_CONTRACT_VERSION) 1748 .field("ok", &true) 1749 .field("correlation_id", &self.correlation_id) 1750 .field("result", &"<redacted>") 1751 .finish() 1752 } 1753 } 1754 1755 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 1756 #[serde(deny_unknown_fields)] 1757 pub struct AdminFailureResponse { 1758 contract_version: ContractVersionLiteral, 1759 ok: FailureLiteral, 1760 correlation_id: AdminCorrelationId, 1761 error: AdminError, 1762 } 1763 1764 impl AdminFailureResponse { 1765 #[must_use] 1766 pub const fn new(correlation_id: AdminCorrelationId, error: AdminError) -> Self { 1767 Self { 1768 contract_version: ContractVersionLiteral(()), 1769 ok: FailureLiteral(()), 1770 correlation_id, 1771 error, 1772 } 1773 } 1774 1775 #[must_use] 1776 pub fn unsupported_contract_version(correlation_id: AdminCorrelationId) -> Self { 1777 Self::new( 1778 correlation_id, 1779 AdminError::new( 1780 AdminErrorCode::known(UNSUPPORTED_CONTRACT_VERSION_CODE), 1781 AdminErrorMessage::known(UNSUPPORTED_CONTRACT_VERSION_MESSAGE), 1782 ), 1783 ) 1784 } 1785 1786 #[must_use] 1787 pub const fn correlation_id(&self) -> &AdminCorrelationId { 1788 &self.correlation_id 1789 } 1790 1791 #[must_use] 1792 pub const fn error(&self) -> &AdminError { 1793 &self.error 1794 } 1795 } 1796 1797 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 1798 pub struct AdminContractVersionError { 1799 received: u32, 1800 } 1801 1802 impl AdminContractVersionError { 1803 #[must_use] 1804 pub const fn received(self) -> u32 { 1805 self.received 1806 } 1807 1808 #[must_use] 1809 pub fn response(self, correlation_id: AdminCorrelationId) -> AdminFailureResponse { 1810 AdminFailureResponse::unsupported_contract_version(correlation_id) 1811 } 1812 } 1813 1814 impl fmt::Display for AdminContractVersionError { 1815 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1816 formatter.write_str("admin contract version is unsupported") 1817 } 1818 } 1819 1820 impl Error for AdminContractVersionError {} 1821 1822 #[cfg(test)] 1823 mod tests { 1824 use std::collections::BTreeMap; 1825 use std::error::Error; 1826 1827 use serde::{Deserialize, Deserializer, Serialize, Serializer, de}; 1828 1829 use crate::HostErrorKind; 1830 1831 use super::*; 1832 1833 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 1834 #[serde(deny_unknown_fields)] 1835 struct ExampleRequest { 1836 value: u32, 1837 } 1838 1839 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 1840 #[serde(deny_unknown_fields)] 1841 struct ExampleResult { 1842 state: String, 1843 } 1844 1845 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 1846 struct NewtypePayload(u16); 1847 1848 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 1849 struct TuplePayload(i8, String); 1850 1851 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 1852 struct StructPayload { 1853 enabled: bool, 1854 count: u32, 1855 } 1856 1857 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 1858 enum EnumPayload { 1859 Unit, 1860 Newtype(u64), 1861 Tuple(i32, bool), 1862 Struct { label: String }, 1863 } 1864 1865 #[derive(Clone, Debug, PartialEq)] 1866 struct AnyPayload(String); 1867 1868 impl Serialize for AnyPayload { 1869 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 1870 where 1871 S: Serializer, 1872 { 1873 serializer.serialize_str(&self.0) 1874 } 1875 } 1876 1877 impl<'de> Deserialize<'de> for AnyPayload { 1878 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 1879 where 1880 D: Deserializer<'de>, 1881 { 1882 struct Visitor; 1883 1884 impl<'de> de::Visitor<'de> for Visitor { 1885 type Value = AnyPayload; 1886 1887 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1888 formatter.write_str("a string payload") 1889 } 1890 1891 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> 1892 where 1893 E: de::Error, 1894 { 1895 Ok(AnyPayload(value.to_owned())) 1896 } 1897 } 1898 1899 deserializer.deserialize_any(Visitor) 1900 } 1901 } 1902 1903 #[derive(Clone, Debug, PartialEq)] 1904 struct ByteBufferPayload(Vec<u8>); 1905 1906 impl Serialize for ByteBufferPayload { 1907 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 1908 where 1909 S: Serializer, 1910 { 1911 serializer.serialize_bytes(&self.0) 1912 } 1913 } 1914 1915 impl<'de> Deserialize<'de> for ByteBufferPayload { 1916 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 1917 where 1918 D: Deserializer<'de>, 1919 { 1920 struct Visitor; 1921 1922 impl<'de> de::Visitor<'de> for Visitor { 1923 type Value = ByteBufferPayload; 1924 1925 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 1926 formatter.write_str("a byte buffer") 1927 } 1928 1929 fn visit_byte_buf<E>(self, value: Vec<u8>) -> Result<Self::Value, E> { 1930 Ok(ByteBufferPayload(value)) 1931 } 1932 1933 fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> { 1934 Ok(ByteBufferPayload(value.to_vec())) 1935 } 1936 1937 fn visit_borrowed_bytes<E>(self, value: &'de [u8]) -> Result<Self::Value, E> { 1938 Ok(ByteBufferPayload(value.to_vec())) 1939 } 1940 } 1941 1942 deserializer.deserialize_byte_buf(Visitor) 1943 } 1944 } 1945 1946 fn operation_id() -> AdminOperationId { 1947 AdminOperationId::new("stable-operation").unwrap() 1948 } 1949 1950 fn correlation_id() -> AdminCorrelationId { 1951 AdminCorrelationId::new("safe-correlation").unwrap() 1952 } 1953 1954 #[test] 1955 fn request_and_response_snapshots_are_exact() { 1956 let request = AdminMutationRequest::new( 1957 operation_id(), 1958 Some(correlation_id()), 1959 ExampleRequest { value: 7 }, 1960 ) 1961 .unwrap(); 1962 assert_eq!( 1963 serde_json::to_string(&request).unwrap(), 1964 r#"{"contract_version":1,"operation_id":"stable-operation","correlation_id":"safe-correlation","request":{"value":7}}"# 1965 ); 1966 1967 let without_correlation = 1968 AdminMutationRequest::new(operation_id(), None, ExampleRequest { value: 7 }).unwrap(); 1969 assert_eq!( 1970 serde_json::to_string(&without_correlation).unwrap(), 1971 r#"{"contract_version":1,"operation_id":"stable-operation","request":{"value":7}}"# 1972 ); 1973 1974 let success = AdminSuccessResponse::new( 1975 correlation_id(), 1976 ExampleResult { 1977 state: "committed".to_owned(), 1978 }, 1979 ) 1980 .unwrap(); 1981 assert_eq!( 1982 serde_json::to_string(&success).unwrap(), 1983 r#"{"contract_version":1,"ok":true,"correlation_id":"safe-correlation","result":{"state":"committed"}}"# 1984 ); 1985 1986 let failure = AdminFailureResponse::new( 1987 correlation_id(), 1988 AdminError::new( 1989 AdminErrorCode::new("operation_id_conflict").unwrap(), 1990 AdminErrorMessage::new("operation identity conflicts with prior input").unwrap(), 1991 ), 1992 ); 1993 assert_eq!( 1994 serde_json::to_string(&failure).unwrap(), 1995 r#"{"contract_version":1,"ok":false,"correlation_id":"safe-correlation","error":{"code":"operation_id_conflict","message":"operation identity conflicts with prior input"}}"# 1996 ); 1997 } 1998 1999 #[test] 2000 fn recursive_non_null_adapter_covers_every_supported_serde_shape() { 2001 macro_rules! payload { 2002 ($ty:ty, $json:literal, $expected:expr) => { 2003 assert_eq!( 2004 serde_json::from_str::<NonNullPayload<$ty>>($json) 2005 .expect("non-null payload must decode") 2006 .0, 2007 $expected 2008 ); 2009 }; 2010 } 2011 2012 payload!(bool, "true", true); 2013 payload!(i8, "-8", -8); 2014 payload!(i16, "-16", -16); 2015 payload!(i32, "-32", -32); 2016 payload!(i64, "-64", -64); 2017 payload!(i128, "-128", -128); 2018 payload!(u8, "8", 8); 2019 payload!(u16, "16", 16); 2020 payload!(u32, "32", 32); 2021 payload!(u64, "64", 64); 2022 payload!(u128, "128", 128); 2023 payload!(f32, "1.5", 1.5); 2024 payload!(f64, "2.5", 2.5); 2025 payload!(char, r#""r""#, 'r'); 2026 payload!(String, r#""text""#, "text".to_owned()); 2027 payload!(Option<u32>, "7", Some(7)); 2028 payload!([u8; 3], "[1,2,3]", [1, 2, 3]); 2029 payload!((u8, bool), "[4,true]", (4, true)); 2030 payload!(NewtypePayload, "9", NewtypePayload(9)); 2031 payload!( 2032 TuplePayload, 2033 r#"[5,"tuple"]"#, 2034 TuplePayload(5, "tuple".to_owned()) 2035 ); 2036 payload!( 2037 StructPayload, 2038 r#"{"enabled":true,"count":11}"#, 2039 StructPayload { 2040 enabled: true, 2041 count: 11, 2042 } 2043 ); 2044 payload!(EnumPayload, r#""Unit""#, EnumPayload::Unit); 2045 payload!(EnumPayload, r#"{"Newtype":12}"#, EnumPayload::Newtype(12)); 2046 payload!( 2047 EnumPayload, 2048 r#"{"Tuple":[13,false]}"#, 2049 EnumPayload::Tuple(13, false) 2050 ); 2051 payload!( 2052 EnumPayload, 2053 r#"{"Struct":{"label":"enum"}}"#, 2054 EnumPayload::Struct { 2055 label: "enum".to_owned(), 2056 } 2057 ); 2058 payload!(AnyPayload, r#""any""#, AnyPayload("any".to_owned())); 2059 payload!( 2060 BTreeMap<String, u8>, 2061 r#"{"first":1,"second":2}"#, 2062 BTreeMap::from([("first".to_owned(), 1), ("second".to_owned(), 2)]) 2063 ); 2064 2065 let bytes = serde::de::value::BytesDeserializer::<serde::de::value::Error>::new(&[1, 2, 3]); 2066 assert_eq!( 2067 ByteBufferPayload::deserialize(NoNullDeserializer(bytes)).unwrap(), 2068 ByteBufferPayload(vec![1, 2, 3]) 2069 ); 2070 2071 assert!(serde_json::from_str::<NonNullPayload<()>>("null").is_err()); 2072 assert!(serde_json::from_str::<NonNullPayload<Option<u8>>>("null").is_err()); 2073 assert!(serde_json::from_str::<NonNullPayload<Vec<Option<u8>>>>("[1,null]").is_err()); 2074 assert!( 2075 serde_json::from_str::<NonNullPayload<BTreeMap<String, Option<u8>>>>( 2076 r#"{"safe":1,"forbidden":null}"#, 2077 ) 2078 .is_err() 2079 ); 2080 } 2081 2082 #[test] 2083 fn unknown_version_maps_to_the_stable_failure_response() { 2084 let request: AdminMutationRequest<ExampleRequest> = serde_json::from_str( 2085 r#"{"contract_version":2,"operation_id":"stable-operation","request":{"value":7}}"#, 2086 ) 2087 .unwrap(); 2088 let mismatch = request.validate_contract_version().unwrap_err(); 2089 assert_eq!(mismatch.received(), 2); 2090 let response = mismatch.response(correlation_id()); 2091 assert_eq!( 2092 serde_json::to_string(&response).unwrap(), 2093 r#"{"contract_version":1,"ok":false,"correlation_id":"safe-correlation","error":{"code":"unsupported_contract_version","message":"admin contract version is unsupported"}}"# 2094 ); 2095 } 2096 2097 #[test] 2098 fn invalid_ids_codes_messages_and_literals_fail_closed() { 2099 assert_eq!( 2100 AdminOperationId::new("").unwrap_err(), 2101 AdminIdentifierError::Empty { 2102 field: AdminIdentifierField::OperationId 2103 } 2104 ); 2105 assert!(AdminOperationId::new("x".repeat(ADMIN_OPERATION_ID_MAX_UTF8_BYTES)).is_ok()); 2106 assert!(AdminOperationId::new("x".repeat(ADMIN_OPERATION_ID_MAX_UTF8_BYTES + 1)).is_err()); 2107 for valid in ["a", "Z9", "a.b_c:d-e"] { 2108 assert!(AdminOperationId::new(valid).is_ok()); 2109 assert!(AdminCorrelationId::new(valid).is_ok()); 2110 } 2111 let maximum = "0".repeat(ADMIN_OPERATION_ID_MAX_UTF8_BYTES); 2112 assert!(AdminOperationId::new(&maximum).is_ok()); 2113 assert!(AdminCorrelationId::new(&maximum).is_ok()); 2114 for invalid in [ 2115 ".first", "_first", ":first", "-first", "é", "a/b", "a b", "a\n", 2116 ] { 2117 assert!(AdminOperationId::new(invalid).is_err()); 2118 assert!(AdminCorrelationId::new(invalid).is_err()); 2119 } 2120 assert_eq!( 2121 AdminOperationId::new("-first").unwrap_err(), 2122 AdminIdentifierError::InvalidFirstCharacter { 2123 field: AdminIdentifierField::OperationId 2124 } 2125 ); 2126 assert_eq!( 2127 AdminCorrelationId::new("a/b").unwrap_err(), 2128 AdminIdentifierError::InvalidCharacter { 2129 field: AdminIdentifierField::CorrelationId 2130 } 2131 ); 2132 let redacted_operation = AdminOperationId::new("private-operation").unwrap(); 2133 let redacted_correlation = AdminCorrelationId::new("private-correlation").unwrap(); 2134 assert_eq!( 2135 format!("{redacted_operation:?}"), 2136 "AdminOperationId(\"[redacted]\")" 2137 ); 2138 assert_eq!( 2139 format!("{redacted_correlation:?}"), 2140 "AdminCorrelationId(\"[redacted]\")" 2141 ); 2142 assert_eq!(redacted_operation.as_str(), "private-operation"); 2143 assert_eq!(redacted_correlation.as_str(), "private-correlation"); 2144 assert_eq!( 2145 serde_json::to_string(&redacted_operation).unwrap(), 2146 "\"private-operation\"" 2147 ); 2148 assert_eq!( 2149 serde_json::to_string(&redacted_correlation).unwrap(), 2150 "\"private-correlation\"" 2151 ); 2152 for byte in 0_u8..=127 { 2153 let character = char::from(byte); 2154 let first = character.to_string(); 2155 let first_allowed = byte.is_ascii_alphanumeric(); 2156 assert_eq!(AdminOperationId::new(&first).is_ok(), first_allowed); 2157 assert_eq!(AdminCorrelationId::new(&first).is_ok(), first_allowed); 2158 2159 let remaining = format!("a{character}"); 2160 let remaining_allowed = 2161 byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b':' | b'-'); 2162 assert_eq!(AdminOperationId::new(&remaining).is_ok(), remaining_allowed); 2163 assert_eq!( 2164 AdminCorrelationId::new(&remaining).is_ok(), 2165 remaining_allowed 2166 ); 2167 } 2168 assert!(AdminErrorCode::new("valid_code_2").is_ok()); 2169 assert!(AdminErrorCode::new("x".repeat(ADMIN_ERROR_CODE_MAX_UTF8_BYTES)).is_ok()); 2170 assert!(AdminErrorCode::new("Invalid-Code").is_err()); 2171 assert!(AdminErrorCode::new("valid-code").is_err()); 2172 assert!(AdminErrorMessage::new("x".repeat(ADMIN_ERROR_MESSAGE_MAX_UTF8_BYTES)).is_ok()); 2173 assert!( 2174 AdminErrorMessage::new("x".repeat(ADMIN_ERROR_MESSAGE_MAX_UTF8_BYTES + 1)).is_err() 2175 ); 2176 assert!(AdminErrorMessage::new("unsafe\nmessage").is_err()); 2177 2178 let very_large = "x".repeat(4 * 1024 * 1024); 2179 assert!(AdminOperationId::new(&very_large).is_err()); 2180 assert!(AdminCorrelationId::new(&very_large).is_err()); 2181 assert!(AdminErrorCode::new(&very_large).is_err()); 2182 assert!(AdminErrorMessage::new(&very_large).is_err()); 2183 let very_large_json = serde_json::to_string(&very_large).expect("large admin JSON string"); 2184 assert!(serde_json::from_str::<AdminOperationId>(&very_large_json).is_err()); 2185 assert!(serde_json::from_str::<AdminCorrelationId>(&very_large_json).is_err()); 2186 assert!(serde_json::from_str::<AdminErrorCode>(&very_large_json).is_err()); 2187 assert!(serde_json::from_str::<AdminErrorMessage>(&very_large_json).is_err()); 2188 2189 let wrong_success: Result<AdminSuccessResponse<ExampleResult>, _> = serde_json::from_str( 2190 r#"{"contract_version":1,"ok":false,"correlation_id":"safe-correlation","result":{"state":"committed"}}"#, 2191 ); 2192 assert!(wrong_success.is_err()); 2193 let wrong_failure: Result<AdminFailureResponse, _> = serde_json::from_str( 2194 r#"{"contract_version":1,"ok":true,"correlation_id":"safe-correlation","error":{"code":"valid_code","message":"safe"}}"#, 2195 ); 2196 assert!(wrong_failure.is_err()); 2197 let wrong_version: Result<AdminFailureResponse, _> = serde_json::from_str( 2198 r#"{"contract_version":2,"ok":false,"correlation_id":"safe-correlation","error":{"code":"valid_code","message":"safe"}}"#, 2199 ); 2200 assert!(wrong_version.is_err()); 2201 } 2202 2203 #[test] 2204 fn public_accessors_and_stable_errors_are_fully_bound() { 2205 let operation = operation_id(); 2206 let correlation = correlation_id(); 2207 let request = AdminMutationRequest::new( 2208 operation.clone(), 2209 Some(correlation.clone()), 2210 ExampleRequest { value: 17 }, 2211 ) 2212 .unwrap(); 2213 assert_eq!(request.contract_version(), ADMIN_CONTRACT_VERSION); 2214 assert_eq!(request.operation_id(), &operation); 2215 assert_eq!(request.correlation_id(), Some(&correlation)); 2216 assert_eq!(request.request().value, 17); 2217 assert!(request.validate_contract_version().is_ok()); 2218 assert_eq!(request.into_request(), ExampleRequest { value: 17 }); 2219 2220 let success = AdminSuccessResponse::new( 2221 correlation.clone(), 2222 ExampleResult { 2223 state: "ready".to_owned(), 2224 }, 2225 ) 2226 .unwrap(); 2227 assert_eq!(success.correlation_id(), &correlation); 2228 assert_eq!(success.result().state, "ready"); 2229 assert_eq!(success.into_result().state, "ready"); 2230 2231 let error = AdminError::new( 2232 AdminErrorCode::new("stable_error").unwrap(), 2233 AdminErrorMessage::new("stable message").unwrap(), 2234 ); 2235 assert_eq!(error.code().as_str(), "stable_error"); 2236 assert_eq!(error.message().as_str(), "stable message"); 2237 assert_eq!(error.code().to_string(), "stable_error"); 2238 assert_eq!(error.message().to_string(), "stable message"); 2239 let failure = AdminFailureResponse::new(correlation.clone(), error.clone()); 2240 assert_eq!(failure.correlation_id(), &correlation); 2241 assert_eq!(failure.error(), &error); 2242 2243 for rendered in [ 2244 AdminIdentifierError::Empty { 2245 field: AdminIdentifierField::CorrelationId, 2246 } 2247 .to_string(), 2248 AdminErrorCodeError::Empty.to_string(), 2249 AdminErrorMessageError::Empty.to_string(), 2250 AdminPayloadError::NullForbidden.to_string(), 2251 AdminPayloadError::Encoding.to_string(), 2252 AdminContractVersionError { received: 9 }.to_string(), 2253 ] { 2254 assert!(!rendered.is_empty()); 2255 } 2256 assert_eq!(operation.as_str(), "stable-operation"); 2257 assert_eq!(correlation.as_str(), "safe-correlation"); 2258 assert!(AdminErrorCode::new("").is_err()); 2259 assert!(AdminErrorCode::new("x".repeat(ADMIN_ERROR_CODE_MAX_UTF8_BYTES + 1)).is_err()); 2260 assert!(AdminErrorMessage::new("").is_err()); 2261 } 2262 2263 #[test] 2264 fn duplicate_unknown_and_null_fields_are_rejected() { 2265 for document in [ 2266 r#"{"contract_version":1,"contract_version":1,"operation_id":"stable-operation","request":{"value":7}}"#, 2267 r#"{"contract_version":1,"operation_id":"stable-operation","unknown":true,"request":{"value":7}}"#, 2268 r#"{"contract_version":1,"operation_id":"stable-operation","correlation_id":null,"request":{"value":7}}"#, 2269 r#"{"contract_version":1,"operation_id":"stable-operation","request":{"value":7,"unknown":true}}"#, 2270 ] { 2271 assert!( 2272 serde_json::from_str::<AdminMutationRequest<ExampleRequest>>(document).is_err() 2273 ); 2274 } 2275 2276 assert!( 2277 serde_json::from_str::<AdminMutationRequest<Option<ExampleRequest>>>( 2278 r#"{"contract_version":1,"operation_id":"stable-operation","request":null}"#, 2279 ) 2280 .is_err() 2281 ); 2282 assert!( 2283 serde_json::from_str::<AdminSuccessResponse<Option<ExampleResult>>>( 2284 r#"{"contract_version":1,"ok":true,"correlation_id":"safe-correlation","result":null}"#, 2285 ) 2286 .is_err() 2287 ); 2288 assert!(matches!( 2289 AdminMutationRequest::new(operation_id(), None, Option::<ExampleRequest>::None), 2290 Err(AdminPayloadError::NullForbidden) 2291 )); 2292 assert!(matches!( 2293 AdminSuccessResponse::new(correlation_id(), Option::<ExampleResult>::None), 2294 Err(AdminPayloadError::NullForbidden) 2295 )); 2296 } 2297 2298 #[derive(Serialize)] 2299 struct SensitivePayload { 2300 credential: String, 2301 } 2302 2303 struct NullNormalizingPayload; 2304 2305 impl Serialize for NullNormalizingPayload { 2306 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 2307 where 2308 S: Serializer, 2309 { 2310 serializer.serialize_str("normalized") 2311 } 2312 } 2313 2314 impl<'de> Deserialize<'de> for NullNormalizingPayload { 2315 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 2316 where 2317 D: Deserializer<'de>, 2318 { 2319 Option::<de::IgnoredAny>::deserialize(deserializer)?; 2320 Ok(Self) 2321 } 2322 } 2323 2324 #[test] 2325 fn raw_null_is_rejected_before_a_payload_can_normalize_it() { 2326 assert!( 2327 serde_json::from_str::<AdminMutationRequest<NullNormalizingPayload>>( 2328 r#"{"contract_version":1,"operation_id":"stable-operation","request":null}"#, 2329 ) 2330 .is_err() 2331 ); 2332 assert!( 2333 serde_json::from_str::<AdminSuccessResponse<NullNormalizingPayload>>( 2334 r#"{"contract_version":1,"ok":true,"correlation_id":"safe-correlation","result":null}"#, 2335 ) 2336 .is_err() 2337 ); 2338 } 2339 2340 struct IgnoredNestedNull; 2341 2342 impl Serialize for IgnoredNestedNull { 2343 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 2344 where 2345 S: Serializer, 2346 { 2347 let mut structure = serializer.serialize_struct("IgnoredNestedNull", 1)?; 2348 let _ = ser::SerializeStruct::serialize_field( 2349 &mut structure, 2350 "ignored", 2351 &Option::<u8>::None, 2352 ); 2353 ser::SerializeStruct::end(structure) 2354 } 2355 } 2356 2357 #[test] 2358 fn construction_rejects_a_nested_null_even_when_custom_serialization_ignores_the_error() { 2359 assert!(matches!( 2360 AdminSuccessResponse::new(correlation_id(), IgnoredNestedNull), 2361 Err(AdminPayloadError::NullForbidden) 2362 )); 2363 2364 let raw = serde_json::value::RawValue::from_string("null".to_owned()).unwrap(); 2365 assert!(matches!( 2366 AdminSuccessResponse::new(correlation_id(), raw), 2367 Err(AdminPayloadError::NullForbidden) 2368 )); 2369 2370 let raw = serde_json::value::RawValue::from_string( 2371 r#"{"null":"escaped \"null\" text"}"#.to_owned(), 2372 ) 2373 .unwrap(); 2374 assert!(AdminSuccessResponse::new(correlation_id(), raw).is_ok()); 2375 2376 let mut writer = NonNullJsonWriter::default(); 2377 assert_eq!(std::io::Write::write(&mut writer, b"nu").unwrap(), 2); 2378 assert!(std::io::Write::write(&mut writer, b"ll").is_err()); 2379 assert!(std::io::Write::write(&mut writer, b"true").is_err()); 2380 } 2381 2382 #[test] 2383 fn ordinary_debug_redacts_request_and_result_payloads() { 2384 let request = AdminMutationRequest::new( 2385 operation_id(), 2386 Some(correlation_id()), 2387 SensitivePayload { 2388 credential: "secret request credential".to_owned(), 2389 }, 2390 ) 2391 .unwrap(); 2392 let response = AdminSuccessResponse::new( 2393 correlation_id(), 2394 SensitivePayload { 2395 credential: "secret response credential".to_owned(), 2396 }, 2397 ) 2398 .unwrap(); 2399 2400 let request_debug = format!("{request:?}"); 2401 let response_debug = format!("{response:?}"); 2402 assert!(request_debug.contains("<redacted>")); 2403 assert!(response_debug.contains("<redacted>")); 2404 assert!(!request_debug.contains("secret request")); 2405 assert!(!response_debug.contains("secret response")); 2406 } 2407 2408 #[test] 2409 fn payload_encoding_failure_has_only_a_stable_crate_owned_error() { 2410 let unsupported_json_map_key = std::collections::BTreeMap::from([((1_u8, 2_u8), true)]); 2411 let error = AdminMutationRequest::new(operation_id(), None, unsupported_json_map_key) 2412 .expect_err("tuple map key must not encode as JSON"); 2413 2414 assert_eq!(error, AdminPayloadError::Encoding); 2415 assert_eq!(format!("{error:?}"), "Encoding"); 2416 assert!(error.source().is_none()); 2417 } 2418 2419 #[derive(Debug)] 2420 struct SensitiveCause; 2421 2422 impl fmt::Display for SensitiveCause { 2423 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 2424 formatter.write_str("database password and raw SQL") 2425 } 2426 } 2427 2428 impl Error for SensitiveCause {} 2429 2430 #[test] 2431 fn host_error_mapping_preserves_only_the_safe_projection() { 2432 let internal = HostError::with_source(HostErrorKind::TaskFailure, SensitiveCause); 2433 let response = 2434 AdminFailureResponse::new(correlation_id(), AdminError::from_host_error(&internal)); 2435 let encoded = serde_json::to_string(&response).unwrap(); 2436 2437 assert_eq!( 2438 encoded, 2439 r#"{"contract_version":1,"ok":false,"correlation_id":"safe-correlation","error":{"code":"host_task_failure","message":"authoritative service task failed"}}"# 2440 ); 2441 assert!(!encoded.contains("password")); 2442 assert!(!encoded.contains("SQL")); 2443 } 2444 }