Skip to main content

Inspector

Trait Inspector 

Source
pub trait Inspector {
    // Provided methods
    fn part_start(&mut self, head: &PartHead<'_>) -> Verdict { ... }
    fn sniff(&mut self, head: &PartHead<'_>, first: &[u8]) -> Verdict { ... }
    fn data(&mut self, part: u32, chunk: &[u8]) -> Verdict { ... }
    fn field(&mut self, name: &str, value: &[u8]) -> Verdict { ... }
    fn part_end(&mut self, summary: &PartSummary) -> Verdict { ... }
    fn end(&mut self) -> Verdict { ... }
    fn failed(&mut self, error: &FormError) { ... }
}
Expand description

Takes part in a parse: called for every part head, the first bytes of every file, every data chunk, every complete text field, every part end, the end of the body, and once on any failure.

Every method has a default, so an inspector implements only what it checks.

Order guarantee, per part and at every split of the input:

part_start ─▶ sniff (file parts, when sniff_bytes > 0) ─▶ data* ─▶ field (text fields) ─▶ part_end
... after the last part: end
... on any error, at any point: failed (once), then the error is returned

For urlencoded bodies only field, end, and failed are called.

§Examples

use form_net::{Inspector, PartHead, Refusal, Verdict};

/// Allows only PNG and JPEG avatars, judged by their bytes.
struct ImagesOnly;

impl Inspector for ImagesOnly {
    fn part_start(&mut self, head: &PartHead<'_>) -> Verdict {
        match (head.name(), head.is_file()) {
            ("avatar", true) | ("title", false) => Verdict::Continue,
            _ => Verdict::Refuse(Refusal::new(422, "example.unexpected_field")),
        }
    }
    fn sniff(&mut self, _head: &PartHead<'_>, first: &[u8]) -> Verdict {
        if first.starts_with(b"\x89PNG\r\n\x1a\n") || first.starts_with(b"\xff\xd8\xff") {
            Verdict::Continue
        } else {
            Verdict::Refuse(Refusal::new(415, "example.avatar_not_image"))
        }
    }
}

Provided Methods§

Source

fn part_start(&mut self, head: &PartHead<'_>) -> Verdict

A part’s headers were read and passed every rule. Called before any byte of the part reaches a sink.

Source

fn sniff(&mut self, head: &PartHead<'_>, first: &[u8]) -> Verdict

The first min(sniff_bytes, part length) bytes of a file part, as one contiguous slice however the input was split, before any data call for that part.

Source

fn data(&mut self, part: u32, chunk: &[u8]) -> Verdict

Bytes of part part’s data, text fields included.

Source

fn field(&mut self, name: &str, value: &[u8]) -> Verdict

A complete text field (multipart) or a decoded pair (urlencoded): the value as bytes, so the inspector can apply its own charset rules. Skip leaves the field out of the result.

Source

fn part_end(&mut self, summary: &PartSummary) -> Verdict

A part ended. Skip here is treated as Continue.

Source

fn end(&mut self) -> Verdict

The body ended. Skip here is treated as Continue.

Source

fn failed(&mut self, error: &FormError)

The parse failed with error (for any reason, this inspector’s refusal included). Called once; it cannot change the outcome. The hook for security signals: a stream of refusals from one client is a probe.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementations on Foreign Types§

Source§

impl<A: Inspector, B: Inspector> Inspector for (A, B)

Two inspectors in one pass, self.0 first (D-088). A refusal from either wins and the second is not asked; otherwise the part is skipped if either says Skip. failed reaches both. Nest pairs for longer chains: (customs, (sentinel, app)).

§Examples

use form_net::{Inspector, Limits, Policy, Refusal, Verdict};

struct NoAdmin;
impl Inspector for NoAdmin {
    fn field(&mut self, _name: &str, value: &[u8]) -> Verdict {
        if value == b"admin" { Verdict::Refuse(Refusal::new(403, "app.admin")) } else { Verdict::Continue }
    }
}
struct Count(u32);
impl Inspector for Count {
    fn field(&mut self, _name: &str, _value: &[u8]) -> Verdict {
        self.0 += 1;
        Verdict::Continue
    }
}

let mut chain = (Count(0), NoAdmin);
let r = form_net::parse_urlencoded_inspected(b"a=1&b=admin", &Limits::DEFAULT, &Policy::DEFAULT, &mut chain);
assert_eq!(r.unwrap_err().status_hint(), 403);
assert_eq!(chain.0 .0, 2);
Source§

fn part_start(&mut self, head: &PartHead<'_>) -> Verdict

Source§

fn sniff(&mut self, head: &PartHead<'_>, first: &[u8]) -> Verdict

Source§

fn data(&mut self, part: u32, chunk: &[u8]) -> Verdict

Source§

fn field(&mut self, name: &str, value: &[u8]) -> Verdict

Source§

fn part_end(&mut self, summary: &PartSummary) -> Verdict

Source§

fn end(&mut self) -> Verdict

Source§

fn failed(&mut self, error: &FormError)

Source§

impl<I: Inspector + ?Sized> Inspector for &mut I

Source§

fn part_start(&mut self, head: &PartHead<'_>) -> Verdict

Source§

fn sniff(&mut self, head: &PartHead<'_>, first: &[u8]) -> Verdict

Source§

fn data(&mut self, part: u32, chunk: &[u8]) -> Verdict

Source§

fn field(&mut self, name: &str, value: &[u8]) -> Verdict

Source§

fn part_end(&mut self, summary: &PartSummary) -> Verdict

Source§

fn end(&mut self) -> Verdict

Source§

fn failed(&mut self, error: &FormError)

Source§

impl<I: Inspector + ?Sized> Inspector for Box<I>

Available on crate feature alloc only.

A boxed inspector, for a chain chosen at run time (D-088).

Source§

fn part_start(&mut self, head: &PartHead<'_>) -> Verdict

Source§

fn sniff(&mut self, head: &PartHead<'_>, first: &[u8]) -> Verdict

Source§

fn data(&mut self, part: u32, chunk: &[u8]) -> Verdict

Source§

fn field(&mut self, name: &str, value: &[u8]) -> Verdict

Source§

fn part_end(&mut self, summary: &PartSummary) -> Verdict

Source§

fn end(&mut self) -> Verdict

Source§

fn failed(&mut self, error: &FormError)

Implementors§