base64_ng/stream/mod.rs
1//! Streaming Base64 wrappers for `std::io`.
2//!
3//! Decoder adapters fail closed after malformed Base64 input. Encoder writer
4//! adapters also expose failed-state diagnostics for unrecoverable internal
5//! queue/encoding errors. Use
6//! `is_failed()` for diagnostics; unchecked `into_inner()` remains
7//! available when the wrapped reader or writer must be explicitly
8//! recovered after a decode error.
9//!
10//! # Security
11//!
12//! Streaming decoders use the normal strict decode path. They preserve
13//! localized I/O-style errors and are not constant-time decoders. For
14//! secret-bearing frames where timing posture matters, collect the complete
15//! framed payload first and then use `base64_ng::ct`:
16//!
17//! Streaming decoder writers commit decoded bytes as quads are accepted. If a
18//! later quad in the same logical frame is malformed, valid leading decoded
19//! bytes may already have reached the wrapped writer before `finish()` reports
20//! failure. Callers that require atomic frame semantics must buffer the full
21//! encoded frame first and use a non-streaming decoder. Callers that use
22//! streaming decode for untrusted frames must not trust the wrapped writer's
23//! output until `finish()` succeeds, and can inspect [`Decoder::is_failed`] for
24//! diagnostics after each write.
25//!
26//! The streaming adapters use fixed stack buffers up to 1024 bytes for bounded
27//! I/O staging. This keeps heap behavior predictable, but callers embedding
28//! these adapters in constrained `std` environments should account for that
29//! stack footprint in deeply nested writer/reader chains.
30//!
31//! ```no_run
32//! use std::io::Read;
33//! use base64_ng::ct;
34//!
35//! const MAX_FRAME: usize = 4096;
36//!
37//! # fn decode_secret_frame<R: Read>(mut reader: R) -> Result<(), Box<dyn std::error::Error>> {
38//! let mut frame = Vec::new();
39//! reader.read_to_end(&mut frame)?;
40//! let decoded = ct::STANDARD.decode_buffer::<MAX_FRAME>(&frame)?;
41//! # let _ = decoded;
42//! # Ok(())
43//! # }
44//! ```
45//!
46//! ```
47//! use std::io::{Read, Write};
48//! use base64_ng::{STANDARD, stream::{Decoder, DecoderReader, Encoder, EncoderReader}};
49//!
50//! let mut encoder = Encoder::new(Vec::new(), STANDARD);
51//! encoder.write_all(b"he").unwrap();
52//! encoder.write_all(b"llo").unwrap();
53//! let encoded = encoder.finish().unwrap();
54//! assert_eq!(encoded, b"aGVsbG8=");
55//!
56//! let mut reader = EncoderReader::new(&b"hello"[..], STANDARD);
57//! let mut encoded = String::new();
58//! reader.read_to_string(&mut encoded).unwrap();
59//! assert_eq!(encoded, "aGVsbG8=");
60//!
61//! let mut decoder = Decoder::new(Vec::new(), STANDARD);
62//! decoder.write_all(b"aGVs").unwrap();
63//! decoder.write_all(b"bG8=").unwrap();
64//! let decoded = decoder.finish().unwrap();
65//! assert_eq!(decoded, b"hello");
66//!
67//! let mut reader = DecoderReader::new(&b"aGVsbG8="[..], STANDARD);
68//! let mut decoded = Vec::new();
69//! reader.read_to_end(&mut decoded).unwrap();
70//! assert_eq!(decoded, b"hello");
71//! ```
72
73mod common;
74mod decoder;
75mod decoder_reader;
76mod encoder;
77mod encoder_reader;
78mod queue;
79
80pub use decoder::Decoder;
81pub use decoder_reader::DecoderReader;
82pub use encoder::Encoder;
83pub use encoder_reader::EncoderReader;
84
85use common::{
86 decode_error_to_io, encode_error_to_io, redacted_inner_state, stream_decoder_failed_error,
87 stream_encoder_failed_error, trailing_input_after_padding_error,
88};
89use queue::OutputQueue;