Skip to content

Commit 5f8a7b4

Browse files
Improve request method parsing (#119)
Special-case parsing of the GET and POST request method as that is by far the most common. Speeds up the req_short benchmark by a fair margin: req_short/req_short time: [32.601 ns 32.737 ns 32.914 ns] thrpt: [1.9241 GiB/s 1.9345 GiB/s 1.9425 GiB/s] change: time: [-4.1113% -3.5415% -3.0150%] (p = 0.00 < 0.05) thrpt: [+3.1087% +3.6715% +4.2876%] Performance has improved. Co-authored-by: Luca Casonato <[email protected]> Co-authored-by: Ben Noordhuis <[email protected]>
1 parent aa6108b commit 5f8a7b4

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

src/iter.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,21 @@ impl<'a> Bytes<'a> {
2121

2222
#[inline]
2323
pub fn peek(&self) -> Option<u8> {
24-
self.slice.get(self.pos).cloned()
24+
self.peek_ahead(0)
25+
}
26+
27+
#[inline]
28+
pub fn peek_ahead(&self, n: usize) -> Option<u8> {
29+
self.slice.get(self.pos + n).cloned()
30+
}
31+
32+
#[inline]
33+
pub fn peek_4(&self) -> Option<&[u8]> {
34+
if self.slice.len() >= self.pos + 4 {
35+
Some(&self.slice[self.pos..=self.pos + 3])
36+
} else {
37+
None
38+
}
2539
}
2640

2741
#[inline]
@@ -62,6 +76,16 @@ impl<'a> Bytes<'a> {
6276
head
6377
}
6478

79+
#[inline]
80+
pub unsafe fn advance_and_commit(&mut self, n: usize) {
81+
debug_assert!(self.pos + n <= self.slice.len(), "overflow");
82+
self.pos += n;
83+
let ptr = self.slice.as_ptr();
84+
let tail = slice::from_raw_parts(ptr.add(n), self.slice.len() - n);
85+
self.pos = 0;
86+
self.slice = tail;
87+
}
88+
6589
#[inline]
6690
pub fn next_8<'b>(&'b mut self) -> Option<Bytes8<'b, 'a>> {
6791
if self.slice.len() >= self.pos + 8 {

src/lib.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,10 +475,25 @@ impl<'h, 'b> Request<'h, 'b> {
475475
config: &ParserConfig,
476476
mut headers: &'h mut [MaybeUninit<Header<'b>>],
477477
) -> Result<usize> {
478-
let orig_len = buf.len();
478+
let orig_len = buf.len();
479479
let mut bytes = Bytes::new(buf);
480480
complete!(skip_empty_lines(&mut bytes));
481-
self.method = Some(complete!(parse_token(&mut bytes)));
481+
let method = match bytes.peek_4() {
482+
Some(b"GET ") => {
483+
unsafe {
484+
bytes.advance_and_commit(4);
485+
}
486+
"GET"
487+
}
488+
Some(b"POST") if bytes.peek_ahead(4) == Some(b' ') => {
489+
unsafe {
490+
bytes.advance_and_commit(5);
491+
}
492+
"POST"
493+
}
494+
_ => complete!(parse_token(&mut bytes)),
495+
};
496+
self.method = Some(method);
482497
if config.allow_multiple_spaces_in_request_line_delimiters {
483498
complete!(skip_spaces(&mut bytes));
484499
}

0 commit comments

Comments
 (0)