Struct sequoia_openpgp::parse::PacketPileParser

source ·
pub struct PacketPileParser<'a> { /* private fields */ }
Expand description

Parses an OpenPGP stream with the convenience of PacketPile::from_file and the flexibility of a PacketParser.

Like PacketPile::from_file (and unlike PacketParser), a PacketPileParser parses an OpenPGP message and returns a PacketPile. But, unlike PacketPile::from_file (and like PacketParser), it allows the caller to inspect each packet as it is being parsed.

Thus, using a PacketPileParser, it is possible to decide on a per-packet basis whether to stream, buffer or drop the packet’s body, whether to recurse into a container, or whether to abort processing, for example. And, PacketPileParser conveniently packs the packets into a PacketPile.

If old packets don’t need to be retained, then PacketParser should be preferred. If no per-packet processing needs to be done, then PacketPile::from_file will be slightly faster.

§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:

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 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 dropped.
    assert_eq!(literal.body(), b"");
} else {
    unreachable!("We know it is a literal packet.");
}

This example demonstrates how the body can be buffered by configuring the PacketPileParser to buffer all packet bodies:

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.");
}

This example demonstrates how the body can be buffered by buffering an individual packet:

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.");
}

This example demonstrates how to stream the packet body:

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.");
}

Implementations§

source§

impl<'a> PacketPileParser<'a>

source

pub fn recurse(&mut self) -> Result<()>

Finishes parsing the current packet and starts parsing the next one, recursing if possible.

This method is similar to the next() method (see that method for more details), but if the current packet is a container (and we haven’t reached the maximum recursion depth, and the user hasn’t started reading the packet’s contents), we recurse into the container, and return a PacketParser for its first child. Otherwise, we return the next packet in the packet stream. If this function recurses, then the new packet’s recursion depth will be last_recursion_depth() + 1; because we always visit interior nodes, we can’t recurse more than one level at a time.

§Examples
use sequoia_openpgp as openpgp;
use openpgp::parse::{Parse, PacketPileParser};

// Parse a message.
let message_data: &[u8] = // ...
let mut ppp = PacketPileParser::from_bytes(message_data)?;
while let Ok(pp) = ppp.as_ref() {
    // Do something interesting with `pp` here.

    // Start parsing the next packet, recursing.
    ppp.recurse()?;
}

let pile = ppp.finish();
source

pub fn next(&mut self) -> Result<()>

Finishes parsing the current packet and starts parsing the next one.

This function finishes parsing the current packet. By default, any unread content is dropped. (See PacketParsererBuilder for how to configure this.) It then creates a new packet parser for the next packet. If the current packet is a container, this function does not recurse into the container, but skips any packets it contains. To recurse into the container, use the recurse() method.

§Examples
use sequoia_openpgp as openpgp;
use openpgp::parse::{Parse, PacketPileParser};

// Parse a message.
let message_data: &[u8] = // ...
let mut ppp = PacketPileParser::from_bytes(message_data)?;
while let Ok(pp) = ppp.as_ref() {
    // Do something interesting with `pp` here.

    // Start parsing the next packet.
    ppp.next()?;
}

let pile = ppp.finish();
source

pub fn recursion_depth(&self) -> Option<isize>

Returns the current packet’s recursion depth.

A top-level packet has a recursion depth of 0. Packets in a top-level container have a recursion depth of 1. Etc.

§Examples
use sequoia_openpgp as openpgp;
use openpgp::Packet;
use openpgp::parse::{Parse, PacketPileParser};

// Parse a simple compressed message.
let message_data: &[u8] = // ...
let mut ppp = PacketPileParser::from_bytes(message_data)?;
while let Ok(pp) = ppp.as_ref() {
    match pp.packet {
        Packet::CompressedData(_) =>
            assert_eq!(ppp.recursion_depth(), Some(0)),
        Packet::Literal(_) =>
            assert_eq!(ppp.recursion_depth(), Some(1)),
        _ => unreachable!(),
    }

    // Alternatively, the recursion depth can be queried
    // from the packet parser.
    assert_eq!(ppp.recursion_depth(), Some(pp.recursion_depth()));

    // Start parsing the next packet.
    ppp.next()?;
}

let pile = ppp.finish();
source

pub fn is_done(&self) -> bool

Returns whether the message has been completely parsed.

§Examples
use sequoia_openpgp as openpgp;
use openpgp::Packet;
use openpgp::parse::{Parse, PacketPileParser};

// Parse a message.
let message_data: &[u8] = // ...
let mut ppp = PacketPileParser::from_bytes(message_data)?;
while ppp.is_some() {
    // Start parsing the next packet.
    ppp.next()?;
}

assert!(ppp.is_done());
let pile = ppp.finish();
source

pub fn finish(self) -> PacketPile

Finishes parsing the message and returns the assembled PacketPile.

This function can be called at any time, not only when the message has been completely parsed. If the packet sequence has not been completely parsed, this function aborts processing, and the returned PacketPile just contains those packets that were completely processed; the packet that is currently being processed is not included in the PacketPile.

§Examples
use sequoia_openpgp as openpgp;
use openpgp::Packet;
use openpgp::parse::{Parse, PacketPileParser};

// Parse a message.
let message_data: &[u8] = // ...
let mut ppp = PacketPileParser::from_bytes(message_data)?;
ppp.next()?;

let pp = ppp.finish();
assert_eq!(pp.children().count(), 1);

Methods from Deref<Target = PacketParserResult<'a>>§

source

pub fn is_eof(&self) -> bool

Returns true if the result is EOF.

source

pub fn is_some(&self) -> bool

Returns true if the result is Some.

source

pub fn as_ref(&self) -> StdResult<&PacketParser<'a>, &PacketParserEOF<'_>>

Converts from PacketParserResult to Result<&PacketParser, &PacketParserEOF>.

Produces a new Result, containing references into the original PacketParserResult, leaving the original in place.

source

pub fn as_mut( &mut self ) -> StdResult<&mut PacketParser<'a>, &mut PacketParserEOF<'a>>

Converts from PacketParserResult to Result<&mut PacketParser, &mut PacketParserEOF>.

Produces a new Result, containing mutable references into the original PacketParserResult, leaving the original in place.

source

pub fn take(&mut self) -> Self

Takes the value out of the PacketParserResult, leaving a EOF in its place.

The EOF left in place carries a PacketParserEOF with default values.

Trait Implementations§

source§

impl<'a> Debug for PacketPileParser<'a>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'a> DerefMut for PacketPileParser<'a>

source§

fn deref_mut(&mut self) -> &mut Self::Target

Mutably dereferences the value.
source§

impl<'a> Parse<'a, PacketPileParser<'a>> for PacketPileParser<'a>

source§

fn from_reader<R: Read + 'a + Send + Sync>( reader: R ) -> Result<PacketPileParser<'a>>

Creates a PacketPileParser to parse the OpenPGP message stored in the io::Read object.

source§

fn from_file<P: AsRef<Path>>(path: P) -> Result<PacketPileParser<'a>>

Creates a PacketPileParser to parse the OpenPGP message stored in the file named by path.

source§

fn from_bytes<D: AsRef<[u8]> + ?Sized + Send + Sync>( data: &'a D ) -> Result<PacketPileParser<'a>>

Creates a PacketPileParser to parse the OpenPGP message stored in the provided buffer.

source§

fn from_buffered_reader<R>(reader: R) -> Result<PacketPileParser<'a>>
where R: BufferedReader<Cookie> + 'a,

Reads from the given buffered reader.
source§

impl<'a> TryFrom<PacketParserBuilder<'a>> for PacketPileParser<'a>

source§

fn try_from(ppb: PacketParserBuilder<'a>) -> Result<PacketPileParser<'a>>

Finishes configuring the PacketParser and returns a PacketPileParser.

§

type Error = Error

The type returned in the event of a conversion error.
source§

impl<'a> Deref for PacketPileParser<'a>

§

type Target = PacketParserResult<'a>

The resulting type after dereferencing.
source§

fn deref(&self) -> &Self::Target

Dereferences the value.

Auto Trait Implementations§

§

impl<'a> !Freeze for PacketPileParser<'a>

§

impl<'a> !RefUnwindSafe for PacketPileParser<'a>

§

impl<'a> Send for PacketPileParser<'a>

§

impl<'a> Sync for PacketPileParser<'a>

§

impl<'a> Unpin for PacketPileParser<'a>

§

impl<'a> !UnwindSafe for PacketPileParser<'a>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.