1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use http::{Request, Version, header};
use crate::body::BodyReader;
use crate::ext::HeaderIterExt;
use crate::parser::try_parse_request;
use crate::util::log_data;
use crate::{ArrayVec, CloseReason, Error};
use super::state::RecvRequest;
use super::{Inner, Reply, ResponsePhase};
use super::{MAX_REQUEST_HEADERS, RecvRequestResult};
impl Reply<RecvRequest> {
/// Create a new Reply in the RecvRequest state.
///
/// This is the entry point for the server state machine. It creates a new Reply
/// in the RecvRequest state, ready to receive an HTTP request from a client.
///
/// Returns an error if the Reply cannot be created.
pub fn new() -> Result<Self, Error> {
let close_reason = ArrayVec::from_fn(|_| CloseReason::ClientConnectionClose);
let inner = Inner {
phase: ResponsePhase::Status,
state: super::BodyState::default(),
response: None,
close_reason,
force_recv_body: false,
force_send_body: false,
method: None,
expect_100: false,
expect_100_reject: false,
};
Ok(Reply::wrap(inner))
}
/// Try reading a request from the input.
///
/// Attempts to parse an HTTP request from the input buffer. If the input buffer
/// doesn't contain a complete request, this method will return `Ok((0, None))`.
///
/// Returns a tuple with the number of bytes consumed from the input and
/// the parsed request (or None if incomplete).
///
/// Returns an error if there's a problem parsing the request.
pub fn try_request(&mut self, input: &[u8]) -> Result<(usize, Option<Request<()>>), Error> {
let maybe_request = self.do_try_request(input)?;
let (input_used, request) = match maybe_request {
Some(v) => v,
// Not enough input for a full response yet
None => return Ok((0, None)),
};
self.inner.method = Some(request.method().clone());
self.inner.expect_100 = request.headers().iter().has_expect_100();
let headers = request.headers();
let is_http10 = request.version() == Version::HTTP_10;
let is_keep_alive = headers.iter().has(header::CONNECTION, "keep-alive");
let is_conn_close = headers.iter().has(header::CONNECTION, "close");
if is_http10 && !is_keep_alive {
self.inner
.close_reason
.push(CloseReason::CloseDelimitedBody);
}
if is_conn_close {
self.inner
.close_reason
.push(CloseReason::ClientConnectionClose);
}
Ok((input_used, Some(request)))
}
/// Try reading request headers
///
/// A request is only possible once the `input` holds all the HTTP request
/// headers. Before that this returns `None`. When the request is succesfully read,
/// the return value `(usize, Request<()>)` contains how many bytes were consumed
/// of the `input`.
fn do_try_request(&mut self, input: &[u8]) -> Result<Option<(usize, Request<()>)>, Error> {
// ~3k for 100 headers
let (input_used, request) = match try_parse_request::<MAX_REQUEST_HEADERS>(input)? {
Some(v) => v,
None => {
return Ok(None);
}
};
log_data(&input[..input_used]);
let http10 = request.version() == Version::HTTP_10;
let method = request.method();
let header_lookup = |name: http::HeaderName| {
let header = request.headers().get(name)?;
header.to_str().ok()
};
let reader =
BodyReader::for_request(http10, method, self.inner.force_recv_body, &header_lookup)?;
self.inner.state.reader = Some(reader);
Ok(Some((input_used, request)))
}
/// Check if the Reply can proceed to the next state.
///
/// This method is currently not implemented and will panic if called.
/// In a real implementation, it would check if the request has been fully received
/// and is ready to proceed to the next state.
pub fn can_proceed(&self) -> bool {
self.inner.state.reader.is_some()
}
/// Proceed to the next state.
///
/// This returns `None` if we have not finished receiving the request. It is guaranteed that if
/// `can_proceed()` returns true, this will return `Some`.
///
/// Returns one of the following variants of `RecvRequestResult`:
/// - `Send100` if the request included an "Expect: 100-continue" header
/// - `RecvBody` if the request has a body to receive
/// - `ProvideResponse` if the request doesn't have a body
pub fn proceed(self) -> Option<RecvRequestResult> {
if !self.can_proceed() {
return None;
}
let has_request_body = self.inner.state.reader.as_ref().unwrap().has_body();
if has_request_body {
if self.inner.expect_100 {
Some(RecvRequestResult::Send100(Reply::wrap(self.inner)))
} else {
Some(RecvRequestResult::RecvBody(Reply::wrap(self.inner)))
}
} else {
Some(RecvRequestResult::ProvideResponse(Reply::wrap(self.inner)))
}
}
/// Convert the state to receive a body despite method.
///
/// Methods like HEAD and CONNECT should not have attached bodies.
/// Some broken APIs use bodies anyway and this is an escape hatch to
/// interoperate with such services.
pub fn force_recv_body(&mut self) {
self.inner.force_recv_body = true;
}
}