uri.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. use log::*;
  2. use crate::wire::*;
  3. /// A **URI** record, which holds a URI along with weight and priority values
  4. /// to balance between several records.
  5. ///
  6. /// # References
  7. ///
  8. /// - [RFC 7553](https://tools.ietf.org/html/rfc7553) — The Uniform Resource
  9. /// Identifier (URI) DNS Resource Record (June 2015)
  10. /// - [RFC 3986](https://tools.ietf.org/html/rfc3986) — Uniform Resource
  11. /// Identifier (URI): Generic Syntax (January 2005)
  12. #[derive(PartialEq, Debug)]
  13. pub struct URI {
  14. /// The priority of the URI. Clients are supposed to contact the URI with
  15. /// the lowest priority out of all the ones it can reach.
  16. pub priority: u16,
  17. /// The weight of the URI, which specifies a relative weight for entries
  18. /// with the same priority.
  19. pub weight: u16,
  20. /// The URI contained in the record. Since all we are doing is displaying
  21. /// it to the user, we do not need to parse it for accuracy.
  22. pub target: String,
  23. }
  24. impl Wire for URI {
  25. const NAME: &'static str = "URI";
  26. const RR_TYPE: u16 = 256;
  27. #[cfg_attr(feature = "with_mutagen", ::mutagen::mutate)]
  28. fn read(stated_length: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
  29. let priority = c.read_u16::<BigEndian>()?;
  30. trace!("Parsed priority -> {:?}", priority);
  31. let weight = c.read_u16::<BigEndian>()?;
  32. trace!("Parsed weight -> {:?}", weight);
  33. // The target must not be empty.
  34. if stated_length <= 4 {
  35. let mandated_length = MandatedLength::AtLeast(5);
  36. return Err(WireError::WrongRecordLength { stated_length, mandated_length });
  37. }
  38. let remaining_length = stated_length - 4;
  39. let mut buf = Vec::with_capacity(remaining_length.into());
  40. for _ in 0 .. remaining_length {
  41. buf.push(c.read_u8()?);
  42. }
  43. let target = String::from_utf8_lossy(&buf).to_string();
  44. trace!("Parsed target -> {:?}", target);
  45. Ok(Self { priority, weight, target })
  46. }
  47. }
  48. #[cfg(test)]
  49. mod test {
  50. use super::*;
  51. use pretty_assertions::assert_eq;
  52. #[test]
  53. fn parses() {
  54. let buf = &[
  55. 0x00, 0x0A, // priority
  56. 0x00, 0x10, // weight
  57. 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x72, 0x66, 0x63,
  58. 0x73, 0x2e, 0x69, 0x6f, 0x2f, // uri
  59. ];
  60. assert_eq!(URI::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(),
  61. URI {
  62. priority: 10,
  63. weight: 16,
  64. target: String::from("https://rfcs.io/"),
  65. });
  66. }
  67. #[test]
  68. fn one_byte_of_uri() {
  69. let buf = &[
  70. 0x00, 0x0A, // priority
  71. 0x00, 0x10, // weight
  72. 0x2f, // one byte of uri (invalid but still a legitimate DNS record)
  73. ];
  74. assert_eq!(URI::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(),
  75. URI {
  76. priority: 10,
  77. weight: 16,
  78. target: String::from("/"),
  79. });
  80. }
  81. #[test]
  82. fn missing_any_data() {
  83. let buf = &[
  84. 0x00, 0x0A, // priority
  85. 0x00, 0x10, // weight
  86. ];
  87. assert_eq!(URI::read(buf.len() as _, &mut Cursor::new(buf)),
  88. Err(WireError::WrongRecordLength { stated_length: 4, mandated_length: MandatedLength::AtLeast(5) }));
  89. }
  90. #[test]
  91. fn record_empty() {
  92. assert_eq!(URI::read(0, &mut Cursor::new(&[])),
  93. Err(WireError::IO));
  94. }
  95. #[test]
  96. fn buffer_ends_abruptly() {
  97. let buf = &[
  98. 0x00, 0x0A, // half a priority
  99. ];
  100. assert_eq!(URI::read(23, &mut Cursor::new(buf)),
  101. Err(WireError::IO));
  102. }
  103. }