#![allow(dead_code)]
use byte::is_token;
use fsm::{ ParserValue,
Success };
use byte_slice::ByteStream;
use std::fmt;
const FLAG_MASK: u32 = 0xF;
const FLAG_SHIFT: u8 = 0;
const LOWER14_MASK: u32 = 0x3FFF;
const LOWER14_SHIFT: u8 = 4;
const UPPER14_MASK: u32 = 0x3FFF;
const UPPER14_SHIFT: u8 = 18;
const F_CHUNKED: u32 = 1;
const F_CHUNK_EXTENSIONS: u32 = 1 << 1;
const F_MULTIPART: u32 = 1 << 2;
const F_URL_ENCODED: u32 = 1 << 3;
macro_rules! get_lower14 {
($parser:expr) => ({
($parser.bit_data >> LOWER14_SHIFT) & LOWER14_MASK
});
}
macro_rules! get_upper14 {
($parser:expr) => ({
($parser.bit_data >> UPPER14_SHIFT) & UPPER14_MASK
});
}
macro_rules! has_flag {
($parser:expr, $flag:expr) => ({
(($parser.bit_data >> FLAG_SHIFT) & FLAG_MASK) & $flag == $flag
});
}
macro_rules! inc_lower14 {
($parser:expr, $length:expr) => ({
set_lower14!(
$parser,
get_lower14!($parser) as usize + $length as usize
);
});
}
macro_rules! inc_upper14 {
($parser:expr, $length:expr) => ({
set_upper14!(
$parser,
get_upper14!($parser) as usize + $length as usize
);
});
}
macro_rules! set_flag {
($parser:expr, $flag:expr) => ({
$parser.bit_data |= ($flag & FLAG_MASK) << FLAG_SHIFT;
});
}
macro_rules! set_lower14 {
($parser:expr, $bits:expr) => ({
let bits = $bits as u32;
$parser.bit_data &= !(LOWER14_MASK << LOWER14_SHIFT);
$parser.bit_data |= bits << LOWER14_SHIFT;
});
}
macro_rules! set_upper14 {
($parser:expr, $bits:expr) => ({
let bits = $bits as u32;
$parser.bit_data &= !(UPPER14_MASK << UPPER14_SHIFT);
$parser.bit_data |= bits << UPPER14_SHIFT;
});
}
macro_rules! unset_flag {
($parser:expr, $flag:expr) => ({
$parser.bit_data &= !(($flag & FLAG_MASK) << FLAG_SHIFT);
});
}
#[allow(unused_variables)]
pub trait HttpHandler {
fn content_length(&mut self) -> Option<usize> {
None
}
fn on_body_finished(&mut self) -> bool {
true
}
fn on_chunk_begin(&mut self) -> bool {
true
}
fn on_chunk_data(&mut self, data: &[u8]) -> bool {
true
}
fn on_chunk_extension_finished(&mut self) -> bool {
true
}
fn on_chunk_extension_name(&mut self, name: &[u8]) -> bool {
true
}
fn on_chunk_extension_value(&mut self, value: &[u8]) -> bool {
true
}
fn on_chunk_extensions_finished(&mut self) -> bool {
true
}
fn on_chunk_length(&mut self, size: usize) -> bool {
true
}
fn on_header_name(&mut self, name: &[u8]) -> bool {
true
}
fn on_header_value(&mut self, value: &[u8]) -> bool {
true
}
fn on_headers_finished(&mut self) -> bool {
true
}
fn on_initial_finished(&mut self) -> bool {
true
}
fn on_method(&mut self, method: &[u8]) -> bool {
true
}
fn on_multipart_begin(&mut self) -> bool {
true
}
fn on_multipart_data(&mut self, data: &[u8]) -> bool {
true
}
fn on_status(&mut self, status: &[u8]) -> bool {
true
}
fn on_status_code(&mut self, code: u16) -> bool {
true
}
fn on_url(&mut self, url: &[u8]) -> bool {
true
}
fn on_url_encoded_name(&mut self, name: &[u8]) -> bool {
true
}
fn on_url_encoded_value(&mut self, value: &[u8]) -> bool {
true
}
fn on_version(&mut self, major: u16, minor: u16) -> bool {
true
}
}
#[derive(Clone,Copy,PartialEq)]
pub enum ParserError {
ChunkExtensionName(u8),
ChunkExtensionValue(u8),
ChunkLength(u8),
CrlfSequence(u8),
Dead,
HeaderName(u8),
HeaderValue(u8),
MaxChunkLength,
Method(u8),
Multipart(u8),
MultipartBoundary(u8),
Status(u8),
StatusCode(u8),
Url(u8),
UrlEncodedName(u8),
UrlEncodedValue(u8),
Version(u8),
}
impl fmt::Debug for ParserError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
ParserError::ChunkExtensionName(byte) => {
write!(
formatter,
"ParserError::ChunkExtensionName(Invalid chunk extension name on byte {})",
byte
)
},
ParserError::ChunkExtensionValue(byte) => {
write!(
formatter,
"ParserError::ChunkExtensionValue(Invalid chunk extension value on byte {})",
byte
)
},
ParserError::ChunkLength(byte) => {
write!(
formatter,
"ParserError::ChunkLength(Invalid chunk length on byte {})",
byte
)
},
ParserError::CrlfSequence(byte) => {
write!(
formatter,
"ParserError::CrlfSequence(Invalid CRLF sequence on byte {})",
byte
)
},
ParserError::Dead => {
write!(formatter, "ParserError::Dead(Parser is dead)")
},
ParserError::HeaderName(byte) => {
write!(
formatter,
"ParserError::HeaderName(Invalid header name on byte {})",
byte
)
},
ParserError::HeaderValue(byte) => {
write!(
formatter,
"ParserError::HeaderValue(Invalid header value on byte {})",
byte
)
},
ParserError::MaxChunkLength => {
write!(
formatter,
"ParserError::MaxChunkLength(Maximum chunk length has been met)"
)
},
ParserError::Method(byte) => {
write!(
formatter,
"ParserError::Method(Invalid method on byte {})",
byte
)
},
ParserError::Multipart(byte) => {
write!(
formatter,
"ParserError::Multipart(Invalid multipart data on byte {})",
byte
)
},
ParserError::MultipartBoundary(byte) => {
write!(
formatter,
"ParserError::MultipartBoundary(Invalid multipart boundary on byte {})",
byte
)
},
ParserError::Status(byte) => {
write!(
formatter,
"ParserError::Status(Invalid status on byte {})",
byte
)
},
ParserError::StatusCode(byte) => {
write!(
formatter,
"ParserError::StatusCode(Invalid status code on byte {})",
byte
)
},
ParserError::Url(byte) => {
write!(
formatter,
"ParserError::Url(Invalid URL on byte {})",
byte
)
},
ParserError::UrlEncodedName(byte) => {
write!(
formatter,
"ParserError::UrlEncodedName(Invalid URL encoded name on byte {})",
byte
)
},
ParserError::UrlEncodedValue(byte) => {
write!(
formatter,
"ParserError::UrlEncodedValue(Invalid URL encoded value on byte {})",
byte
)
},
ParserError::Version(byte) => {
write!(
formatter,
"ParserError::Version(Invalid HTTP version on byte {})",
byte
)
}
}
}
}
impl fmt::Display for ParserError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
ParserError::ChunkExtensionName(byte) => {
write!(
formatter,
"Invalid chunk extension name on byte {}",
byte
)
},
ParserError::ChunkExtensionValue(byte) => {
write!(
formatter,
"Invalid chunk extension value on byte {}",
byte
)
},
ParserError::ChunkLength(byte) => {
write!(
formatter,
"Invalid chunk length on byte {}",
byte
)
},
ParserError::CrlfSequence(byte) => {
write!(
formatter,
"Invalid CRLF sequence on byte {}",
byte
)
},
ParserError::Dead => {
write!(
formatter,
"Parser is dead"
)
},
ParserError::HeaderName(byte) => {
write!(
formatter,
"Invalid header name on byte {}",
byte
)
},
ParserError::HeaderValue(byte) => {
write!(
formatter,
"Invalid header value on byte {}",
byte
)
},
ParserError::MaxChunkLength => {
write!(
formatter,
"Maximum chunk length has been met"
)
},
ParserError::Method(byte) => {
write!(
formatter,
"Invalid method on byte {}",
byte
)
},
ParserError::Multipart(byte) => {
write!(
formatter,
"Invalid multipart data on byte {}",
byte
)
},
ParserError::MultipartBoundary(byte) => {
write!(
formatter,
"Invalid multipart boundary on byte {}",
byte
)
},
ParserError::Status(byte) => {
write!(
formatter,
"Invalid status on byte {}",
byte
)
},
ParserError::StatusCode(byte) => {
write!(
formatter,
"Invalid status code on byte {}",
byte
)
},
ParserError::Url(byte) => {
write!(
formatter,
"Invalid URL on byte {}",
byte
)
},
ParserError::UrlEncodedName(byte) => {
write!(
formatter,
"Invalid URL encoded name on byte {}",
byte
)
},
ParserError::UrlEncodedValue(byte) => {
write!(
formatter,
"Invalid URL encoded value on byte {}",
byte
)
},
ParserError::Version(byte) => {
write!(
formatter,
"Invalid HTTP version on byte {}",
byte
)
}
}
}
}
#[derive(Clone,Copy,Debug,PartialEq)]
#[repr(u8)]
pub enum ParserState {
Dead,
StripDetect,
Detect1,
Detect2,
Detect3,
Detect4,
Detect5,
UpperRequestMethod,
LowerRequestMethod,
StripRequestUrl,
RequestUrl,
StripRequestHttp,
RequestHttp1,
RequestHttp2,
RequestHttp3,
RequestHttp4,
RequestHttp5,
RequestVersionMajor,
RequestVersionMinor,
ResponseVersionMajor,
ResponseVersionMinor,
StripResponseStatusCode,
ResponseStatusCode,
StripResponseStatus,
ResponseStatus,
InitialEnd,
PreHeadersLf1,
PreHeadersCr2,
StripHeaderName,
FirstHeaderName,
UpperHeaderName,
LowerHeaderName,
StripHeaderValue,
HeaderValue,
HeaderQuotedValue,
HeaderEscapedValue,
HeaderCr1,
HeaderLf1,
HeaderCr2,
HeaderLf2,
ChunkLength1,
ChunkLength2,
ChunkLengthCr,
StripChunkExtensionName,
UpperChunkExtensionName,
LowerChunkExtensionName,
StripChunkExtensionValue,
ChunkExtensionValue,
ChunkExtensionQuotedValue,
ChunkExtensionQuotedValueFinished,
ChunkExtensionEscapedValue,
ChunkExtensionFinished,
ChunkLengthLf,
ChunkData,
ChunkDataCr1,
ChunkDataLf1,
MultipartHyphen1,
MultipartHyphen2,
MultipartBoundary,
MultipartDetectData,
MultipartDataByByte,
MultipartDataByLength,
MultipartDataByLengthCr,
MultipartDataByLengthLf,
MultipartDataByByteLf,
MultipartBoundaryCr,
MultipartBoundaryLf,
MultipartEnd,
UrlEncodedName,
UrlEncodedNameAmpersand,
UrlEncodedNameHex1,
UrlEncodedNameHex2,
UrlEncodedNamePlus,
UrlEncodedValue,
UrlEncodedValueHex1,
UrlEncodedValueHex2,
UrlEncodedValuePlus,
BodyFinished,
Finished
}
pub struct Parser<'a, T: 'a + HttpHandler> {
bit_data: u32,
boundary: Option<&'a [u8]>,
byte_count: usize,
length: usize,
parser_type: ParserType,
state: ParserState,
state_function: fn(&mut Parser<'a, T>, &mut T, &mut ByteStream)
-> Result<ParserValue, ParserError>
}
impl<'a, T: 'a + HttpHandler> Parser<'a, T> {
pub fn new() -> Parser<'a, T> {
Parser{
bit_data: 0,
boundary: None,
byte_count: 0,
length: 0,
parser_type: ParserType::Head,
state: ParserState::StripDetect,
state_function: Parser::strip_detect
}
}
pub fn init_chunked(&mut self) {
self.parser_type = ParserType::Chunked;
self.reset();
}
pub fn init_head(&mut self) {
self.parser_type = ParserType::Head;
self.reset();
}
pub fn init_multipart(&mut self) {
self.parser_type = ParserType::Multipart;
self.reset();
}
pub fn init_url_encoded(&mut self) {
self.parser_type = ParserType::UrlEncoded;
self.reset();
}
pub fn byte_count(&self) -> usize {
self.byte_count
}
#[inline]
fn parse(&mut self, mut handler: &mut T, mut context: &mut ByteStream)
-> Result<Success, ParserError> {
loop {
match (self.state_function)(self, &mut handler, &mut context) {
Ok(ParserValue::Continue) => {
},
Ok(ParserValue::Exit(success)) => {
self.byte_count += context.stream_index;
if let Success::Finished(_) = success {
self.state = ParserState::Finished;
}
return Ok(success);
},
Err(error) => {
self.byte_count += context.stream_index;
self.state = ParserState::Dead;
self.state_function = Parser::dead;
return Err(error);
}
}
}
}
pub fn reset(&mut self) {
self.bit_data = 0;
self.boundary = None;
self.length = 0;
match self.parser_type {
ParserType::Chunked => {
self.state = ParserState::ChunkLength1;
self.state_function = Parser::chunk_length1;
set_flag!(self, F_CHUNKED);
},
ParserType::Head => {
self.state = ParserState::StripDetect;
self.state_function = Parser::strip_detect;
},
ParserType::Multipart => {
self.state = ParserState::MultipartHyphen1;
self.state_function = Parser::multipart_hyphen1;
set_flag!(self, F_MULTIPART);
set_lower14!(self, 1);
},
ParserType::UrlEncoded => {
self.state = ParserState::UrlEncodedName;
self.state_function = Parser::url_encoded_name;
set_flag!(self, F_URL_ENCODED);
}
}
}
#[inline]
pub fn resume(&mut self, mut handler: &mut T, mut stream: &[u8])
-> Result<Success, ParserError> {
if has_flag!(self, F_URL_ENCODED) {
if self.length < stream.len() {
stream = &stream[0..self.length];
}
let mut context = ByteStream::new(stream);
match self.parse(&mut handler, &mut context) {
Ok(Success::Eos(length)) => {
if self.length - length == 0 {
self.state = ParserState::BodyFinished;
self.state_function = Parser::body_finished;
self.parse(&mut handler, &mut context)
} else {
self.length -= length;
Ok(Success::Eos(length))
}
},
Ok(Success::Callback(length)) => {
self.length -= length;
Ok(Success::Callback(length))
},
other => {
other
}
}
} else {
self.parse(&mut handler, &mut ByteStream::new(stream))
}
}
pub fn set_boundary(&mut self, boundary: &'a [u8]) {
self.boundary = Some(boundary);
}
pub fn set_length(&mut self, length: usize) {
self.length = length;
}
pub fn state(&self) -> ParserState {
self.state
}
#[inline]
fn strip_detect(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
consume_empty_space!(
context,
exit_eos!(self, context)
);
transition_fast!(
self,
handler,
context,
Detect1,
detect1
);
}
#[inline]
fn detect1(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
macro_rules! version {
($major:expr, $minor:expr, $length:expr) => ({
bs_jump!(context, $length);
set_state!(self, StripResponseStatusCode, strip_response_status_code
);
if handler.on_version($major, $minor) {
transition_fast!(self, handler, context);
} else {
exit_callback!(self, context);
}
});
}
if bs_starts_with1!(context, b"H") || bs_starts_with1!(context, b"h") {
if bs_has_bytes!(context, 9) {
if bs_starts_with9!(context, b"HTTP/1.1 ") {
version!(1, 1, 9);
} else if bs_starts_with9!(context, b"HTTP/2.0 ") {
version!(2, 0, 9);
} else if bs_starts_with9!(context, b"HTTP/1.0 ") {
version!(1, 0, 9);
} else if bs_starts_with5!(context, b"HTTP/") {
bs_jump!(context, 5);
transition_fast!(
self,
handler,
context,
ResponseVersionMajor,
response_version_major
);
}
} else {
bs_jump!(context, 1);
transition_fast!(
self,
handler,
context,
Detect2,
detect2
);
}
}
transition_fast!(
self,
handler,
context,
UpperRequestMethod,
upper_request_method
);
}
#[inline]
fn detect2(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'T' || context.byte == b't' {
transition_fast!(
self,
handler,
context,
Detect3,
detect3
);
} else {
bs_replay!(context);
callback_transition_fast!(
self,
handler,
context,
on_method,
b"H",
UpperRequestMethod,
upper_request_method
);
}
}
#[inline]
fn detect3(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'T' || context.byte == b't' {
transition_fast!(
self,
handler,
context,
Detect4,
detect4
);
} else {
bs_replay!(context);
callback_transition_fast!(
self,
handler,
context,
on_method,
b"HT",
UpperRequestMethod,
upper_request_method
);
}
}
#[inline]
fn detect4(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'P' || context.byte == b'p' {
transition_fast!(
self,
handler,
context,
Detect5,
detect5
);
} else {
bs_replay!(context);
callback_transition_fast!(
self,
handler,
context,
on_method,
b"HTT",
UpperRequestMethod,
upper_request_method
);
}
}
#[inline]
fn detect5(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'/' {
set_lower14!(self, 0);
set_upper14!(self, 0);
transition_fast!(
self,
handler,
context,
ResponseVersionMajor,
response_version_major
);
} else {
bs_replay!(context);
callback_transition_fast!(
self,
handler,
context,
on_method,
b"HTTP",
UpperRequestMethod,
upper_request_method
);
}
}
#[inline]
fn initial_end(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
set_state!(self, PreHeadersLf1, pre_headers_lf1);
if handler.on_initial_finished() {
transition_fast!(self, handler, context);
} else {
exit_callback!(self, context);
}
}
#[inline]
fn pre_headers_lf1(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\n' {
transition_fast!(
self,
handler,
context,
PreHeadersCr2,
pre_headers_cr2
);
} else {
exit_error!(CrlfSequence, context.byte);
}
}
#[inline]
fn pre_headers_cr2(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\r' {
transition_fast!(
self,
handler,
context,
HeaderLf2,
header_lf2
);
} else {
bs_replay!(context);
transition_fast!(
self,
handler,
context,
StripHeaderName,
strip_header_name
);
}
}
#[inline]
fn strip_header_name(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
consume_linear_space!(
context,
exit_eos!(self, context)
);
transition_fast!(
self,
handler,
context,
FirstHeaderName,
first_header_name
);
}
#[inline]
#[cfg_attr(test, allow(cyclomatic_complexity))]
fn first_header_name(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
macro_rules! name {
($header:expr, $length:expr) => ({
bs_jump!(context, $length);
callback_transition_fast!(
self,
handler,
context,
on_header_name,
$header,
StripHeaderValue,
strip_header_value
);
});
}
if bs_has_bytes!(context, 24) {
if context.byte == b'C' {
if bs_starts_with11!(context, b"Connection:") {
name!(b"connection", 11);
} else if bs_starts_with13!(context, b"Content-Type:") {
name!(b"content-type", 13);
} else if bs_starts_with15!(context, b"Content-Length:") {
name!(b"content-length", 15);
} else if bs_starts_with7!(context, b"Cookie:") {
name!(b"cookie", 7);
} else if bs_starts_with14!(context, b"Cache-Control:") {
name!(b"cache-control", 14);
} else if bs_starts_with24!(context, b"Content-Security-Policy:") {
name!(b"content-security-policy", 24);
}
} else if context.byte == b'A' {
if bs_starts_with7!(context, b"Accept:") {
name!(b"accept", 7);
} else if bs_starts_with15!(context, b"Accept-Charset:") {
name!(b"accept-charset", 15);
} else if bs_starts_with16!(context, b"Accept-Encoding:") {
name!(b"accept-encoding", 16);
} else if bs_starts_with16!(context, b"Accept-Language:") {
name!(b"accept-language", 16);
} else if bs_starts_with14!(context, b"Authorization:") {
name!(b"authorization", 14);
}
} else if context.byte == b'H' {
if bs_starts_with5!(context, b"Host:") {
name!(b"host", 5);
}
} else if context.byte == b'L' {
if bs_starts_with9!(context, b"Location:") {
name!(b"location", 9);
} else if bs_starts_with14!(context, b"Last-Modified:") {
name!(b"last-modified", 14);
}
} else if bs_starts_with7!(context, b"Pragma:") {
name!(b"pragma", 7);
} else if bs_starts_with11!(context, b"Set-Cookie:") {
name!(b"set-cookie", 11);
} else if bs_starts_with18!(context, b"Transfer-Encoding:") {
name!(b"transfer-encoding", 18);
} else if context.byte == b'U' {
if bs_starts_with11!(context, b"User-Agent:") {
name!(b"user-agent", 11);
} else if bs_starts_with8!(context, b"Upgrade:") {
name!(b"upgrade", 8);
}
} else if context.byte == b'X' {
if bs_starts_with13!(context, b"X-Powered-By:") {
name!(b"x-powered-by", 13);
} else if bs_starts_with16!(context, b"X-Forwarded-For:") {
name!(b"x-forwarded-for", 16);
} else if bs_starts_with17!(context, b"X-Forwarded-Host:") {
name!(b"x-forwarded-host", 17);
} else if bs_starts_with17!(context, b"X-XSS-Protection:") {
name!(b"x-xss-protection", 17);
} else if bs_starts_with13!(context, b"X-WebKit-CSP:") {
name!(b"x-webkit-csp", 13);
}
} else if bs_starts_with17!(context, b"WWW-Authenticate:") {
name!(b"www-authenticate", 17);
}
}
transition_fast!(
self,
handler,
context,
UpperHeaderName,
upper_header_name
);
}
#[inline]
fn upper_header_name(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte > 0x40 && context.byte < 0x5B {
callback_transition_fast!(
self,
handler,
context,
on_header_name,
&[context.byte + 0x20],
LowerHeaderName,
lower_header_name
);
} else {
bs_replay!(context);
transition_fast!(
self,
handler,
context,
LowerHeaderName,
lower_header_name
);
}
}
#[inline]
fn lower_header_name(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
collect_tokens!(
context,
ParserError::HeaderName,
context.byte == b':'
|| (context.byte > 0x40 && context.byte < 0x5B),
callback_eos_expr!(self, handler, context, on_header_name)
);
if context.byte == b':' {
callback_ignore_transition!(
self,
handler,
context,
on_header_name,
StripHeaderValue,
strip_header_value
);
} else {
bs_replay!(context);
callback_transition!(
self,
handler,
context,
on_header_name,
UpperHeaderName,
upper_header_name
);
}
}
#[inline]
fn strip_header_value(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
consume_linear_space!(
context,
exit_eos!(self, context)
);
bs_next!(context);
if context.byte == b'"' {
transition_fast!(
self,
handler,
context,
HeaderQuotedValue,
header_quoted_value
);
} else {
bs_replay!(context);
transition_fast!(
self,
handler,
context,
HeaderValue,
header_value
);
}
}
#[inline]
fn header_value(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
collect_field!(
context,
ParserError::HeaderValue,
context.byte == b'\r',
callback_eos_expr!(self, handler, context, on_header_value)
);
callback_ignore_transition_fast!(
self,
handler,
context,
on_header_value,
HeaderLf1,
header_lf1
);
}
#[inline]
fn header_quoted_value(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
collect_quoted!(
context,
ParserError::HeaderValue,
callback_eos_expr!(self, handler, context, on_header_value)
);
if context.byte == b'"' {
callback_ignore_transition_fast!(
self,
handler,
context,
on_header_value,
HeaderCr1,
header_cr1
);
} else {
callback_ignore_transition_fast!(
self,
handler,
context,
on_header_value,
HeaderEscapedValue,
header_escaped_value
);
}
}
#[inline]
fn header_escaped_value(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
callback_transition!(
self,
handler,
context,
on_header_value,
&[context.byte],
HeaderQuotedValue,
header_quoted_value
);
}
#[inline]
fn header_cr1(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
if bs_has_bytes!(context, 2) && bs_starts_with2!(context, b"\r\n") {
bs_jump!(context, 2);
transition_fast!(
self,
handler,
context,
HeaderCr2,
header_cr2
);
} else {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\r' {
transition_fast!(
self,
handler,
context,
HeaderLf1,
header_lf1
);
} else {
exit_error!(CrlfSequence, context.byte);
}
}
}
#[inline]
fn header_lf1(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\n' {
transition_fast!(
self,
handler,
context,
HeaderCr2,
header_cr2
);
} else {
exit_error!(CrlfSequence, context.byte);
}
}
#[inline]
fn header_cr2(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\r' {
transition_fast!(
self,
handler,
context,
HeaderLf2,
header_lf2
);
} else if context.byte == b' ' || context.byte == b'\t' {
callback_transition!(
self,
handler,
context,
on_header_value,
b" ",
StripHeaderValue,
strip_header_value
);
} else {
bs_replay!(context);
transition!(
self,
context,
StripHeaderName,
strip_header_name
);
}
}
#[inline]
fn header_lf2(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\n' {
if has_flag!(self, F_CHUNKED) {
set_state!(self, BodyFinished, body_finished);
} else if has_flag!(self, F_MULTIPART) {
set_state!(self, MultipartDetectData, multipart_detect_data);
} else {
set_state!(self, Finished, finished);
}
if handler.on_headers_finished() {
transition_fast!(self, handler, context);
} else {
exit_callback!(self, context);
}
} else {
exit_error!(CrlfSequence, context.byte);
}
}
#[inline]
fn upper_request_method(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
macro_rules! method {
($method:expr, $length:expr) => (
bs_jump!(context, $length);
callback_transition_fast!(
self,
handler,
context,
on_method,
$method,
StripRequestUrl,
strip_request_url
);
);
}
if bs_has_bytes!(context, 8) {
if bs_starts_with4!(context, b"GET ") {
method!(b"GET", 4);
} else if context.byte == b'P' {
if bs_starts_with5!(context, b"POST ") {
method!(b"POST", 5);
} else if bs_starts_with4!(context, b"PUT ") {
method!(b"PUT", 4);
}
} else if bs_starts_with7!(context, b"DELETE ") {
method!(b"DELETE", 7);
} else if bs_starts_with8!(context, b"CONNECT ") {
method!(b"CONNECT", 8);
} else if bs_starts_with8!(context, b"OPTIONS ") {
method!(b"OPTIONS", 8);
} else if bs_starts_with5!(context, b"HEAD ") {
method!(b"HEAD", 5);
} else if bs_starts_with6!(context, b"TRACE ") {
method!(b"TRACE", 6);
} else if bs_starts_with4!(context, b"PRI ") {
method!(b"PRI", 4);
}
}
collect_tokens!(
context,
ParserError::Method,
context.byte == b' '
|| (context.byte > 0x60 && context.byte < 0x7B),
callback_eos_expr!(self, handler, context, on_method)
);
if context.byte == b' ' {
bs_replay!(context);
callback_transition_fast!(
self,
handler,
context,
on_method,
StripRequestUrl,
strip_request_url
);
} else {
bs_replay!(context);
callback_transition_fast!(
self,
handler,
context,
on_method,
LowerRequestMethod,
lower_request_method
);
}
}
#[inline]
fn lower_request_method(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte > 0x60 && context.byte < 0x7B {
callback_transition!(
self,
handler,
context,
on_method,
&[context.byte - 0x20],
LowerRequestMethod,
lower_request_method
);
} else {
bs_replay!(context);
transition!(
self,
context,
UpperRequestMethod,
upper_request_method
);
}
}
#[inline]
fn strip_request_url(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
consume_linear_space!(
context,
exit_eos!(self, context)
);
transition_fast!(
self,
handler,
context,
RequestUrl,
request_url
);
}
#[inline]
fn request_url(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
collect_visible!(
context,
ParserError::Url,
context.byte == b' ',
callback_eos_expr!(self, handler, context, on_url)
);
bs_replay!(context);
callback_transition_fast!(
self,
handler,
context,
on_url,
StripRequestHttp,
strip_request_http
);
}
#[inline]
fn strip_request_http(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
consume_linear_space!(
context,
exit_eos!(self, context)
);
transition_fast!(
self,
handler,
context,
RequestHttp1,
request_http1
);
}
#[inline]
fn request_http1(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
macro_rules! version {
($major:expr, $minor:expr, $length:expr) => (
bs_jump!(context, $length);
set_state!(self, InitialEnd, initial_end);
if handler.on_version($major, $minor) {
transition_fast!(self, handler, context);
} else {
exit_callback!(self, context);
}
);
}
if bs_has_bytes!(context, 9) {
if bs_starts_with9!(context, b"HTTP/1.1\r") {
version!(1, 1, 9);
} else if bs_starts_with9!(context, b"HTTP/2.0\r") {
version!(2, 0, 9);
} else if bs_starts_with9!(context, b"HTTP/1.0\r") {
version!(1, 0, 9);
}
}
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'H' || context.byte == b'h' {
transition_fast!(self, handler, context, RequestHttp2, request_http2);
} else {
exit_error!(Version, context.byte);
}
}
#[inline]
fn request_http2(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'T' || context.byte == b't' {
transition_fast!(
self,
handler,
context,
RequestHttp3,
request_http3
);
} else {
exit_error!(Version, context.byte);
}
}
#[inline]
fn request_http3(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'T' || context.byte == b't' {
transition_fast!(
self,
handler,
context,
RequestHttp4,
request_http4
);
} else {
exit_error!(Version, context.byte);
}
}
#[inline]
fn request_http4(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'P' || context.byte == b'p' {
transition_fast!(
self,
handler,
context,
RequestHttp5,
request_http5
);
} else {
exit_error!(Version, context.byte);
}
}
#[inline]
fn request_http5(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'/' {
set_lower14!(self, 0);
set_upper14!(self, 0);
transition_fast!(
self,
handler,
context,
RequestVersionMajor,
request_version_major
);
} else {
exit_error!(Version, context.byte);
}
}
#[inline]
fn request_version_major(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
let mut digit = get_lower14!(self);
collect_digits16!(
context,
ParserError::Version,
digit,
999,
{
set_lower14!(self, digit);
exit_eos!(self, context);
}
);
set_lower14!(self, digit);
if context.byte == b'.' {
transition_fast!(
self,
handler,
context,
RequestVersionMinor,
request_version_minor
);
} else {
exit_error!(Version, context.byte);
}
}
#[inline]
fn request_version_minor(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
let mut digit = get_upper14!(self);
collect_digits16!(
context,
ParserError::Version,
digit,
999,
{
set_upper14!(self, digit);
exit_eos!(self, context);
}
);
if context.byte == b'\r' {
set_state!(self, InitialEnd, initial_end);
if handler.on_version(get_lower14!(self) as u16, digit as u16) {
transition_fast!(self, handler, context);
} else {
exit_callback!(self, context);
}
} else {
exit_error!(Version, context.byte);
}
}
#[inline]
fn response_version_major(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
let mut digit = get_lower14!(self);
collect_digits16!(
context,
ParserError::Version,
digit,
999,
{
set_lower14!(self, digit);
exit_eos!(self, context);
}
);
set_lower14!(self, digit);
if context.byte == b'.' {
transition_fast!(
self,
handler,
context,
ResponseVersionMinor,
response_version_minor
);
} else {
exit_error!(Version, context.byte);
}
}
#[inline]
fn response_version_minor(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
let mut digit = get_upper14!(self);
collect_digits16!(
context,
ParserError::Version,
digit,
999,
{
set_upper14!(self, digit);
exit_eos!(self, context);
}
);
set_state!(self, StripResponseStatusCode, strip_response_status_code);
if handler.on_version(get_lower14!(self) as u16, digit as u16) {
transition_fast!(self, handler, context);
} else {
exit_callback!(self, context);
}
}
#[inline]
fn strip_response_status_code(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
consume_linear_space!(
context,
exit_eos!(self, context)
);
bs_next!(context);
if is_digit!(context.byte) {
bs_replay!(context);
set_lower14!(self, 0);
transition_fast!(
self,
handler,
context,
ResponseStatusCode,
response_status_code
);
} else {
exit_error!(StatusCode, context.byte);
}
}
#[inline]
fn response_status_code(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
let mut digit = get_lower14!(self);
collect_digits16!(
context,
ParserError::StatusCode,
digit,
999,
{
set_lower14!(self, digit);
exit_eos!(self, context);
}
);
bs_replay!(context);
set_state!(self, StripResponseStatus, strip_response_status);
if handler.on_status_code(digit as u16) {
transition_fast!(self, handler, context);
} else {
exit_callback!(self, context);
}
}
#[inline]
fn strip_response_status(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
consume_linear_space!(
context,
exit_eos!(self, context)
);
transition_fast!(
self,
handler,
context,
ResponseStatus,
response_status
);
}
#[inline]
fn response_status(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
bs_collect!(context,
if context.byte == b'\r' {
break;
} else if is_token(context.byte) || context.byte == b' ' || context.byte == b'\t' {
continue;
} else {
exit_error!(Status, context.byte);
},
callback!(self, handler, context, on_status, {
exit_eos!(self, context);
})
);
callback_ignore_transition_fast!(
self,
handler,
context,
on_status,
InitialEnd,
initial_end
);
}
#[inline]
fn chunk_length1(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'0' {
set_state!(self, ChunkLengthCr, chunk_length_cr);
if handler.on_chunk_begin() {
transition_fast!(self, handler, context);
} else {
exit_callback!(self, context);
}
} else if is_hex!(context.byte) {
bs_replay!(context);
set_state!(self, ChunkLength2, chunk_length2);
if handler.on_chunk_begin() {
transition_fast!(self, handler, context);
} else {
exit_callback!(self, context);
}
} else {
exit_error!(ChunkLength, context.byte);
}
}
#[inline]
fn chunk_length2(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
collect_hex64!(
context,
ParserError::MaxChunkLength,
self.length,
usize,
exit_eos!(self, context)
);
bs_replay!(context);
transition_fast!(
self,
handler,
context,
ChunkLengthCr,
chunk_length_cr
);
}
#[inline]
fn chunk_length_cr(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\r' {
if self.length == 0 {
callback_transition_fast!(
self,
handler,
context,
on_chunk_length,
self.length,
HeaderLf1,
header_lf1
);
} else {
callback_transition_fast!(
self,
handler,
context,
on_chunk_length,
self.length,
ChunkLengthLf,
chunk_length_lf
);
}
} else if context.byte == b';' {
set_flag!(self, F_CHUNK_EXTENSIONS);
callback_transition_fast!(
self,
handler,
context,
on_chunk_length,
self.length,
StripChunkExtensionName,
strip_chunk_extension_name
);
} else {
exit_error!(ChunkLength, context.byte);
}
}
#[inline]
fn chunk_length_lf(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\n' {
set_state!(self, ChunkData, chunk_data);
if has_flag!(self, F_CHUNK_EXTENSIONS) {
if handler.on_chunk_extensions_finished() {
transition!(self, context);
} else {
exit_callback!(self, context);
}
} else {
transition!(self, context);
}
} else {
exit_error!(CrlfSequence, context.byte);
}
}
#[inline]
fn strip_chunk_extension_name(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
consume_linear_space!(
context,
exit_eos!(self, context)
);
transition_fast!(
self,
handler,
context,
UpperChunkExtensionName,
upper_chunk_extension_name
);
}
#[inline]
fn upper_chunk_extension_name(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte > 0x40 && context.byte < 0x5B {
callback_transition_fast!(
self,
handler,
context,
on_chunk_extension_name,
&[context.byte + 0x20],
LowerChunkExtensionName,
lower_chunk_extension_name
);
} else {
bs_replay!(context);
transition_fast!(
self,
handler,
context,
LowerChunkExtensionName,
lower_chunk_extension_name
);
}
}
#[inline]
fn lower_chunk_extension_name(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
collect_tokens!(
context,
ParserError::ChunkExtensionName,
context.byte == b'='
|| context.byte == b'\r'
|| context.byte == b';'
|| (context.byte > 0x40 && context.byte < 0x5B),
callback_eos_expr!(self, handler, context, on_chunk_extension_name)
);
if context.byte == b'=' {
callback_ignore_transition!(
self,
handler,
context,
on_chunk_extension_name,
StripChunkExtensionValue,
strip_chunk_extension_value
);
} else if context.byte == b'\r' || context.byte == b';' {
bs_replay!(context);
callback_transition!(
self,
handler,
context,
on_chunk_extension_name,
ChunkExtensionFinished,
chunk_extension_finished
);
} else {
bs_replay!(context);
callback_transition!(
self,
handler,
context,
on_chunk_extension_name,
UpperChunkExtensionName,
upper_chunk_extension_name
);
}
}
#[inline]
fn strip_chunk_extension_value(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
consume_linear_space!(
context,
exit_eos!(self, context)
);
transition_fast!(
self,
handler,
context,
ChunkExtensionValue,
chunk_extension_value
);
}
#[inline]
fn chunk_extension_value(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
collect_tokens!(
context,
ParserError::ChunkExtensionValue,
context.byte == b'\r'
|| context.byte == b';'
|| context.byte == b'"',
callback_eos_expr!(self, handler, context, on_chunk_extension_value)
);
if context.byte == b'"' {
transition_fast!(
self,
handler,
context,
ChunkExtensionQuotedValue,
chunk_extension_quoted_value
);
} else {
bs_replay!(context);
callback_transition_fast!(
self,
handler,
context,
on_chunk_extension_value,
ChunkExtensionFinished,
chunk_extension_finished
);
}
}
#[inline]
fn chunk_extension_quoted_value(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
collect_quoted!(
context,
ParserError::ChunkExtensionValue,
callback_eos_expr!(self, handler, context, on_chunk_extension_value)
);
if context.byte == b'"' {
callback_ignore_transition_fast!(
self,
handler,
context,
on_chunk_extension_value,
ChunkExtensionQuotedValueFinished,
chunk_extension_quoted_value_finished
);
} else {
callback_ignore_transition_fast!(
self,
handler,
context,
on_chunk_extension_value,
ChunkExtensionEscapedValue,
chunk_extension_escaped_value
);
}
}
#[inline]
fn chunk_extension_escaped_value(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if is_visible_7bit!(context.byte) || context.byte == b' ' {
callback_transition_fast!(
self,
handler,
context,
on_chunk_extension_value,
&[context.byte],
ChunkExtensionQuotedValue,
chunk_extension_quoted_value
);
} else {
exit_error!(ChunkExtensionValue, context.byte);
}
}
#[inline]
fn chunk_extension_quoted_value_finished(&mut self, _handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b';' || context.byte == b'\r' {
bs_replay!(context);
transition!(
self,
context,
ChunkExtensionFinished,
chunk_extension_finished
);
} else {
exit_error!(ChunkExtensionValue, context.byte);
}
}
#[inline]
fn chunk_extension_finished(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\r' {
set_state!(self, ChunkLengthLf, chunk_length_lf);
} else {
set_state!(self, StripChunkExtensionName, strip_chunk_extension_name);
}
if handler.on_chunk_extension_finished() {
transition!(self, context);
} else {
exit_callback!(self, context);
}
}
#[inline]
fn chunk_data(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
if bs_available!(context) >= self.length {
bs_collect_length!(context, self.length);
self.length = 0;
callback_transition!(
self,
handler,
context,
on_chunk_data,
ChunkDataCr1,
chunk_data_cr1
);
} else {
self.length -= bs_available!(context);
bs_collect_length!(context, bs_available!(context));
callback_transition!(
self,
handler,
context,
on_chunk_data,
ChunkData,
chunk_data
);
}
}
#[inline]
fn chunk_data_cr1(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\r' {
transition_fast!(
self,
handler,
context,
ChunkDataLf1,
chunk_data_lf1
);
} else {
exit_error!(CrlfSequence, context.byte);
}
}
#[inline]
fn chunk_data_lf1(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\n' {
transition_fast!(
self,
handler,
context,
ChunkLength1,
chunk_length1
);
} else {
exit_error!(CrlfSequence, context.byte);
}
}
#[inline]
fn multipart_hyphen1(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'-' {
transition_fast!(
self,
handler,
context,
MultipartHyphen2,
multipart_hyphen2
);
} else if get_lower14!(self) == 0 {
callback_transition!(
self,
handler,
context,
on_multipart_data,
&[b'\r', b'\n', context.byte],
MultipartDataByByte,
multipart_data_by_byte
);
} else {
exit_error!(MultipartBoundary, context.byte);
}
}
#[inline]
fn multipart_hyphen2(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'-' {
transition_fast!(
self,
handler,
context,
MultipartBoundary,
multipart_boundary
);
} else if get_lower14!(self) == 0 {
callback_transition!(
self,
handler,
context,
on_multipart_data,
&[b'\r', b'\n', b'-', context.byte],
MultipartDataByByte,
multipart_data_by_byte
);
} else {
exit_error!(MultipartBoundary, context.byte);
}
}
#[inline]
fn multipart_boundary(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
let (length, callback_data, finished) = {
let boundary = self.boundary.unwrap();
let slice =
if boundary.len() - get_upper14!(self) as usize <= bs_available!(context) {
&boundary[get_upper14!(self) as usize..]
} else {
&boundary[
get_upper14!(self) as usize..
get_upper14!(self) as usize + bs_available!(context)
]
};
if bs_starts_with!(context, slice) {
(slice.len(),
None,
get_upper14!(self) as usize + slice.len() == boundary.len())
} else {
let mut v = Vec::with_capacity( 4 as usize +
get_upper14!(self) as usize);
v.extend_from_slice(b"\r\n--");
v.extend_from_slice(&boundary[..get_upper14!(self) as usize]);
(0, Some(v), false)
}
};
bs_jump!(context, length);
if let Some(v) = callback_data {
if get_lower14!(self) == 0 {
set_upper14!(self, 0);
callback_transition!(
self,
handler,
context,
on_multipart_data,
&v,
MultipartDataByByte,
multipart_data_by_byte
);
} else {
bs_next!(context);
exit_error!(MultipartBoundary, context.byte);
}
} else {
if finished {
set_upper14!(self, 0);
transition!(
self,
context,
MultipartBoundaryCr,
multipart_boundary_cr
);
} else {
inc_upper14!(self, length);
exit_eos!(self, context);
}
}
}
#[inline]
fn multipart_boundary_cr(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\r' {
set_state!(self, PreHeadersLf1, pre_headers_lf1);
if handler.on_multipart_begin() {
transition!(self, context);
} else {
exit_callback!(self, context);
}
} else if context.byte == b'-' {
transition_fast!(
self,
handler,
context,
MultipartEnd,
multipart_end
);
} else {
exit_error!(MultipartBoundary, context.byte);
}
}
#[inline]
fn multipart_boundary_lf(&mut self, _handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\n' {
transition!(
self,
context,
StripHeaderName,
strip_header_name
);
} else {
exit_error!(MultipartBoundary, context.byte);
}
}
#[inline]
fn multipart_detect_data(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
if let Some(length) = handler.content_length() {
self.length = length;
set_lower14!(self, 1);
transition_fast!(
self,
handler,
context,
MultipartDataByLength,
multipart_data_by_length
);
} else {
set_lower14!(self, 0);
transition_fast!(
self,
handler,
context,
MultipartDataByByte,
multipart_data_by_byte
);
}
}
#[inline]
fn multipart_data_by_length(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
if bs_available!(context) >= self.length {
bs_collect_length!(context, self.length);
self.length = 0;
callback_transition!(
self,
handler,
context,
on_multipart_data,
MultipartDataByLengthCr,
multipart_data_by_length_cr
);
} else {
self.length -= bs_available!(context);
bs_collect_length!(context, bs_available!(context));
callback_transition!(
self,
handler,
context,
on_multipart_data,
MultipartDataByLength,
multipart_data_by_length
);
}
}
#[inline]
fn multipart_data_by_length_cr(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\r' {
transition_fast!(
self,
handler,
context,
MultipartDataByLengthLf,
multipart_data_by_length_lf
);
} else {
exit_error!(MultipartBoundary, context.byte);
}
}
#[inline]
fn multipart_data_by_length_lf(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\n' {
transition_fast!(
self,
handler,
context,
MultipartHyphen1,
multipart_hyphen1
);
} else {
exit_error!(MultipartBoundary, context.byte);
}
}
#[inline]
fn multipart_data_by_byte(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
bs_collect_until!(
context,
context.byte == b'\r',
callback_eos_expr!(self, handler, context, on_multipart_data)
);
callback_ignore_transition_fast!(
self,
handler,
context,
on_multipart_data,
MultipartDataByByteLf,
multipart_data_by_byte_lf
)
}
#[inline]
fn multipart_data_by_byte_lf(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'\n' {
transition_fast!(
self,
handler,
context,
MultipartHyphen1,
multipart_hyphen1
);
} else {
callback_transition!(
self,
handler,
context,
on_multipart_data,
&[b'\r', context.byte],
MultipartDataByByte,
multipart_data_by_byte
);
}
}
#[inline]
fn multipart_end(&mut self, _handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
if context.byte == b'-' {
transition!(
self,
context,
BodyFinished,
body_finished
);
} else {
exit_error!(MultipartBoundary, context.byte);
}
}
#[inline]
fn url_encoded_name(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
collect_visible!(
context,
ParserError::UrlEncodedName,
context.byte == b'='
|| context.byte == b'%'
|| context.byte == b'&'
|| context.byte == b';'
|| context.byte == b'+',
callback_eos_expr!(self, handler, context, on_url_encoded_name)
);
match context.byte {
b'=' => {
callback_ignore_transition_fast!(
self,
handler,
context,
on_url_encoded_name,
UrlEncodedValue,
url_encoded_value
);
},
b'%' => {
callback_ignore_transition_fast!(
self,
handler,
context,
on_url_encoded_name,
UrlEncodedNameHex1,
url_encoded_name_hex1
);
},
b'&' | b';' => {
callback_ignore_transition_fast!(
self,
handler,
context,
on_url_encoded_name,
UrlEncodedNameAmpersand,
url_encoded_name_ampersand
);
},
_ => {
callback_ignore_transition_fast!(
self,
handler,
context,
on_url_encoded_name,
UrlEncodedNamePlus,
url_encoded_name_plus
);
}
}
}
#[inline]
fn url_encoded_name_ampersand(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
callback_transition!(
self,
handler,
context,
on_url_encoded_value,
b"",
UrlEncodedName,
url_encoded_name
);
}
#[inline]
fn url_encoded_name_hex1(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
set_upper14!(
self,
if is_digit!(context.byte) {
(context.byte - b'0') << 4
} else if b'@' < context.byte && context.byte < b'G' {
(context.byte - 0x37) << 4
} else if b'`' < context.byte && context.byte < b'g' {
(context.byte - 0x57) << 4
} else {
exit_error!(UrlEncodedName, context.byte);
}
);
transition_fast!(
self,
handler,
context,
UrlEncodedNameHex2,
url_encoded_name_hex2
);
}
#[inline]
fn url_encoded_name_hex2(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
set_lower14!(
self,
if is_digit!(context.byte) {
context.byte - b'0'
} else if b'@' < context.byte && context.byte < b'G' {
context.byte - 0x37
} else if b'`' < context.byte && context.byte < b'g' {
context.byte - 0x57
} else {
exit_error!(UrlEncodedName, context.byte);
}
);
callback_transition!(
self,
handler,
context,
on_url_encoded_name,
&[(get_upper14!(self) | get_lower14!(self)) as u8],
UrlEncodedName,
url_encoded_name
);
}
#[inline]
fn url_encoded_name_plus(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
callback_transition!(
self,
handler,
context,
on_url_encoded_name,
b" ",
UrlEncodedName,
url_encoded_name
);
}
#[inline]
fn url_encoded_value(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
collect_visible!(
context,
ParserError::UrlEncodedValue,
context.byte == b'%'
|| context.byte == b'&'
|| context.byte == b';'
|| context.byte == b'+'
|| context.byte == b'=',
callback_eos_expr!(self, handler, context, on_url_encoded_value)
);
match context.byte {
b'%' => {
callback_ignore_transition_fast!(
self,
handler,
context,
on_url_encoded_value,
UrlEncodedValueHex1,
url_encoded_value_hex1
);
},
b'&' | b';' => {
callback_ignore_transition!(
self,
handler,
context,
on_url_encoded_value,
UrlEncodedName,
url_encoded_name
);
},
b'+' => {
callback_ignore_transition_fast!(
self,
handler,
context,
on_url_encoded_value,
UrlEncodedValuePlus,
url_encoded_value_plus
);
},
_ => {
exit_error!(UrlEncodedValue, context.byte);
}
}
}
#[inline]
fn url_encoded_value_hex1(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
set_upper14!(
self,
if is_digit!(context.byte) {
(context.byte - b'0') << 4
} else if b'@' < context.byte && context.byte < b'G' {
(context.byte - 0x37) << 4
} else if b'`' < context.byte && context.byte < b'g' {
(context.byte - 0x57) << 4
} else {
exit_error!(UrlEncodedValue, context.byte);
}
);
transition_fast!(
self,
handler,
context,
UrlEncodedValueHex2,
url_encoded_value_hex2
);
}
#[inline]
fn url_encoded_value_hex2(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_if_eos!(self, context);
bs_next!(context);
set_lower14!(
self,
if is_digit!(context.byte) {
context.byte - b'0'
} else if b'@' < context.byte && context.byte < b'G' {
context.byte - 0x37
} else if b'`' < context.byte && context.byte < b'g' {
context.byte - 0x57
} else {
exit_error!(UrlEncodedValue, context.byte);
}
);
callback_transition!(
self,
handler,
context,
on_url_encoded_value,
&[(get_upper14!(self) | get_lower14!(self)) as u8],
UrlEncodedValue,
url_encoded_value
);
}
#[inline]
fn url_encoded_value_plus(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
callback_transition!(
self,
handler,
context,
on_url_encoded_value,
b" ",
UrlEncodedValue,
url_encoded_value
);
}
#[inline]
fn dead(&mut self, _handler: &mut T, _context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_error!(Dead);
}
#[inline]
fn body_finished(&mut self, handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
set_state!(self, Finished, finished);
if handler.on_body_finished() {
transition_fast!(self, handler, context);
} else {
exit_callback!(self, context);
}
}
#[inline]
fn finished(&mut self, _handler: &mut T, context: &mut ByteStream)
-> Result<ParserValue, ParserError> {
exit_finished!(self, context);
}
}
#[derive(Clone,Copy,PartialEq)]
#[repr(u8)]
pub enum State {
None,
RequestMethod,
RequestUrl,
RequestVersion,
ResponseVersion,
ResponseStatusCode,
ResponseStatus,
HeaderName,
HeaderValue,
ChunkLength,
ChunkExtensionName,
ChunkExtensionValue,
ChunkData,
MultipartData,
UrlEncodedName,
UrlEncodedValue
}
enum ParserType {
Chunked,
Head,
Multipart,
UrlEncoded
}