1 use std::fmt; 2 use std::cmp; 3 use std::convert::TryInto; 4 use std::time; 5 6 #[cfg(any(test, feature = "quickcheck"))] 7 use quickcheck::{Arbitrary, Gen}; 8 9 use crate::types::{DataFormat, Timestamp}; 10 use crate::Error; 11 use crate::packet; 12 use crate::Packet; 13 use crate::Result; 14 15 /// Holds a literal packet. 16 /// 17 /// A literal packet contains unstructured data. Since the size can 18 /// be very large, it is advised to process messages containing such 19 /// packets using a `PacketParser` or a `PacketPileParser` and process 20 /// the data in a streaming manner rather than the using the 21 /// `PacketPile::from_file` and related interfaces. 22 /// 23 /// See [Section 5.9 of RFC 4880] for details. 24 /// 25 /// [Section 5.9 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.9 26 // IMPORTANT: If you add fields to this struct, you need to explicitly 27 // IMPORTANT: implement PartialEq, Eq, and Hash. 28 #[derive(Clone, PartialEq, Eq, Hash)] 29 pub struct Literal { 30 /// CTB packet header fields. 31 pub(crate) common: packet::Common, 32 /// A one-octet field that describes how the data is formatted. 33 format: DataFormat, 34 /// filename is a string, but strings in Rust are valid UTF-8. 35 /// There is no guarantee, however, that the filename is valid 36 /// UTF-8. Thus, we leave filename as a byte array. It can be 37 /// converted to a string using String::from_utf8() or 38 /// String::from_utf8_lossy(). 39 filename: Option<Vec<u8>>, 40 /// A four-octet number that indicates a date associated with the 41 /// literal data. 42 date: Option<Timestamp>, 43 /// The literal data packet is a container packet, but cannot 44 /// store packets. 45 /// 46 /// This is written when serialized, and set by the packet parser 47 /// if `buffer_unread_content` is used. 48 container: packet::Container, 49 } 50 51 impl fmt::Debug for Literal { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result52 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 53 let filename = if let Some(ref filename) = self.filename { 54 Some(String::from_utf8_lossy(filename)) 55 } else { 56 None 57 }; 58 59 let threshold = 36; 60 let body = self.body(); 61 let prefix = &body[..cmp::min(threshold, body.len())]; 62 let mut prefix_fmt = String::from_utf8_lossy(prefix).into_owned(); 63 if body.len() > threshold { 64 prefix_fmt.push_str("..."); 65 } 66 prefix_fmt.push_str(&format!(" ({} bytes)", body.len())[..]); 67 68 f.debug_struct("Literal") 69 .field("format", &self.format) 70 .field("filename", &filename) 71 .field("date", &self.date) 72 .field("body", &prefix_fmt) 73 .field("body_digest", &self.container.body_digest()) 74 .finish() 75 } 76 } 77 78 impl Default for Literal { default() -> Self79 fn default() -> Self { 80 Self::new(Default::default()) 81 } 82 } 83 84 impl Literal { 85 /// Returns a new `Literal` packet. new(format: DataFormat) -> Literal86 pub fn new(format: DataFormat) -> Literal { 87 Literal { 88 common: Default::default(), 89 format, 90 filename: None, 91 date: None, 92 container: packet::Container::default_unprocessed(), 93 } 94 } 95 96 /// Gets the Literal packet's content disposition. format(&self) -> DataFormat97 pub fn format(&self) -> DataFormat { 98 self.format 99 } 100 101 /// Sets the Literal packet's content disposition. set_format(&mut self, format: DataFormat) -> DataFormat102 pub fn set_format(&mut self, format: DataFormat) -> DataFormat { 103 ::std::mem::replace(&mut self.format, format) 104 } 105 106 /// Gets the literal packet's filename. 107 /// 108 /// Note: when a literal data packet is protected by a signature, 109 /// only the literal data packet's body is protected, not the 110 /// meta-data. As such, this field should normally be ignored. filename(&self) -> Option<&[u8]>111 pub fn filename(&self) -> Option<&[u8]> { 112 self.filename.as_ref().map(|b| b.as_slice()) 113 } 114 115 /// Sets the literal packet's filename field. 116 /// 117 /// The standard does not specify the encoding. Filenames must 118 /// not be longer than 255 bytes. 119 /// 120 /// Note: when a literal data packet is protected by a signature, 121 /// only the literal data packet's body is protected, not the 122 /// meta-data. As such, this field should not be used. set_filename<F>(&mut self, filename: F) -> Result<Option<Vec<u8>>> where F: AsRef<[u8]>123 pub fn set_filename<F>(&mut self, filename: F) 124 -> Result<Option<Vec<u8>>> 125 where F: AsRef<[u8]> 126 { 127 let filename = filename.as_ref(); 128 Ok(::std::mem::replace(&mut self.filename, match filename.len() { 129 0 => None, 130 1..=255 => Some(filename.to_vec()), 131 n => return 132 Err(Error::InvalidArgument( 133 format!("filename too long: {} bytes", n)).into()), 134 })) 135 } 136 137 /// Gets the literal packet's date field. 138 /// 139 /// Note: when a literal data packet is protected by a signature, 140 /// only the literal data packet's body is protected, not the 141 /// meta-data. As such, this field should normally be ignored. date(&self) -> Option<time::SystemTime>142 pub fn date(&self) -> Option<time::SystemTime> { 143 self.date.map(|d| d.into()) 144 } 145 146 /// Sets the literal packet's date field. 147 /// 148 /// Note: when a literal data packet is protected by a signature, 149 /// only the literal data packet's body is protected, not the 150 /// meta-data. As such, this field should not be used. set_date<T>(&mut self, timestamp: T) -> Result<Option<time::SystemTime>> where T: Into<Option<time::SystemTime>>151 pub fn set_date<T>(&mut self, timestamp: T) 152 -> Result<Option<time::SystemTime>> 153 where T: Into<Option<time::SystemTime>> 154 { 155 let date = if let Some(d) = timestamp.into() { 156 let t = d.try_into()?; 157 if u32::from(t) == 0 { 158 None // RFC4880, section 5.9: 0 =^= "no specific time". 159 } else { 160 Some(t) 161 } 162 } else { 163 None 164 }; 165 Ok(std::mem::replace(&mut self.date, date).map(|d| d.into())) 166 } 167 } 168 169 impl_body_forwards!(Literal); 170 171 impl From<Literal> for Packet { from(s: Literal) -> Self172 fn from(s: Literal) -> Self { 173 Packet::Literal(s) 174 } 175 } 176 177 #[cfg(any(test, feature = "quickcheck"))] 178 impl Arbitrary for Literal { arbitrary<G: Gen>(g: &mut G) -> Self179 fn arbitrary<G: Gen>(g: &mut G) -> Self { 180 let mut l = Literal::new(DataFormat::arbitrary(g)); 181 l.set_body(Vec::<u8>::arbitrary(g)); 182 while let Err(_) = l.set_filename(&Vec::<u8>::arbitrary(g)) { 183 // Too long, try again. 184 } 185 l.set_date(Some(Timestamp::arbitrary(g).into())).unwrap(); 186 l 187 } 188 } 189 190 #[cfg(test)] 191 mod tests { 192 use super::*; 193 use crate::parse::Parse; 194 use crate::serialize::MarshalInto; 195 196 quickcheck! { 197 fn roundtrip(p: Literal) -> bool { 198 let q = Literal::from_bytes(&p.to_vec().unwrap()).unwrap(); 199 assert_eq!(p, q); 200 true 201 } 202 } 203 204 /// Checks that partially read packets are still considered equal. 205 #[test] partial_read_eq() -> Result<()>206 fn partial_read_eq() -> Result<()> { 207 use buffered_reader::BufferedReader; 208 use crate::parse::PacketParserBuilder; 209 210 let mut l0 = Literal::new(Default::default()); 211 l0.set_body(vec![0, 0]); 212 let l0 = Packet::from(l0); 213 let l0bin = l0.to_vec()?; 214 // Sanity check. 215 assert_eq!(l0, Packet::from_bytes(&l0bin)?); 216 217 for &buffer_unread_content in &[false, true] { 218 for read_n in 0..3 { 219 eprintln!("buffer_unread_content: {:?}, read_n: {}", 220 buffer_unread_content, read_n); 221 222 let mut b = PacketParserBuilder::from_bytes(&l0bin)?; 223 if buffer_unread_content { 224 b = b.buffer_unread_content(); 225 } 226 let mut pp = b.build()?.unwrap(); 227 let d = pp.steal(read_n)?; 228 d.into_iter().for_each(|b| assert_eq!(b, 0)); 229 let l = pp.finish()?; 230 assert_eq!(&l0, l); 231 let l = pp.next()?.0; 232 assert_eq!(l0, l); 233 } 234 } 235 Ok(()) 236 } 237 } 238