/// Queues a max size update. /// /// The next call to `encode` will include a dynamic size update frame. pubfn update_max_size(&mutself, val: usize) { matchself.size_update {
Some(SizeUpdate::One(old)) => { if val > old { if old > self.table.max_size() { self.size_update = Some(SizeUpdate::One(val));
} else { self.size_update = Some(SizeUpdate::Two(old, val));
}
} else { self.size_update = Some(SizeUpdate::One(val));
}
}
Some(SizeUpdate::Two(min, _)) => { if val < min { self.size_update = Some(SizeUpdate::One(val));
} else { self.size_update = Some(SizeUpdate::Two(min, val));
}
}
None => { if val != self.table.max_size() { // Don't bother writing a frame if the value already matches // the table's max size. self.size_update = Some(SizeUpdate::One(val));
}
}
}
}
/// Encode a set of headers into the provide buffer pubfn encode<I>(&mutself, headers: I, dst: &>mut BytesMut) where
I: IntoIterator<Item = Header<Option<HeaderName>>>,
{ let span = tracing::trace_span!("hpack::encode"); let _e = span.enter();
self.encode_size_updates(dst);
letmut last_index = None;
for header in headers { match header.reify() { // The header has an associated name. In which case, try to // index it in the table.
Ok(header) => { let index = self.table.index(header); self.encode_header(&index, dst);
last_index = Some(index);
} // The header does not have an associated name. This means that // the name is the same as the previously yielded header. In // which case, we skip table lookup and just use the same index // as the previous entry.
Err(value) => { self.encode_header_without_name(
last_index.as_ref().unwrap_or_else(|| {
panic!("encoding header without name, but no previous index to use for name");
}),
&value,
dst,
);
}
}
}
}
fn encode_str(val: &[u8], dst: &mut BytesMut) { if !val.is_empty() { let idx = position(dst);
// Push a placeholder byte for the length header
dst.put_u8(0);
// Encode with huffman
huffman::encode(val, dst);
let huff_len = position(dst) - (idx + 1);
if encode_int_one_byte(huff_len, 7) { // Write the string head
dst[idx] = 0x80 | huff_len as u8;
} else { // Write the head to a placeholder const PLACEHOLDER_LEN: usize = 8; letmut buf = [0u8; PLACEHOLDER_LEN];
// This is just done to reserve space in the destination
dst.put_slice(&buf[1..head_len]);
// Shift the header forward for i in0..huff_len { let src_i = idx + 1 + (huff_len - (i + 1)); let dst_i = idx + head_len + (huff_len - (i + 1));
dst[dst_i] = dst[src_i];
}
// Copy in the head for i in0..head_len {
dst[idx + i] = buf[i];
}
}
} else { // Write an empty string
dst.put_u8(0);
}
}
/// Encode an integer into the given destination buffer fn encode_int<B: BufMut>( mut value: usize, // The integer to encode
prefix_bits: usize, // The number of bits in the prefix
first_byte: u8, // The base upon which to start encoding the int
dst: &mut B,
) { if encode_int_one_byte(value, prefix_bits) {
dst.put_u8(first_byte | value as u8); return;
}
let low = (1 << prefix_bits) - 1;
value -= low;
dst.put_u8(first_byte | low as u8);
while value >= 128 {
dst.put_u8(0b1000_0000 | value as u8);
value >>= 7;
}
dst.put_u8(value as u8);
}
/// Returns true if the in the int can be fully encoded in the first byte. fn encode_int_one_byte(value: usize, prefix_bits: usize) -> bool {
value < (1 << prefix_bits) - 1
}
#[test] fn test_encode_indexed_name_literal_value() { letmut encoder = Encoder::default(); let res = encode(&mut encoder, vec![header("content-language", "foo")]);
assert_eq!(res[0], 0b01000000 | 27); // Indexed name
assert_eq!(res[1], 0x80 | 2); // header value w/ huffman coding
assert_eq!("foo", huff_decode(&res[2..4]));
// Same name, new value should still use incremental let res = encode(&mut encoder, vec![header("content-language", "bar")]);
assert_eq!(res[0], 0b01000000 | 27); // Indexed name
assert_eq!(res[1], 0x80 | 3); // header value w/ huffman coding
assert_eq!("bar", huff_decode(&res[2..5]));
}
#[test] fn test_repeated_headers_are_indexed() { letmut encoder = Encoder::default(); let res = encode(&mut encoder, vec![header("foo", "hello")]);
// Find existing headers for i in0..64 { let key = format!("x-hello-world-{:02}", i); let res = encode(&mut encoder, vec![header(&key, &key)]);
assert_eq!(0x80, res[0] & 0x80);
}
// Insert a new header let key = "x-hello-world-64"; let res = encode(&mut encoder, vec![header(key, key)]);
// Now try encoding entries that should exist in the table for i in1..65 { let key = format!("x-hello-world-{:02}", i); let res = encode(&mut encoder, vec![header(&key, &key)]);
assert_eq!(0x80 | (61 + (65 - i)), res[0]);
}
}
// Now, try to encode a sensitive header w/ a name in the static table let name = "authorization".parse().unwrap(); letmut value = HeaderValue::from_bytes(b"12345").unwrap();
value.set_sensitive(true);
let header = Header::Field {
name: Some(name),
value,
};
letmut encoder = Encoder::default(); let res = encode(&mut encoder, vec![header]);
#[test] fn test_encoding_headers_with_same_name() { letmut encoder = Encoder::default(); let name = "hello";
// Encode first one let _ = encode(&mut encoder, vec![header(name, "one")]);
// Encode second one let res = encode(&mut encoder, vec![header(name, "two")]);
assert_eq!(&[0x40 | 62, 0x80 | 3], &res[0..2]);
assert_eq!("two", huff_decode(&res[2..]));
assert_eq!(5, res.len());
// Encode the first one again let res = encode(&mut encoder, vec![header(name, "one")]);
assert_eq!(&[0x80 | 63], &res[..]);
// Now the second one let res = encode(&mut encoder, vec![header(name, "two")]);
assert_eq!(&[0x80 | 62], &res[..]);
}
#[test] fn test_evicting_headers_when_multiple_of_same_name_are_in_table() { // The encoder only has space for 2 headers letmut encoder = Encoder::new(76, 0);
let _ = encode(&mut encoder, vec![header("foo", "bar")]);
assert_eq!(1, encoder.table.len());
let _ = encode(&mut encoder, vec![header("bar", "foo")]);
assert_eq!(2, encoder.table.len());
// This will evict the first header, while still referencing the header // name let res = encode(&mut encoder, vec![header("foo", "baz")]);
assert_eq!(&[0x40 | 63, 0, 0x80 | 3], &res[..>3]);
assert_eq!(2, encoder.table.len());
// Try adding the same header again let res = encode(&mut encoder, vec![header("foo", "baz")]);
assert_eq!(&[0x80 | 62], &res[..]);
assert_eq!(2, encoder.table.len());
}
#[test] fn test_max_size_zero() { // Static table only letmut encoder = Encoder::new(0, 0); let res = encode(&mut encoder, vec![method("GET")]);
assert_eq!(*res, [0x80 | 2]);
assert_eq!(encoder.table.len(), 0);
fn header(name: &str, val: &str) -> Header<Option<HeaderName>> { let name = HeaderName::from_bytes(name.as_bytes()).unwrap(); let value = HeaderValue::from_bytes(val.as_bytes()).unwrap();
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.