1use core::mem;
55
56use alloc::{borrow::ToOwned, string::String, vec::Vec};
57
58use httparse::Error as HttparseError;
59use log::{debug, trace};
60use thiserror::Error;
61use url::Url;
62
63use crate::{
64 coroutine::*,
65 rfc9110::{
66 headers::{HTTP_CONTENT_LENGTH, HTTP_LOCATION},
67 request::HttpRequest,
68 response::HttpResponse,
69 send::{HTTP_DEFAULT_MAX_BODY_LEN, HttpSendOutput, HttpSendYield},
70 },
71 rfc9112::read_headers::{
72 HTTP_DEFAULT_MAX_HEADERS_LEN, Http11HeadersRead, Http11HeadersReadError,
73 },
74};
75
76#[derive(Debug, Error)]
78pub enum Http10SendError {
79 #[error("HTTP/1.0 send failed: reached unexpected EOF")]
81 Eof,
82 #[error("HTTP/1.0 send failed: parse response headers: {0}")]
84 ParseResponseHeaders(HttparseError),
85 #[error("HTTP/1.0 send failed: invalid content length `{0}`")]
87 InvalidContentLength(String),
88 #[error("HTTP/1.0 send failed: response head exceeds {0} bytes")]
90 HeadersTooLarge(usize),
91 #[error("HTTP/1.0 send failed: response body exceeds {0} bytes")]
93 BodyTooLarge(usize),
94}
95
96impl From<Http11HeadersReadError> for Http10SendError {
97 fn from(err: Http11HeadersReadError) -> Self {
98 match err {
99 Http11HeadersReadError::Eof => Self::Eof,
100 Http11HeadersReadError::ParseResponseHeaders(e) => Self::ParseResponseHeaders(e),
101 Http11HeadersReadError::TooLarge(limit) => Self::HeadersTooLarge(limit),
102 }
103 }
104}
105
106#[derive(Debug)]
108pub struct Http10Send {
109 pub max_headers_len: usize,
112 pub max_body_len: usize,
116 request_url: Url,
117 state: State,
118 wants_write: Option<Vec<u8>>,
119 keep_alive: bool,
120 response: Option<HttpResponse>,
121 buf: Vec<u8>,
122}
123
124impl Http10Send {
125 pub fn new(req: HttpRequest) -> Self {
128 debug!("prepare request to send");
129 trace!("{req:?}");
130
131 let request_url = req.url.clone();
132 let bytes = req.to_http_10_vec();
133
134 Self {
135 max_headers_len: HTTP_DEFAULT_MAX_HEADERS_LEN,
136 max_body_len: HTTP_DEFAULT_MAX_BODY_LEN,
137 request_url,
138 state: State::ReadHeaders(Http11HeadersRead::default()),
139 wants_write: Some(bytes),
140 keep_alive: false,
141 response: None,
142 buf: Vec::new(),
143 }
144 }
145
146 fn finish(
147 &self,
148 response: HttpResponse,
149 remaining: Vec<u8>,
150 ) -> HttpCoroutineState<HttpSendYield, Result<HttpSendOutput, Http10SendError>> {
151 let keep_alive = self.keep_alive;
152
153 if response.status.is_redirection()
154 && let Some(location) = response.header(HTTP_LOCATION)
155 && let Ok(url) = self.request_url.join(location)
156 {
157 let same_scheme = self.request_url.scheme() == url.scheme();
158 let same_host =
159 self.request_url.host() == url.host() && self.request_url.port() == url.port();
160 let same_origin = same_scheme && same_host;
161
162 return HttpCoroutineState::Yielded(HttpSendYield::WantsRedirect {
163 url,
164 response,
165 keep_alive,
166 same_origin,
167 });
168 }
169
170 HttpCoroutineState::Complete(Ok(HttpSendOutput {
171 response,
172 remaining,
173 keep_alive,
174 }))
175 }
176}
177
178impl HttpCoroutine for Http10Send {
179 type Yield = HttpSendYield;
180 type Return = Result<HttpSendOutput, Http10SendError>;
181
182 fn resume(&mut self, mut arg: Option<&[u8]>) -> HttpCoroutineState<Self::Yield, Self::Return> {
183 loop {
184 if let Some(bytes) = self.wants_write.take() {
185 return HttpCoroutineState::Yielded(HttpSendYield::WantsWrite(bytes));
186 }
187
188 if let State::ReadHeaders(rh) = &mut self.state {
189 rh.max_len = self.max_headers_len;
190 }
191
192 match &mut self.state {
193 State::ReadHeaders(rh) => match rh.resume(arg.take()) {
194 HttpCoroutineState::Yielded(HttpYield::WantsRead) => {
195 return HttpCoroutineState::Yielded(HttpSendYield::WantsRead);
196 }
197 HttpCoroutineState::Yielded(HttpYield::WantsWrite(_)) => {
198 unreachable!("Http11HeadersRead never writes");
199 }
200 HttpCoroutineState::Complete(Err(err)) => {
201 return HttpCoroutineState::Complete(Err(err.into()));
202 }
203 HttpCoroutineState::Complete(Ok(out)) => {
204 let response = out.response;
205 self.keep_alive = out.keep_alive;
206 let status = *response.status;
207
208 if status == 204 || status == 304 {
209 return self.finish(response, out.remaining);
210 }
211
212 if let Some(len_str) = response.header(HTTP_CONTENT_LENGTH) {
213 let len_str = len_str.trim();
214 let is_digits = len_str.bytes().all(|b| b.is_ascii_digit());
215
216 let Some(len) =
217 is_digits.then(|| len_str.parse::<usize>().ok()).flatten()
218 else {
219 let err = Http10SendError::InvalidContentLength(len_str.to_owned());
220 return HttpCoroutineState::Complete(Err(err));
221 };
222
223 if len > self.max_body_len {
224 let err = Http10SendError::BodyTooLarge(self.max_body_len);
225 return HttpCoroutineState::Complete(Err(err));
226 }
227
228 self.buf = out.remaining;
229 self.response = Some(response);
230 debug!("reading body of length {len}");
231 self.state = State::BodyLength(len);
232 continue;
233 }
234
235 self.buf = out.remaining;
236 self.response = Some(response);
237 debug!("reading body until connection closes");
238 self.state = State::BodyEof;
239 }
240 },
241 State::BodyLength(len) => {
242 match arg.take() {
243 Some(&[]) if *len > self.buf.len() => {
244 return HttpCoroutineState::Complete(Err(Http10SendError::Eof));
245 }
246 Some(data) => self.buf.extend_from_slice(data),
247 None => {}
248 }
249
250 if *len > self.buf.len() {
251 trace!("received incomplete body {len}/{}", self.buf.len());
252 return HttpCoroutineState::Yielded(HttpSendYield::WantsRead);
253 }
254
255 let body = self.buf.drain(..*len).collect();
256 let remaining = mem::take(&mut self.buf);
257 let mut response = self.response.take().expect("response missing");
258 response.body = body;
259 return self.finish(response, remaining);
260 }
261 State::BodyEof => match arg.take() {
262 _ if self.buf.len() > self.max_body_len => {
263 let err = Http10SendError::BodyTooLarge(self.max_body_len);
264 return HttpCoroutineState::Complete(Err(err));
265 }
266 Some(&[]) => {
267 let buf = mem::take(&mut self.buf);
268 let mut response = self.response.take().expect("response missing");
269 response.body = buf;
270 return self.finish(response, Vec::new());
271 }
272 Some(data) if data.len() > self.max_body_len.saturating_sub(self.buf.len()) => {
273 let err = Http10SendError::BodyTooLarge(self.max_body_len);
274 return HttpCoroutineState::Complete(Err(err));
275 }
276 Some(data) => {
277 self.buf.extend_from_slice(data);
278 return HttpCoroutineState::Yielded(HttpSendYield::WantsRead);
279 }
280 None => {
281 return HttpCoroutineState::Yielded(HttpSendYield::WantsRead);
282 }
283 },
284 }
285 }
286 }
287}
288
289#[derive(Debug)]
290enum State {
291 ReadHeaders(Http11HeadersRead),
292 BodyLength(usize),
293 BodyEof,
294}
295
296#[cfg(test)]
297mod tests {
298 use crate::rfc1945::send::*;
299
300 #[test]
301 fn body_length_completes() {
302 let req = HttpRequest::get("http://example.com".try_into().unwrap());
303 let mut coroutine = Http10Send::new(req);
304
305 let bytes = expect_wants_write(&mut coroutine, None);
306 assert_eq!(bytes, b"GET / HTTP/1.0\r\ncontent-length: 0\r\n\r\n");
307
308 expect_wants_read(&mut coroutine, None);
309
310 let reply = b"HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\nhello";
311 let out = expect_complete_ok(&mut coroutine, Some(reply));
312 assert_eq!(out.response.version, "HTTP/1.0");
313 assert_eq!(*out.response.status, 200);
314 assert_eq!(out.response.body, b"hello");
315 assert!(!out.keep_alive);
316 }
317
318 #[test]
319 fn body_eof_completes() {
320 let req = HttpRequest::get("http://example.com".try_into().unwrap());
321 let mut coroutine = Http10Send::new(req);
322
323 expect_wants_write(&mut coroutine, None);
324 expect_wants_read(&mut coroutine, None);
325 expect_wants_read(&mut coroutine, Some(b"HTTP/1.0 200 OK\r\n\r\nhello "));
326 expect_wants_read(&mut coroutine, Some(b"world"));
327
328 let out = expect_complete_ok(&mut coroutine, Some(b""));
329 assert_eq!(out.response.body, b"hello world");
330 assert!(!out.keep_alive);
331 }
332
333 #[test]
334 fn keep_alive_when_server_says_so() {
335 let req = HttpRequest::get("http://example.com".try_into().unwrap());
336 let mut coroutine = Http10Send::new(req);
337
338 expect_wants_write(&mut coroutine, None);
339 expect_wants_read(&mut coroutine, None);
340
341 let reply = b"HTTP/1.0 200 OK\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n";
342 let out = expect_complete_ok(&mut coroutine, Some(reply));
343 assert!(out.keep_alive);
344 }
345
346 #[test]
347 fn invalid_content_length_errors() {
348 let req = HttpRequest::get("http://example.com".try_into().unwrap());
349 let mut coroutine = Http10Send::new(req);
350
351 expect_wants_write(&mut coroutine, None);
352 expect_wants_read(&mut coroutine, None);
353
354 let reply = b"HTTP/1.0 200 OK\r\nContent-Length: notanumber\r\n\r\n";
355 let err = expect_complete_err(&mut coroutine, Some(reply));
356 let Http10SendError::InvalidContentLength(s) = err else {
357 panic!("expected InvalidContentLength, got {err:?}");
358 };
359 assert_eq!(s, "notanumber");
360 }
361
362 fn expect_wants_write(cor: &mut Http10Send, arg: Option<&[u8]>) -> Vec<u8> {
363 match cor.resume(arg) {
364 HttpCoroutineState::Yielded(HttpSendYield::WantsWrite(bytes)) => bytes,
365 state => panic!("expected WantsWrite, got {state:?}"),
366 }
367 }
368
369 fn expect_wants_read(cor: &mut Http10Send, arg: Option<&[u8]>) {
370 match cor.resume(arg) {
371 HttpCoroutineState::Yielded(HttpSendYield::WantsRead) => {}
372 state => panic!("expected WantsRead, got {state:?}"),
373 }
374 }
375
376 fn expect_complete_ok(cor: &mut Http10Send, arg: Option<&[u8]>) -> HttpSendOutput {
377 match cor.resume(arg) {
378 HttpCoroutineState::Complete(Ok(out)) => out,
379 state => panic!("expected Complete(Ok), got {state:?}"),
380 }
381 }
382
383 fn expect_complete_err(cor: &mut Http10Send, arg: Option<&[u8]>) -> Http10SendError {
384 match cor.resume(arg) {
385 HttpCoroutineState::Complete(Err(err)) => err,
386 state => panic!("expected Complete(Err), got {state:?}"),
387 }
388 }
389}