1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use crate::huffman;
use crate::io::SliceReader;
use crate::Result;
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::borrow::Cow;
use std::io::{Read, Write};
use std::u16;
use trackable::error::Failed;
pub(crate) fn encode_u16<W: Write>(
mut writer: W,
prepended_value: u8,
prefix_bits: u8,
value: u16,
) -> Result<()> {
debug_assert!(1 <= prefix_bits && prefix_bits <= 8);
let max_prefix_value: u16 = (1 << prefix_bits) - 1;
if value < max_prefix_value {
let first_octet = (((prepended_value as u16) << prefix_bits) | value) as u8;
track_io!(writer.write_u8(first_octet))?;
} else {
let first_octet = (prepended_value << prefix_bits) | (max_prefix_value as u8);
track_io!(writer.write_u8(first_octet))?;
let mut value = value - max_prefix_value;
while value >= 128 {
track_io!(writer.write_u8((value % 128 + 128) as u8))?;
value /= 128;
}
track_io!(writer.write_u8(value as u8))?;
}
Ok(())
}
pub(crate) fn decode_u16<R: Read>(mut reader: R, prefix_bits: u8) -> Result<(u8, u16)> {
debug_assert!(1 <= prefix_bits && prefix_bits <= 8);
let max_prefix_value: u16 = (1 << prefix_bits) - 1;
let first_octet = track_io!(reader.read_u8())?;
let prepended_value = ((first_octet as u16) >> prefix_bits) as u8;
let mut value = first_octet as u16 & max_prefix_value;
if value == max_prefix_value {
let mut offset = 0;
let mut octet = 128;
while octet & 128 == 128 {
octet = track_io!(reader.read_u8())?;
let addition = (octet as u16 & 127) << offset;
value = track_assert_some!(
value.checked_add(addition),
Failed,
"Too large integer: {}",
value as u32 + addition as u32
);
offset += 7;
}
}
Ok((prepended_value, value))
}
#[derive(Debug)]
#[allow(missing_docs)]
pub enum HpackString<'a> {
Plain(Cow<'a, [u8]>),
Huffman(Cow<'a, [u8]>),
}
impl<'a> HpackString<'a> {
pub(crate) fn to_plain_bytes(&self) -> Result<Cow<[u8]>> {
match *self {
HpackString::Plain(ref x) => Ok(Cow::Borrowed(x.as_ref())),
HpackString::Huffman(ref x) => Ok(Cow::Owned(track!(huffman::decode(x))?)),
}
}
pub(crate) fn into_plain_bytes(self) -> Result<Cow<'a, [u8]>> {
match self {
HpackString::Plain(x) => Ok(x),
HpackString::Huffman(x) => Ok(Cow::Owned(track!(huffman::decode(x.as_ref()))?)),
}
}
pub(crate) fn encode<W: Write>(&self, mut writer: W) -> Result<()> {
let (encoding, octets) = match *self {
HpackString::Plain(ref x) => (0, x.as_ref()),
HpackString::Huffman(ref x) => (1, x.as_ref()),
};
debug_assert!(octets.len() <= u16::MAX as usize);
track!(encode_u16(&mut writer, encoding, 7, octets.len() as u16))?;
track_io!(writer.write_all(octets))?;
Ok(())
}
pub(crate) fn decode(mut reader: &mut SliceReader<'a>) -> Result<Self> {
let (encoding, octets_len) = track!(decode_u16(&mut reader, 7))?;
let octets = Cow::Borrowed(track!(reader.read_slice(octets_len as usize))?);
if encoding == 0 {
Ok(HpackString::Plain(octets))
} else {
Ok(HpackString::Huffman(octets))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encoding_10_using_a_5bit_prefix() {
let mut buf = [0; 1];
track_try_unwrap!(encode_u16(&mut buf[..], 0b110, 5, 10));
assert_eq!(buf, [0b110_01010]);
let (prepended, value) = track_try_unwrap!(decode_u16(&buf[..], 5));
assert_eq!(prepended, 0b110);
assert_eq!(value, 10);
}
#[test]
fn encoding_1337_using_a_5bit_prefix() {
let mut buf = [0; 3];
track_try_unwrap!(encode_u16(&mut buf[..], 0b110, 5, 1337));
assert_eq!(buf, [0b110_11111, 0b10011010, 0b00001010]);
let (prepended, value) = track_try_unwrap!(decode_u16(&buf[..], 5));
assert_eq!(prepended, 0b110);
assert_eq!(value, 1337);
}
#[test]
fn encoding_42_starting_at_an_octet_boundary() {
let mut buf = [0; 1];
track_try_unwrap!(encode_u16(&mut buf[..], 0, 8, 42));
assert_eq!(buf, [0b00101010]);
let (prepended, value) = track_try_unwrap!(decode_u16(&buf[..], 8));
assert_eq!(prepended, 0);
assert_eq!(value, 42);
}
}