for (text_expected, base64data) in tests.iter() { // Read n bytes at a time. for n in1..base64data.len() + 1 { letmut wrapped_reader = io::Cursor::new(base64data); letmut decoder = DecoderReader::new(&mut wrapped_reader, &STANDARD);
// handle errors as you normally would letmut text_got = Vec::new(); letmut buffer = vec![0u8; n]; whilelet Ok(read) = decoder.read(&mut buffer[..]) { if read == 0 { break;
}
text_got.extend_from_slice(&buffer[..read]);
}
// Make sure we error out on trailing junk. #[test] fn trailing_junk() { let tests: &[&[u8]] = &[&b"MDEyMzQ1Njc4*!@#$%^&"[..], b"MDEyMzQ1Njc4OQ== "][..];
for base64data in tests.iter() { // Read n bytes at a time. for n in1..base64data.len() + 1 { letmut wrapped_reader = io::Cursor::new(base64data); letmut decoder = DecoderReader::new(&mut wrapped_reader, &STANDARD);
// handle errors as you normally would letmut buffer = vec![0u8; n]; letmut saw_error = false; loop { match decoder.read(&mut buffer[..]) {
Err(_) => {
saw_error = true; break;
}
Ok(read) if read == 0 => break,
Ok(_) => (),
}
}
for _ in0..10_000 {
bytes.clear();
b64.clear();
decoded.clear();
let size = rng.gen_range(0..(10 * BUF_SIZE));
bytes.extend(iter::repeat(0).take(size)); // leave room to play around with larger buffers
decoded.extend(iter::repeat(0).take(size * 3));
for _ in0..10_000 {
bytes.clear();
b64.clear();
decoded.clear();
let size = rng.gen_range(0..(10 * BUF_SIZE));
bytes.extend(iter::repeat(0).take(size)); // leave room to play around with larger buffers
decoded.extend(iter::repeat(0).take(size * 3));
let config = random_config(&mut rng); let alphabet = random_alphabet(&mut rng); // changing padding will cause invalid padding errors when we twiddle the last byte let engine = GeneralPurpose::new(alphabet, config.with_encode_padding(false));
engine.encode_string(&bytes[..], &mut b64);
b64_bytes.extend(b64.bytes());
assert_eq!(b64_bytes.len(), b64.len());
// change the last character to every possible symbol. Should behave the same as bulk // decoding whether invalid or valid. for &s1 in alphabet.symbols.iter() {
decoded.clear();
bulk_decoded.clear();
// replace the last
*b64_bytes.last_mut().unwrap() = s1; let bulk_res = engine.decode_vec(&b64_bytes[..], &mut bulk_decoded);
let engine = GeneralPurpose::new(&alphabet::STANDARD, random_config(&mut rng));
engine.encode_string(&bytes[..], &mut b64); // replace one byte, somewhere, with '*', which is invalid let bad_byte_pos = rng.gen_range(0..b64.len()); letmut b64_bytes = b64.bytes().collect::<Vec<u8>>();
b64_bytes[bad_byte_pos] = b'*';
let read_decode_err = decoder
.read_to_end(&mut stream_decoded)
.map_err(|e| { let kind = e.kind(); let inner = e
.into_inner()
.and_then(|e| e.downcast::<DecodeError>().ok());
inner.map(|i| (*i, kind))
})
.err()
.and_then(|o| o);
let bulk_decode_err = engine.decode_vec(&b64_bytes[..], &mut bulk_decoded).err();
// it's tricky to predict where the invalid data's offset will be since if it's in the last // chunk it will be reported at the first padding location because it's treated as invalid // padding. So, we just check that it's the same as it is for decoding all at once.
assert_eq!(
bulk_decode_err.map(|e| (e, io::ErrorKind::InvalidData)),
read_decode_err
);
}
}
// encodes with padding, requires that padding be present so we don't get InvalidPadding // just because padding is there at all let engine = STANDARD;
for _ in0..10_000 {
bytes.clear();
b64.clear();
reader_decoded.clear();
bulk_decoded.clear();
// at least 2 bytes so there can be a split point between bytes let size = rng.gen_range(2..(10 * BUF_SIZE));
bytes.resize(size, 0);
rng.fill_bytes(&mut bytes[..size]);
// Concatenate two valid b64s, yielding padding in the middle. // This avoids scenarios that are challenging to assert on, like random padding location // that might be InvalidLastSymbol when decoded at certain buffer sizes but InvalidByte // when done all at once. let split = loop { // find a split point that will produce padding on the first part let s = rng.gen_range(1..size); if s % 3 != 0 { // short enough to need padding break s;
};
};
// short read to make it plausible for padding to happen on a read boundary let read_len = rng.gen_range(1..10); letmut wrapped_reader = ShortRead {
max_read_len: read_len,
delegate: io::Cursor::new(&b64_bytes),
};
// encodes with padding, requires that padding be present so we don't get InvalidPadding // just because padding is there at all let engine = STANDARD;
for _ in0..10_000 {
bytes.clear();
b64.clear();
reader_decoded.clear();
// Just shove a padding byte in there somewhere. // The specific error to expect is challenging to predict precisely because it // will vary based on the position of the padding in the quad and the read buffer // length, but SOMETHING should go wrong.
engine.encode_string(&bytes[..], &mut b64); letmut b64_bytes = b64.as_bytes().to_vec(); // put padding somewhere other than the last quad
b64_bytes[rng.gen_range(0..bytes.len() - 4)] = PAD_BYTE;
// short read to make it plausible for padding to happen on a read boundary let read_len = rng.gen_range(1..10); letmut wrapped_reader = ShortRead {
max_read_len: read_len,
delegate: io::Cursor::new(&b64_bytes),
};
/// Limits how many bytes a reader will provide in each read call. /// Useful for shaking out code that may work fine only with typical input sources that always fill /// the buffer. struct RandomShortRead<'a, 'b, R: io::Read, N: rand::Rng> {
delegate: &'b mut R,
rng: &'a mut N,
}
impl<'a, 'b, R: io::Read, N: rand::Rng> io::Read for RandomShortRead<'a, 'b, R, N> { fn read(&mutself, buf: &mut [u8]) -> Result<usize, io::Error> { // avoid 0 since it means EOF for non-empty buffers let effective_len = cmp::min(self.rng.gen_range(1..20), buf.len());
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.