ureq_proto/server/
recvreq.rs

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