Skip to content

Commit 85549fc

Browse files
authored
fix header parsing: consume buf only if header name and value are both decoded
Decoding error when processing continuation header which contains normal header name at boundary
1 parent 7bb1462 commit 85549fc

File tree

1 file changed

+94
-7
lines changed

1 file changed

+94
-7
lines changed

src/hpack/decoder.rs

+94-7
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ struct Table {
142142
max_size: usize,
143143
}
144144

145+
struct StringMarker {
146+
offset: usize,
147+
len: usize,
148+
string: Option<Bytes>,
149+
}
150+
145151
// ===== impl Decoder =====
146152

147153
impl Decoder {
@@ -279,10 +285,13 @@ impl Decoder {
279285

280286
// First, read the header name
281287
if table_idx == 0 {
288+
let old_pos = buf.position();
289+
let name_marker = self.try_decode_string(buf)?;
290+
let value_marker = self.try_decode_string(buf)?;
291+
buf.set_position(old_pos);
282292
// Read the name as a literal
283-
let name = self.decode_string(buf)?;
284-
let value = self.decode_string(buf)?;
285-
293+
let name = name_marker.consume(buf);
294+
let value = value_marker.consume(buf);
286295
Header::new(name, value)
287296
} else {
288297
let e = self.table.get(table_idx)?;
@@ -292,7 +301,11 @@ impl Decoder {
292301
}
293302
}
294303

295-
fn decode_string(&mut self, buf: &mut Cursor<&mut BytesMut>) -> Result<Bytes, DecoderError> {
304+
fn try_decode_string(
305+
&mut self,
306+
buf: &mut Cursor<&mut BytesMut>,
307+
) -> Result<StringMarker, DecoderError> {
308+
let old_pos = buf.position();
296309
const HUFF_FLAG: u8 = 0b1000_0000;
297310

298311
// The first bit in the first byte contains the huffman encoded flag.
@@ -309,17 +322,34 @@ impl Decoder {
309322
return Err(DecoderError::NeedMore(NeedMore::StringUnderflow));
310323
}
311324

325+
let offset = (buf.position() - old_pos) as usize;
312326
if huff {
313327
let ret = {
314328
let raw = &buf.chunk()[..len];
315-
huffman::decode(raw, &mut self.buffer).map(BytesMut::freeze)
329+
huffman::decode(raw, &mut self.buffer).map(|buf| StringMarker {
330+
offset,
331+
len,
332+
string: Some(BytesMut::freeze(buf)),
333+
})
316334
};
317335

318336
buf.advance(len);
319-
return ret;
337+
ret
338+
} else {
339+
buf.advance(len);
340+
Ok(StringMarker {
341+
offset,
342+
len,
343+
string: None,
344+
})
320345
}
346+
}
321347

322-
Ok(take(buf, len))
348+
fn decode_string(&mut self, buf: &mut Cursor<&mut BytesMut>) -> Result<Bytes, DecoderError> {
349+
let old_pos = buf.position();
350+
let marker = self.try_decode_string(buf)?;
351+
buf.set_position(old_pos);
352+
Ok(marker.consume(buf))
323353
}
324354
}
325355

@@ -433,6 +463,19 @@ fn take(buf: &mut Cursor<&mut BytesMut>, n: usize) -> Bytes {
433463
head.freeze()
434464
}
435465

466+
impl StringMarker {
467+
fn consume(self, buf: &mut Cursor<&mut BytesMut>) -> Bytes {
468+
buf.advance(self.offset);
469+
match self.string {
470+
Some(string) => {
471+
buf.advance(self.len);
472+
string
473+
}
474+
None => take(buf, self.len),
475+
}
476+
}
477+
}
478+
436479
fn consume(buf: &mut Cursor<&mut BytesMut>) {
437480
// remove bytes from the internal BytesMut when they have been successfully
438481
// decoded. This is a more permanent cursor position, which will be
@@ -850,4 +893,48 @@ mod test {
850893
huffman::encode(src, &mut buf);
851894
buf
852895
}
896+
897+
#[test]
898+
fn test_decode_continuation_header_with_non_huff_encoded_name() {
899+
let mut de = Decoder::new(0);
900+
let value = huff_encode(b"bar");
901+
let mut buf = BytesMut::new();
902+
// header name is non_huff encoded
903+
buf.extend(&[0b01000000, 0x00 | 3]);
904+
buf.extend(b"foo");
905+
// header value is partial
906+
buf.extend(&[0x80 | 3]);
907+
buf.extend(&value[0..1]);
908+
909+
let mut res = vec![];
910+
let e = de
911+
.decode(&mut Cursor::new(&mut buf), |h| {
912+
res.push(h);
913+
})
914+
.unwrap_err();
915+
// decode error because the header value is partial
916+
assert_eq!(e, DecoderError::NeedMore(NeedMore::StringUnderflow));
917+
918+
// extend buf with the remaining header value
919+
buf.extend(&value[1..]);
920+
let _ = de
921+
.decode(&mut Cursor::new(&mut buf), |h| {
922+
res.push(h);
923+
})
924+
.unwrap();
925+
926+
assert_eq!(res.len(), 1);
927+
assert_eq!(de.table.size(), 0);
928+
929+
match res[0] {
930+
Header::Field {
931+
ref name,
932+
ref value,
933+
} => {
934+
assert_eq!(name, "foo");
935+
assert_eq!(value, "bar");
936+
}
937+
_ => panic!(),
938+
}
939+
}
853940
}

0 commit comments

Comments
 (0)