summaryrefslogtreecommitdiffstats
path: root/openpgp
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-09-17 14:09:46 +0200
committerJustus Winter <justus@sequoia-pgp.org>2020-09-17 14:31:50 +0200
commit9310ec08bd0a46f6b128678cefa4ff861eaa3bfe (patch)
tree50117be75dc3d4b00fd356cbdbf0dcaa20611ab0 /openpgp
parent072818fdf67f7693a71f8bf1ad331e3e99cabfcf (diff)
openpgp: Improve parsing examples to demonstrate body handling.
- Demonstrate dropping, buffering of all bodies, buffering of individual bodies, and streaming. - Fixes #540.
Diffstat (limited to 'openpgp')
-rw-r--r--openpgp/src/parse.rs132
-rw-r--r--openpgp/src/parse/packet_pile_parser.rs147
2 files changed, 258 insertions, 21 deletions
diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs
index de43c1c4..d2ac00c4 100644
--- a/openpgp/src/parse.rs
+++ b/openpgp/src/parse.rs
@@ -3027,7 +3027,15 @@ impl PacketParserState {
///
/// # Examples
///
-/// Parse an OpenPGP message using a `PacketParser`:
+/// These examples demonstrate how to process packet bodies by parsing
+/// the simplest possible OpenPGP message containing just a single
+/// literal data packet with the body "Hello world.". There are three
+/// options. First, the body can be dropped. Second, it can be
+/// buffered. Lastly, the body can be streamed. In general,
+/// streaming should be preferred, because it avoids buffering in
+/// Sequoia.
+///
+/// This example demonstrates simply ignoring the packet body:
///
/// ```rust
/// # fn main() -> sequoia_openpgp::Result<()> {
@@ -3035,19 +3043,127 @@ impl PacketParserState {
/// use openpgp::Packet;
/// use openpgp::parse::{Parse, PacketParserResult, PacketParser};
///
-/// let message_data: &[u8] = // ...
-/// # include_bytes!("../tests/data/keys/public-key.gpg");
-/// let mut ppr = PacketParser::from_bytes(message_data)?;
+/// // By default, the `PacketParser` will drop packet bodies.
+/// let mut ppr =
+/// PacketParser::from_bytes(b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?;
+/// while let PacketParserResult::Some(pp) = ppr {
+/// // Get the packet out of the parser and start parsing the next
+/// // packet, recursing.
+/// let (packet, next_ppr) = pp.recurse()?;
+/// ppr = next_ppr;
+///
+/// // Process the packet.
+/// if let Packet::Literal(literal) = packet {
+/// // The body was dropped.
+/// assert_eq!(literal.body(), b"");
+/// } else {
+/// unreachable!("We know it is a literal packet.");
+/// }
+/// }
+/// # Ok(()) }
+/// ```
+///
+/// This example demonstrates how the body can be buffered by
+/// configuring the `PacketParser` to buffer all packet bodies:
+///
+/// ```rust
+/// # fn main() -> sequoia_openpgp::Result<()> {
+/// use sequoia_openpgp as openpgp;
+/// use openpgp::Packet;
+/// use openpgp::parse::{Parse, PacketParserResult, PacketParserBuilder};
+///
+/// // By default, the `PacketParser` will drop packet bodies. Use a
+/// // `PacketParserBuilder` to change that.
+/// let mut ppr =
+/// PacketParserBuilder::from_bytes(
+/// b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?
+/// .buffer_unread_content()
+/// .build()?;
+/// while let PacketParserResult::Some(pp) = ppr {
+/// // Get the packet out of the parser and start parsing the next
+/// // packet, recursing.
+/// let (packet, next_ppr) = pp.recurse()?;
+/// ppr = next_ppr;
+///
+/// // Process the packet.
+/// if let Packet::Literal(literal) = packet {
+/// // The body was buffered.
+/// assert_eq!(literal.body(), b"Hello world.");
+/// } else {
+/// unreachable!("We know it is a literal packet.");
+/// }
+/// }
+/// # Ok(()) }
+/// ```
+///
+/// This example demonstrates how the body can be buffered by
+/// buffering an individual packet:
+///
+/// ```rust
+/// # fn main() -> sequoia_openpgp::Result<()> {
+/// use sequoia_openpgp as openpgp;
+/// use openpgp::Packet;
+/// use openpgp::parse::{Parse, PacketParserResult, PacketParser};
+///
+/// // By default, the `PacketParser` will drop packet bodies.
+/// let mut ppr =
+/// PacketParser::from_bytes(b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?;
/// while let PacketParserResult::Some(mut pp) = ppr {
+/// if let Packet::Literal(_) = pp.packet {
+/// // Buffer this packet's body.
+/// pp.buffer_unread_content()?;
+/// }
+///
+/// // Get the packet out of the parser and start parsing the next
+/// // packet, recursing.
+/// let (packet, next_ppr) = pp.recurse()?;
+/// ppr = next_ppr;
+///
/// // Process the packet.
+/// if let Packet::Literal(literal) = packet {
+/// // The body was buffered.
+/// assert_eq!(literal.body(), b"Hello world.");
+/// } else {
+/// unreachable!("We know it is a literal packet.");
+/// }
+/// }
+/// # Ok(()) }
+/// ```
+///
+/// This example demonstrates how to stream the packet body:
+///
+/// ```rust
+/// # fn main() -> sequoia_openpgp::Result<()> {
+/// use std::io::Read;
///
+/// use sequoia_openpgp as openpgp;
+/// use openpgp::Packet;
+/// use openpgp::parse::{Parse, PacketParserResult, PacketParser};
+///
+/// let mut ppr =
+/// PacketParser::from_bytes(b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?;
+/// while let PacketParserResult::Some(mut pp) = ppr {
/// if let Packet::Literal(_) = pp.packet {
-/// // Stream the content of any literal packets to stdout.
-/// std::io::copy(&mut pp, &mut std::io::stdout());
+/// // Stream the body.
+/// let mut buf = Vec::new();
+/// pp.read_to_end(&mut buf)?;
+/// assert_eq!(buf, b"Hello world.");
+/// } else {
+/// unreachable!("We know it is a literal packet.");
/// }
///
-/// // Start parsing the next packet, recursing.
-/// ppr = pp.recurse()?.1;
+/// // Get the packet out of the parser and start parsing the next
+/// // packet, recursing.
+/// let (packet, next_ppr) = pp.recurse()?;
+/// ppr = next_ppr;
+///
+/// // Process the packet.
+/// if let Packet::Literal(literal) = packet {
+/// // The body was streamed, not buffered.
+/// assert_eq!(literal.body(), b"");
+/// } else {
+/// unreachable!("We know it is a literal packet.");
+/// }
/// }
/// # Ok(()) }
/// ```
diff --git a/openpgp/src/parse/packet_pile_parser.rs b/openpgp/src/parse/packet_pile_parser.rs
index 78483b82..fe1e989c 100644
--- a/openpgp/src/parse/packet_pile_parser.rs
+++ b/openpgp/src/parse/packet_pile_parser.rs
@@ -44,28 +44,145 @@ use buffered_reader::BufferedReader;
///
/// # Examples
///
+/// These examples demonstrate how to process packet bodies by parsing
+/// the simplest possible OpenPGP message containing just a single
+/// literal data packet with the body "Hello world.". There are three
+/// options. First, the body can be dropped. Second, it can be
+/// buffered. Lastly, the body can be streamed. In general,
+/// streaming should be preferred, because it avoids buffering in
+/// Sequoia.
+///
+/// This example demonstrates simply ignoring the packet body:
+///
/// ```rust
/// # fn main() -> sequoia_openpgp::Result<()> {
/// use sequoia_openpgp as openpgp;
+/// use openpgp::Packet;
/// use openpgp::parse::{Parse, PacketPileParser};
///
-/// // Parse a message.
-/// let message_data: &[u8] = // ...
-/// # include_bytes!("../../tests/data/keys/public-key.gpg");
-/// # let mut n = 0;
-/// let mut ppp = PacketPileParser::from_bytes(message_data)?;
-/// while let Ok(pp) = ppp.as_ref() {
-/// eprintln!("{:?}", pp);
+/// // By default, the `PacketPileParser` will drop packet bodies.
+/// let mut ppp =
+/// PacketPileParser::from_bytes(
+/// b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?;
+/// while ppp.is_some() {
+/// // Start parsing the next packet, recursing.
/// ppp.recurse()?;
-/// # n += 1;
/// }
///
/// let pile = ppp.finish();
-/// pile.pretty_print();
-/// # assert_eq!(n, 61);
-/// # assert_eq!(pile.children().len(), 61);
-/// # Ok(())
-/// # }
+/// // Process the packet.
+/// if let Some(Packet::Literal(literal)) = pile.path_ref(&[0]) {
+/// // The body was dropped.
+/// assert_eq!(literal.body(), b"");
+/// } else {
+/// unreachable!("We know it is a literal packet.");
+/// }
+/// # Ok(()) }
+/// ```
+///
+/// This example demonstrates how the body can be buffered by
+/// configuring the `PacketPileParser` to buffer all packet bodies:
+///
+/// ```rust
+/// # fn main() -> sequoia_openpgp::Result<()> {
+/// use std::convert::TryFrom;
+///
+/// use sequoia_openpgp as openpgp;
+/// use openpgp::Packet;
+/// use openpgp::parse::{Parse, PacketPileParser, PacketParserBuilder};
+///
+/// // By default, the `PacketPileParser` will drop packet bodies.
+/// // Use a `PacketParserBuilder` to change that.
+/// let mut ppb =
+/// PacketParserBuilder::from_bytes(
+/// b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?
+/// .buffer_unread_content();
+/// let mut ppp = PacketPileParser::try_from(ppb)?;
+/// while ppp.is_some() {
+/// // Start parsing the next packet, recursing.
+/// ppp.recurse()?;
+/// }
+///
+/// let pile = ppp.finish();
+/// // Process the packet.
+/// if let Some(Packet::Literal(literal)) = pile.path_ref(&[0]) {
+/// // The body was buffered.
+/// assert_eq!(literal.body(), b"Hello world.");
+/// } else {
+/// unreachable!("We know it is a literal packet.");
+/// }
+/// # Ok(()) }
+/// ```
+///
+/// This example demonstrates how the body can be buffered by
+/// buffering an individual packet:
+///
+/// ```rust
+/// # fn main() -> sequoia_openpgp::Result<()> {
+/// use sequoia_openpgp as openpgp;
+/// use openpgp::Packet;
+/// use openpgp::parse::{Parse, PacketPileParser};
+///
+/// // By default, the `PacketPileParser` will drop packet bodies.
+/// let mut ppp =
+/// PacketPileParser::from_bytes(
+/// b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?;
+/// while let Ok(pp) = ppp.as_mut() {
+/// if let Packet::Literal(_) = pp.packet {
+/// // Buffer this packet's body.
+/// pp.buffer_unread_content()?;
+/// }
+///
+/// // Start parsing the next packet, recursing.
+/// ppp.recurse()?;
+/// }
+///
+/// let pile = ppp.finish();
+/// // Process the packet.
+/// if let Some(Packet::Literal(literal)) = pile.path_ref(&[0]) {
+/// // The body was buffered.
+/// assert_eq!(literal.body(), b"Hello world.");
+/// } else {
+/// unreachable!("We know it is a literal packet.");
+/// }
+/// # Ok(()) }
+/// ```
+///
+/// This example demonstrates how to stream the packet body:
+///
+/// ```rust
+/// # fn main() -> sequoia_openpgp::Result<()> {
+/// use std::io::Read;
+///
+/// use sequoia_openpgp as openpgp;
+/// use openpgp::Packet;
+/// use openpgp::parse::{Parse, PacketPileParser};
+///
+/// // By default, the `PacketPileParser` will drop packet bodies.
+/// let mut ppp =
+/// PacketPileParser::from_bytes(
+/// b"\xcb\x12b\x00\x00\x00\x00\x00Hello world.")?;
+/// while let Ok(pp) = ppp.as_mut() {
+/// if let Packet::Literal(_) = pp.packet {
+/// // Stream the body.
+/// let mut buf = Vec::new();
+/// pp.read_to_end(&mut buf)?;
+/// assert_eq!(buf, b"Hello world.");
+/// }
+///
+/// // Start parsing the next packet, recursing.
+/// ppp.recurse()?;
+/// }
+///
+/// let pile = ppp.finish();
+/// // Process the packet.
+/// if let Some(Packet::Literal(literal)) = pile.path_ref(&[0]) {
+/// // The body was streamed, not buffered.
+/// assert_eq!(literal.body(), b"");
+/// } else {
+/// unreachable!("We know it is a literal packet.");
+/// }
+/// # Ok(()) }
/// ```
#[derive(Debug)]
pub struct PacketPileParser<'a> {
@@ -394,6 +511,8 @@ fn test_recurse() -> Result<()> {
ppp.recurse().unwrap();
}
assert_eq!(count, 61);
+ let pp = ppp.finish();
+ assert_eq!(pp.children().count(), 61);
Ok(())
}
@@ -407,6 +526,8 @@ fn test_next() -> Result<()> {
ppp.next().unwrap();
}
assert_eq!(count, 61);
+ let pp = ppp.finish();
+ assert_eq!(pp.children().count(), 61);
Ok(())
}