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