sequoia_openpgp/parse/
packet_pile_parser.rs

1use std::convert::TryFrom;
2
3use crate::{
4    Result,
5    Packet,
6    PacketPile,
7};
8use crate::parse::{
9    PacketParserBuilder,
10    PacketParserEOF,
11    PacketParserResult,
12    PacketParser,
13    Parse,
14    Cookie
15};
16use buffered_reader::BufferedReader;
17
18/// Parses an OpenPGP stream with the convenience of
19/// [`PacketPile::from_file`] and the flexibility of a
20/// [`PacketParser`].
21///
22///   [`PacketPile::from_file`]: ../struct.PacketPile.html#impl-Parse<%27a%2C%20PacketPile>
23///
24/// Like [`PacketPile::from_file`] (and unlike [`PacketParser`]), a
25/// `PacketPileParser` parses an OpenPGP message and returns a
26/// [`PacketPile`].  But, unlike [`PacketPile::from_file`] (and like
27/// [`PacketParser`]), it allows the caller to inspect each packet as
28/// it is being parsed.
29///
30///   [`PacketPile`]: crate::PacketPile
31///
32/// Thus, using a `PacketPileParser`, it is possible to decide on a
33/// per-packet basis whether to stream, buffer or drop the packet's
34/// body, whether to recurse into a container, or whether to abort
35/// processing, for example.  And, `PacketPileParser` conveniently packs
36/// the packets into a [`PacketPile`].
37///
38/// If old packets don't need to be retained, then [`PacketParser`]
39/// should be preferred.  If no per-packet processing needs to be
40/// done, then [`PacketPile::from_file`] will be slightly faster.
41///
42/// # Examples
43///
44/// These examples demonstrate how to process packet bodies by parsing
45/// the simplest possible OpenPGP message containing just a single
46/// literal data packet with the body "Hello world.".  There are three
47/// options.  First, the body can be dropped.  Second, it can be
48/// buffered.  Lastly, the body can be streamed.  In general,
49/// streaming should be preferred, because it avoids buffering in
50/// Sequoia.
51///
52/// This example demonstrates simply ignoring the packet body:
53///
54/// ```rust
55/// # fn main() -> sequoia_openpgp::Result<()> {
56/// use sequoia_openpgp as openpgp;
57/// use openpgp::Packet;
58/// use openpgp::parse::{Parse, PacketPileParser};
59///
60/// // By default, the `PacketPileParser` will drop packet bodies.
61/// let mut ppp =
62///     PacketPileParser::from_bytes(
63///         b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?;
64/// while ppp.packet().is_ok() {
65///     // Start parsing the next packet, recursing.
66///     ppp.recurse()?;
67/// }
68///
69/// let pile = ppp.finish();
70/// // Process the packet.
71/// if let Some(Packet::Literal(literal)) = pile.path_ref(&[0]) {
72///     // The body was dropped.
73///     assert_eq!(literal.body(), b"");
74/// } else {
75///     unreachable!("We know it is a literal packet.");
76/// }
77/// # Ok(()) }
78/// ```
79///
80/// This example demonstrates how the body can be buffered by
81/// configuring the `PacketPileParser` to buffer all packet bodies:
82///
83/// ```rust
84/// # fn main() -> sequoia_openpgp::Result<()> {
85/// use std::convert::TryFrom;
86///
87/// use sequoia_openpgp as openpgp;
88/// use openpgp::Packet;
89/// use openpgp::parse::{Parse, PacketPileParser, PacketParserBuilder};
90///
91/// // By default, the `PacketPileParser` will drop packet bodies.
92/// // Use a `PacketParserBuilder` to change that.
93/// let mut ppb =
94///     PacketParserBuilder::from_bytes(
95///         b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?
96///     .buffer_unread_content();
97/// let mut ppp = PacketPileParser::try_from(ppb)?;
98/// while ppp.packet().is_ok() {
99///     // Start parsing the next packet, recursing.
100///     ppp.recurse()?;
101/// }
102///
103/// let pile = ppp.finish();
104/// // Process the packet.
105/// if let Some(Packet::Literal(literal)) = pile.path_ref(&[0]) {
106///     // The body was buffered.
107///     assert_eq!(literal.body(), b"Hello world.");
108/// } else {
109///     unreachable!("We know it is a literal packet.");
110/// }
111/// # Ok(()) }
112/// ```
113///
114/// This example demonstrates how the body can be buffered by
115/// buffering an individual packet:
116///
117/// ```rust
118/// # fn main() -> sequoia_openpgp::Result<()> {
119/// use sequoia_openpgp as openpgp;
120/// use openpgp::Packet;
121/// use openpgp::parse::{Parse, PacketPileParser};
122///
123/// // By default, the `PacketPileParser` will drop packet bodies.
124/// let mut ppp =
125///     PacketPileParser::from_bytes(
126///         b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?;
127/// while let Ok(pp) = ppp.packet_mut() {
128///     if let Packet::Literal(_) = pp.packet {
129///         // Buffer this packet's body.
130///         pp.buffer_unread_content()?;
131///     }
132///
133///     // Start parsing the next packet, recursing.
134///     ppp.recurse()?;
135/// }
136///
137/// let pile = ppp.finish();
138/// // Process the packet.
139/// if let Some(Packet::Literal(literal)) = pile.path_ref(&[0]) {
140///     // The body was buffered.
141///     assert_eq!(literal.body(), b"Hello world.");
142/// } else {
143///     unreachable!("We know it is a literal packet.");
144/// }
145/// # Ok(()) }
146/// ```
147///
148/// This example demonstrates how to stream the packet body:
149///
150/// ```rust
151/// # fn main() -> sequoia_openpgp::Result<()> {
152/// use std::io::Read;
153///
154/// use sequoia_openpgp as openpgp;
155/// use openpgp::Packet;
156/// use openpgp::parse::{Parse, PacketPileParser};
157///
158/// // By default, the `PacketPileParser` will drop packet bodies.
159/// let mut ppp =
160///     PacketPileParser::from_bytes(
161///         b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?;
162/// while let Ok(pp) = ppp.packet_mut() {
163///     if let Packet::Literal(_) = pp.packet {
164///         // Stream the body.
165///         let mut buf = Vec::new();
166///         pp.read_to_end(&mut buf)?;
167///         assert_eq!(buf, b"Hello world.");
168///     }
169///
170///     // Start parsing the next packet, recursing.
171///     ppp.recurse()?;
172/// }
173///
174/// let pile = ppp.finish();
175/// // Process the packet.
176/// if let Some(Packet::Literal(literal)) = pile.path_ref(&[0]) {
177///     // The body was streamed, not buffered.
178///     assert_eq!(literal.body(), b"");
179/// } else {
180///     unreachable!("We know it is a literal packet.");
181/// }
182/// # Ok(()) }
183/// ```
184#[derive(Debug)]
185pub struct PacketPileParser<'a> {
186    /// The current packet.
187    ppr: PacketParserResult<'a>,
188
189    /// The packet pile that has been assembled so far.
190    pile: PacketPile,
191}
192assert_send_and_sync!(PacketPileParser<'_>);
193
194impl<'a> TryFrom<PacketParserBuilder<'a>> for PacketPileParser<'a> {
195    type Error = anyhow::Error;
196
197    /// Finishes configuring the `PacketParser` and returns a
198    /// `PacketPileParser`.
199    fn try_from(ppb: PacketParserBuilder<'a>) -> Result<PacketPileParser<'a>> {
200        Self::from_packet_parser(ppb.build()?)
201    }
202}
203
204impl<'a> Parse<'a, PacketPileParser<'a>> for PacketPileParser<'a> {
205    fn from_buffered_reader<R>(reader: R) -> Result<PacketPileParser<'a>>
206    where
207        R: BufferedReader<Cookie> + 'a
208    {
209        PacketPileParser::from_cookie_reader(reader.into_boxed())
210    }
211}
212
213impl<'a> crate::seal::Sealed for PacketPileParser<'a> {}
214
215impl<'a> PacketPileParser<'a> {
216    /// Creates a `PacketPileParser` from a *fresh* `PacketParser`.
217    fn from_packet_parser(ppr: PacketParserResult<'a>)
218        -> Result<PacketPileParser<'a>>
219    {
220        Ok(PacketPileParser {
221            pile: Default::default(),
222            ppr,
223        })
224    }
225
226    /// Creates a `PacketPileParser` to parse the OpenPGP message stored
227    /// in the `BufferedReader` object.
228    pub(crate) fn from_cookie_reader(bio: Box<dyn BufferedReader<Cookie> + 'a>)
229            -> Result<PacketPileParser<'a>> {
230        Self::from_packet_parser(PacketParser::from_cookie_reader(bio)?)
231    }
232
233    /// Inserts the next packet into the `PacketPile`.
234    fn insert_packet(&mut self, packet: Packet, position: isize) {
235        // Find the right container.
236        let mut container = self.pile.top_level_mut();
237
238        assert!(position >= 0);
239
240        for i in 0..position {
241            // The most recent child.
242            let tmp = container;
243            let packets_len = tmp.children_ref().expect("is a container").len();
244            let p = &mut tmp.children_mut()
245                .expect("is a container")
246                [packets_len - 1];
247            if p.children().expect("is a container").next().is_none() {
248                assert!(i == position - 1,
249                        "Internal inconsistency while building message.");
250            }
251
252            container = p.container_mut().unwrap();
253        }
254
255        container.children_mut().unwrap().push(packet);
256    }
257
258    /// Returns a reference to the current packet.
259    pub fn packet(&self)
260                  -> std::result::Result<&PacketParser<'a>, &PacketParserEOF>
261    {
262        self.ppr.as_ref()
263    }
264
265    /// Returns a mutable reference to the current packet.
266    pub fn packet_mut<>(&mut self)
267                        -> std::result::Result<&mut PacketParser<'a>,
268                                               &mut PacketParserEOF<'a>>
269    {
270        self.ppr.as_mut()
271    }
272
273    /// Finishes parsing the current packet and starts parsing the
274    /// next one, recursing if possible.
275    ///
276    /// This method is similar to the [`next()`] method (see that
277    /// method for more details), but if the current packet is a
278    /// container (and we haven't reached the maximum recursion depth,
279    /// and the user hasn't started reading the packet's contents), we
280    /// recurse into the container, and return a `PacketParser` for
281    /// its first child.  Otherwise, we return the next packet in the
282    /// packet stream.  If this function recurses, then the new
283    /// packet's recursion depth will be `last_recursion_depth() + 1`;
284    /// because we always visit interior nodes, we can't recurse more
285    /// than one level at a time.
286    ///
287    ///   [`next()`]: PacketPileParser::next()
288    ///
289    /// # Examples
290    ///
291    /// ```rust
292    /// # fn main() -> sequoia_openpgp::Result<()> {
293    /// use sequoia_openpgp as openpgp;
294    /// use openpgp::parse::{Parse, PacketPileParser};
295    ///
296    /// // Parse a message.
297    /// let message_data: &[u8] = // ...
298    /// #    include_bytes!("../../tests/data/messages/compressed-data-algo-0.pgp");
299    /// let mut ppp = PacketPileParser::from_bytes(message_data)?;
300    /// while let Ok(pp) = ppp.packet() {
301    ///     // Do something interesting with `pp` here.
302    ///
303    ///     // Start parsing the next packet, recursing.
304    ///     ppp.recurse()?;
305    /// }
306    ///
307    /// let pile = ppp.finish();
308    /// # Ok(()) }
309    /// ```
310    pub fn recurse(&mut self) -> Result<()> {
311        match self.ppr.take() {
312            PacketParserResult::Some(pp) => {
313                let recursion_depth = pp.recursion_depth();
314                let (packet, ppr) = pp.recurse()?;
315                self.insert_packet(
316                    packet,
317                    recursion_depth as isize);
318                self.ppr = ppr;
319            }
320            eof @ PacketParserResult::EOF(_) => {
321                self.ppr = eof;
322            }
323        }
324
325        Ok(())
326    }
327
328    /// Finishes parsing the current packet and starts parsing the
329    /// next one.
330    ///
331    /// This function finishes parsing the current packet.  By
332    /// default, any unread content is dropped.  (See
333    /// [`PacketParsererBuilder`] for how to configure this.)  It then
334    /// creates a new packet parser for the next packet.  If the
335    /// current packet is a container, this function does *not*
336    /// recurse into the container, but skips any packets it contains.
337    /// To recurse into the container, use the [`recurse()`] method.
338    ///
339    ///   [`PacketParsererBuilder`]: PacketParserBuilder
340    ///   [`recurse()`]: PacketPileParser::recurse()
341    ///
342    /// # Examples
343    ///
344    /// ```rust
345    /// # fn main() -> sequoia_openpgp::Result<()> {
346    /// use sequoia_openpgp as openpgp;
347    /// use openpgp::parse::{Parse, PacketPileParser};
348    ///
349    /// // Parse a message.
350    /// let message_data: &[u8] = // ...
351    /// #    include_bytes!("../../tests/data/messages/compressed-data-algo-0.pgp");
352    /// let mut ppp = PacketPileParser::from_bytes(message_data)?;
353    /// while let Ok(pp) = ppp.packet() {
354    ///     // Do something interesting with `pp` here.
355    ///
356    ///     // Start parsing the next packet.
357    ///     ppp.next()?;
358    /// }
359    ///
360    /// let pile = ppp.finish();
361    /// # Ok(()) }
362    /// ```
363    pub fn next(&mut self) -> Result<()> {
364        match self.ppr.take() {
365            PacketParserResult::Some(pp) => {
366                let recursion_depth = pp.recursion_depth();
367                let (packet, ppr) = pp.next()?;
368                self.insert_packet(
369                    packet,
370                    recursion_depth as isize);
371                self.ppr = ppr;
372            },
373            eof @ PacketParserResult::EOF(_) => {
374                self.ppr = eof
375            },
376        }
377
378        Ok(())
379    }
380
381    /// Returns the current packet's recursion depth.
382    ///
383    /// A top-level packet has a recursion depth of 0.  Packets in a
384    /// top-level container have a recursion depth of 1.  Etc.
385    ///
386    /// # Examples
387    ///
388    /// ```rust
389    /// # fn main() -> sequoia_openpgp::Result<()> {
390    /// use sequoia_openpgp as openpgp;
391    /// use openpgp::Packet;
392    /// use openpgp::parse::{Parse, PacketPileParser};
393    ///
394    /// // Parse a simple compressed message.
395    /// let message_data: &[u8] = // ...
396    /// #    include_bytes!("../../tests/data/messages/compressed-data-algo-0.pgp");
397    /// let mut ppp = PacketPileParser::from_bytes(message_data)?;
398    /// while let Ok(pp) = ppp.packet() {
399    ///     match pp.packet {
400    ///         Packet::CompressedData(_) =>
401    ///             assert_eq!(ppp.recursion_depth(), Some(0)),
402    ///         Packet::Literal(_) =>
403    ///             assert_eq!(ppp.recursion_depth(), Some(1)),
404    ///         _ => unreachable!(),
405    ///     }
406    ///
407    ///     // Alternatively, the recursion depth can be queried
408    ///     // from the packet parser.
409    ///     assert_eq!(ppp.recursion_depth(), Some(pp.recursion_depth()));
410    ///
411    ///     // Start parsing the next packet.
412    ///     ppp.next()?;
413    /// }
414    ///
415    /// let pile = ppp.finish();
416    /// # Ok(()) }
417    /// ```
418    pub fn recursion_depth(&self) -> Option<isize> {
419        if let PacketParserResult::Some(ref pp) = self.ppr {
420            Some(pp.recursion_depth())
421        } else {
422            None
423        }
424    }
425
426    /// Returns whether the message has been completely parsed.
427    ///
428    /// # Examples
429    ///
430    /// ```rust
431    /// # fn main() -> sequoia_openpgp::Result<()> {
432    /// use sequoia_openpgp as openpgp;
433    /// use openpgp::Packet;
434    /// use openpgp::parse::{Parse, PacketPileParser};
435    ///
436    /// // Parse a message.
437    /// let message_data: &[u8] = // ...
438    /// #    include_bytes!("../../tests/data/messages/compressed-data-algo-0.pgp");
439    /// let mut ppp = PacketPileParser::from_bytes(message_data)?;
440    /// while ppp.packet().is_ok() {
441    ///     // Start parsing the next packet.
442    ///     ppp.next()?;
443    /// }
444    ///
445    /// assert!(ppp.is_done());
446    /// let pile = ppp.finish();
447    /// # Ok(()) }
448    /// ```
449    pub fn is_done(&self) -> bool {
450        self.ppr.is_eof()
451    }
452
453    /// Finishes parsing the message and returns the assembled
454    /// `PacketPile`.
455    ///
456    /// This function can be called at any time, not only when the
457    /// message has been completely parsed.  If the packet sequence has not
458    /// been completely parsed, this function aborts processing, and
459    /// the returned `PacketPile` just contains those packets that were
460    /// completely processed; the packet that is currently being
461    /// processed is not included in the `PacketPile`.
462    ///
463    /// # Examples
464    ///
465    /// ```rust
466    /// # fn main() -> sequoia_openpgp::Result<()> {
467    /// use sequoia_openpgp as openpgp;
468    /// use openpgp::Packet;
469    /// use openpgp::parse::{Parse, PacketPileParser};
470    ///
471    /// // Parse a message.
472    /// let message_data: &[u8] = // ...
473    /// #    include_bytes!("../../tests/data/messages/compressed-data-algo-0.pgp");
474    /// let mut ppp = PacketPileParser::from_bytes(message_data)?;
475    /// ppp.next()?;
476    ///
477    /// let pp = ppp.finish();
478    /// assert_eq!(pp.children().count(), 1);
479    /// # Ok(()) }
480    /// ```
481    pub fn finish(self) -> PacketPile {
482        self.pile
483    }
484}
485
486#[test]
487fn test_recurse() -> Result<()> {
488    let mut count = 0;
489    let mut ppp =
490        PacketPileParser::from_bytes(crate::tests::key("public-key.pgp"))?;
491    while ppp.packet().is_ok() {
492        count += 1;
493        ppp.recurse().unwrap();
494    }
495    assert_eq!(count, 61);
496    let pp = ppp.finish();
497    assert_eq!(pp.children().count(), 61);
498    Ok(())
499}
500
501#[test]
502fn test_next() -> Result<()> {
503    let mut count = 0;
504    let mut ppp =
505        PacketPileParser::from_bytes(crate::tests::key("public-key.pgp"))?;
506    while ppp.packet().is_ok() {
507        count += 1;
508        ppp.next().unwrap();
509    }
510    assert_eq!(count, 61);
511    let pp = ppp.finish();
512    assert_eq!(pp.children().count(), 61);
513    Ok(())
514}
515
516/// Check that we can use the read interface to stream the contents of
517/// a packet.
518#[cfg(feature = "compression-deflate")]
519#[test]
520fn message_parser_reader_interface() {
521    use std::io::Read;
522
523    let expected = crate::tests::manifesto();
524
525    // A message containing a compressed packet that contains a
526    // literal packet.
527    let mut ppp = PacketPileParser::from_bytes(
528        crate::tests::message("compressed-data-algo-1.pgp")).unwrap();
529    let mut count = 0;
530    while let Ok(pp) = ppp.packet_mut() {
531        if let Packet::Literal(_) = pp.packet {
532            assert_eq!(count, 1); // The *second* packet.
533
534            // Check that we can read the packet's contents.  We do this one
535            // byte at a time to exercise the cursor implementation.
536            for i in 0..expected.len() {
537                let mut buf = [0u8; 1];
538                let r = pp.read(&mut buf).unwrap();
539                assert_eq!(r, 1);
540                assert_eq!(buf[0], expected[i]);
541            }
542            // And, now an EOF.
543            let mut buf = [0u8; 1];
544            let r = pp.read(&mut buf).unwrap();
545            assert_eq!(r, 0);
546        }
547        ppp.recurse().unwrap();
548        count += 1;
549    }
550    assert_eq!(count, 2);
551}