in src/connection.rs [262:371]
fn parse_headers(
&mut self,
line_start_index: &mut usize,
end_cursor: usize,
) -> Result<bool, ConnectionError> {
if end_cursor > self.buffer.len() {
return Err(ConnectionError::ParseError(RequestError::Overflow));
}
if end_cursor < *line_start_index {
return Err(ConnectionError::ParseError(RequestError::Underflow));
}
// Safe to access the slice as the bounds are checked above.
match find(&self.buffer[*line_start_index..end_cursor], &[CR, LF]) {
// `line_start_index` points to the end of the most recently found CR LF
// sequence. That means that if we found the next CR LF sequence at this index,
// they are, in fact, a CR LF CR LF sequence, which marks the end of the header
// fields, per HTTP specification.
// We have found the end of the header.
Some(0) => {
// The current state is `WaitingForHeaders`, ensuring a valid request formed from a
// request line.
let request = self
.pending_request
.as_mut()
.ok_or(ConnectionError::ParseError(
RequestError::HeadersWithoutPendingRequest,
))?;
if request.headers.content_length() == 0 {
self.state = ConnectionState::RequestReady;
} else {
if request.headers.content_length() as usize > self.payload_max_size {
return Err(ConnectionError::ParseError(
RequestError::SizeLimitExceeded(
self.payload_max_size,
request.headers.content_length() as usize,
),
));
}
if request.headers.expect() {
// Send expect.
let expect_response =
Response::new(request.http_version(), StatusCode::Continue);
self.response_queue.push_back(expect_response);
}
self.body_bytes_to_be_read = request.headers.content_length();
request.body = Some(Body::new(vec![]));
self.state = ConnectionState::WaitingForBody;
}
// Update the index for the next header.
*line_start_index = line_start_index
.checked_add(CRLF_LEN)
.ok_or(ConnectionError::ParseError(RequestError::Overflow))?;
Ok(true)
}
// We have found the end of a header line.
Some(relative_line_end_index) => {
let request = self
.pending_request
.as_mut()
.ok_or(ConnectionError::ParseError(
RequestError::HeadersWithoutPendingRequest,
))?;
// The `line_end_index` relative to the whole buffer.
let line_end_index = relative_line_end_index
.checked_add(*line_start_index)
.ok_or(ConnectionError::ParseError(RequestError::Overflow))?;
// Get the line slice and parse it.
// The slice access is safe because `line_end_index` is a sum of `line_end_index`
// and something else, and `line_end_index` itself is guaranteed to be within
// `self.buffer`'s bounds by the `find()`.
let line = &self.buffer[*line_start_index..line_end_index];
match request.headers.parse_header_line(line) {
// If a header is unsupported we ignore it.
Ok(_)
| Err(RequestError::HeaderError(HttpHeaderError::UnsupportedValue(_, _))) => {}
// If parsing the header invalidates the request, we propagate
// the error.
Err(e) => return Err(ConnectionError::ParseError(e)),
};
// Update the `line_start_index` to where we finished parsing.
*line_start_index = line_end_index
.checked_add(CRLF_LEN)
.ok_or(ConnectionError::ParseError(RequestError::Overflow))?;
Ok(true)
}
// If we have an incomplete header line.
None => {
// If we have parsed BUFFER_SIZE bytes and still haven't found the header
// line end sequence.
if *line_start_index == 0 && end_cursor == BUFFER_SIZE {
// Header line is longer than BUFFER_SIZE bytes, so it is invalid.
let utf8_string = String::from_utf8_lossy(&self.buffer);
return Err(ConnectionError::ParseError(RequestError::HeaderError(
HttpHeaderError::SizeLimitExceeded(utf8_string.to_string()),
)));
}
// Move the incomplete header line from the end of the buffer to
// the beginning, so that we can append the rest of the line and
// parse it in the next `try_read` call.
self.shift_buffer_left(*line_start_index, end_cursor)
.map_err(ConnectionError::ParseError)?;
Ok(false)
}
}
}