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}