Skip to main content

zenith_http1/
connection.rs

1//! HTTP/1.1 连接管理
2//!
3//! 管理单连接上的请求-响应循环(pipelining 支持可选):
4//! - 状态机:Waiting → Reading → Processing → Sending → Waiting/Closed
5//! - keep-alive 超时
6//! - 最大请求数限制
7//! - 优雅关闭
8
9use crate::parser::Http1Parser;
10use crate::types::{Http1Config, Http1Error, HttpRequest};
11
12/// HTTP/1.1 连接状态
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum Http1ConnectionState {
15    /// 等待请求
16    Waiting,
17    /// 读取请求
18    ReadingRequest,
19    /// 读取头部
20    ReadingHeaders,
21    /// 读取请求体
22    ReadingBody,
23    /// 处理请求
24    Processing,
25    /// 发送响应
26    SendingResponse,
27    /// 关闭中
28    Closing,
29    /// 已关闭
30    Closed,
31}
32
33/// HTTP/1.1 连接
34#[derive(Debug)]
35pub struct Http1Connection {
36    state: Http1ConnectionState,
37    parser: Http1Parser,
38    /// 当前请求
39    current_request: Option<HttpRequest>,
40    /// 是否启用 keep-alive
41    keep_alive: bool,
42    /// 已处理请求数
43    requests_handled: u64,
44    /// 是否关闭
45    closed: bool,
46    /// 上次活动时间戳(毫秒)
47    last_activity_ms: u64,
48    /// update_time 是否已被调用(区分"未初始化"与"update_time(0)")
49    time_initialized: bool,
50}
51
52impl Http1Connection {
53    /// 创建连接
54    #[inline]
55    pub fn new(config: Http1Config) -> Self {
56        Self {
57            keep_alive: config.keep_alive,
58            parser: Http1Parser::new(config),
59            state: Http1ConnectionState::Waiting,
60            current_request: None,
61            requests_handled: 0,
62            closed: false,
63            last_activity_ms: 0,
64            time_initialized: false,
65        }
66    }
67
68    /// 当前状态
69    #[inline]
70    pub fn state(&self) -> Http1ConnectionState {
71        self.state
72    }
73
74    /// 是否关闭
75    #[inline]
76    pub fn is_closed(&self) -> bool {
77        self.closed
78    }
79
80    /// 输入数据,尝试解析请求
81    ///
82    /// # 返回
83    /// - Ok(Some(req, body_consumed)): 已解析完整请求,可能包含 body 字节消耗
84    /// - Ok((None, consumed)): 需要更多数据
85    /// - Err(err): 协议错误(错误会自动关闭连接)
86    pub fn on_data(&mut self, data: &[u8]) -> Result<(Option<HttpRequest>, usize), Http1Error> {
87        if self.closed {
88            return Err(Http1Error::ConnectionClosed);
89        }
90
91        // Slowloris 防护:每次收到数据刷新活跃时间戳
92        // (含 body/chunked 阶段,M-9:body 中途 idle 超时同样生效)
93        // 仅在 update_time 已初始化时间戳时刷新 parser 计时,
94        // 否则跳过以避免 first_byte_ms 被误设为 0(struct 默认值)
95        if !data.is_empty() && self.time_initialized {
96            self.parser.note_activity(self.last_activity_ms);
97        }
98
99        let (req, consumed) = match self.parser.feed(data) {
100            Ok(v) => v,
101            Err(e) => {
102                self.on_error(&e);
103                return Err(e);
104            }
105        };
106
107        if let Some(mut req) = req {
108            // 检查 Connection: close
109            if !req.keep_alive {
110                self.keep_alive = false;
111            }
112            // Http1Parser 现已内置完整 chunked 请求体解析(RFC 7230 §4.1),
113            // 当 req.chunked == true 时 req.body 已包含解码后的完整 body,
114            // 无需上层通过 body_complete() 推送。
115            // - Content-Length > 0 且 req.body 非空:Http1Parser 已同步读取 body,直接进入 Processing
116            // - Content-Length > 0 且 req.body 为空:兼容模式,进入 ReadingBody 等待外部 body_complete()
117            // - Content-Length == 0 或 None:无 body,直接处理
118            if req.chunked {
119                // chunked body 已由 parser 完整解码,直接进入 Processing
120                self.state = Http1ConnectionState::Processing;
121            } else if let Some(len) = req.content_length {
122                if len == 0 {
123                    self.state = Http1ConnectionState::Processing;
124                } else if !req.body.is_empty() && req.body.len() as u64 == len {
125                    // Http1Parser 已按 Content-Length 完整读取 body,无需再等待
126                    self.state = Http1ConnectionState::Processing;
127                } else {
128                    // 兼容旧语义:parser 未读取 body,等待上层调用 body_complete()
129                    self.state = Http1ConnectionState::ReadingBody;
130                }
131            } else if req.line.method.as_ref() == "POST" || req.line.method.as_ref() == "PUT" {
132                // 方法无 content-length 时视为 body 长度为 0
133                req.content_length = Some(0);
134                self.state = Http1ConnectionState::Processing;
135            } else {
136                self.state = Http1ConnectionState::Processing;
137            }
138            self.current_request = Some(req);
139            self.requests_handled += 1;
140            Ok((self.current_request.clone(), consumed))
141        } else {
142            // parser 尚未返回完整请求(仍在读取 header / body / chunked 帧)
143            // 连接层状态反映 parser 的活跃状态
144            self.state = match self.parser.state() {
145                crate::parser::ParserState::WaitingRequest
146                | crate::parser::ParserState::ReadingRequest => Http1ConnectionState::ReadingRequest,
147                crate::parser::ParserState::ReadingHeaders => Http1ConnectionState::ReadingHeaders,
148                crate::parser::ParserState::ReadingBody
149                | crate::parser::ParserState::ReadingChunkSize
150                | crate::parser::ParserState::ReadingChunkData
151                | crate::parser::ParserState::ReadingChunkTrailer => Http1ConnectionState::ReadingBody,
152                crate::parser::ParserState::HeadersComplete => Http1ConnectionState::Processing,
153                crate::parser::ParserState::Error => Http1ConnectionState::Closed,
154            };
155            Ok((None, consumed))
156        }
157    }
158
159    /// 设置请求体已接收完成
160    pub fn body_complete(&mut self, body: Vec<u8>) {
161        if let Some(req) = self.current_request.as_mut() {
162            req.body = body;
163            self.state = Http1ConnectionState::Processing;
164        }
165    }
166
167    /// 获取当前请求
168    #[inline]
169    pub fn current_request(&self) -> Option<&HttpRequest> {
170        self.current_request.as_ref()
171    }
172
173    /// 响应发送完成
174    pub fn response_sent(&mut self) {
175        self.current_request = None;
176        if !self.keep_alive {
177            self.state = Http1ConnectionState::Closing;
178            self.closed = true;
179        } else {
180            // 准备下一个请求
181            self.parser.reset();
182            self.state = Http1ConnectionState::Waiting;
183        }
184    }
185
186    /// 处理错误:关闭连接
187    pub fn on_error(&mut self, _err: &Http1Error) {
188        self.state = Http1ConnectionState::Closing;
189        self.closed = true;
190    }
191
192    /// 获取已处理请求数
193    #[inline]
194    pub fn requests_handled(&self) -> u64 {
195        self.requests_handled
196    }
197
198    /// 更新当前时间戳(由事件循环每周期调用)
199    ///
200    /// 必须在首次 [`Self::on_data`] 之前调用至少一次,否则 parser 的
201    /// `first_byte_ms` 不会被设置(note_activity 被跳过),Slowloris
202    /// 空闲超时检测在首字节阶段不生效。调用后 `time_initialized` 置 true,
203    /// 后续 `on_data` 才会向 parser 刷新活跃时间戳。
204    #[inline]
205    pub fn update_time(&mut self, now_ms: u64) {
206        self.last_activity_ms = now_ms;
207        self.time_initialized = true;
208    }
209
210    /// 检查空闲超时(Slowloris 防护)
211    ///
212    /// 由事件循环在每个周期调用。如果请求解析超时,关闭连接。
213    pub fn check_timeout(&mut self) -> Result<(), Http1Error> {
214        if self.closed {
215            return Ok(());
216        }
217        if let Err(e) = self.parser.check_idle_timeout(self.last_activity_ms) {
218            self.on_error(&e);
219            return Err(e);
220        }
221        Ok(())
222    }
223
224    /// 关闭连接
225    pub fn close(&mut self) {
226        self.state = Http1ConnectionState::Closed;
227        self.closed = true;
228    }
229}
230
231impl Default for Http1Connection {
232    fn default() -> Self {
233        Self::new(Http1Config::new())
234    }
235}
236
237#[cfg(test)]
238mod tests {
239    use super::*;
240
241    #[test]
242    fn test_connection_basic() {
243        let mut conn = Http1Connection::new(Http1Config::new());
244        let input = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n";
245        let (req, _) = conn.on_data(input).unwrap();
246        assert!(req.is_some());
247        assert_eq!(conn.state(), Http1ConnectionState::Processing);
248    }
249
250    #[test]
251    fn test_connection_lifecycle() {
252        let mut conn = Http1Connection::new(Http1Config::new());
253        let input = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n";
254        conn.on_data(input).unwrap();
255        assert_eq!(conn.state(), Http1ConnectionState::Processing);
256
257        conn.response_sent();
258        assert_eq!(conn.state(), Http1ConnectionState::Waiting);
259        assert!(!conn.is_closed());
260    }
261
262    #[test]
263    fn test_connection_close() {
264        let mut conn = Http1Connection::new(Http1Config::new());
265        let input =
266            b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n";
267        conn.on_data(input).unwrap();
268        conn.response_sent();
269        assert!(conn.is_closed());
270    }
271
272    #[test]
273    fn test_connection_error_cases() {
274        let mut conn = Http1Connection::new(Http1Config::new());
275        let r = conn.on_data(b"INV HTTP/1.1\r\nHost: x\r\n\r\n");
276        assert!(r.is_err());
277        assert!(conn.is_closed());
278    }
279
280    #[test]
281    fn test_connection_body_post() {
282        let mut conn = Http1Connection::new(Http1Config::new());
283        // Http1Parser 在 Content-Length 模式下会同步读取完整 body,因此此处需要同时提供 headers + body
284        //(不再走 ReadingBody → body_complete 路径,而是直接进入 Processing)
285        let input =
286            b"POST /api HTTP/1.1\r\nHost: example.com\r\nContent-Length: 5\r\n\r\nhello";
287        let (req, _) = conn.on_data(input).unwrap();
288        let req = req.unwrap();
289        assert_eq!(req.content_length, Some(5));
290        assert_eq!(req.body, b"hello");
291        assert_eq!(conn.state(), Http1ConnectionState::Processing);
292    }
293
294    #[test]
295    fn test_connection_state_variants() {
296        let states = [
297            Http1ConnectionState::Waiting,
298            Http1ConnectionState::ReadingRequest,
299            Http1ConnectionState::ReadingHeaders,
300            Http1ConnectionState::ReadingBody,
301            Http1ConnectionState::Processing,
302            Http1ConnectionState::SendingResponse,
303            Http1ConnectionState::Closing,
304            Http1ConnectionState::Closed,
305        ];
306        for (i, s) in states.iter().enumerate() {
307            assert_eq!(*s, states[i]);
308        }
309        assert_ne!(Http1ConnectionState::Waiting, Http1ConnectionState::Closed);
310    }
311
312    #[test]
313    fn test_connection_default() {
314        let conn = Http1Connection::default();
315        assert_eq!(conn.state(), Http1ConnectionState::Waiting);
316        assert!(!conn.is_closed());
317        assert_eq!(conn.requests_handled(), 0);
318    }
319
320    #[test]
321    fn test_connection_keep_alive_multiple_requests() {
322        let mut conn = Http1Connection::new(Http1Config::new());
323        let input1 = b"GET /1 HTTP/1.1\r\nHost: example.com\r\n\r\n";
324        let (req1, _) = conn.on_data(input1).unwrap();
325        assert!(req1.is_some());
326        assert_eq!(conn.requests_handled(), 1);
327
328        conn.response_sent();
329        assert_eq!(conn.state(), Http1ConnectionState::Waiting);
330
331        let input2 = b"GET /2 HTTP/1.1\r\nHost: example.com\r\n\r\n";
332        let (req2, _) = conn.on_data(input2).unwrap();
333        assert!(req2.is_some());
334        assert_eq!(conn.requests_handled(), 2);
335    }
336
337    #[test]
338    fn test_connection_closed_rejects_data() {
339        let mut conn = Http1Connection::new(Http1Config::new());
340        conn.close();
341        assert!(conn.is_closed());
342        assert_eq!(conn.state(), Http1ConnectionState::Closed);
343
344        let input = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n";
345        let r = conn.on_data(input);
346        assert!(r.is_err());
347        assert!(matches!(r.unwrap_err(), Http1Error::ConnectionClosed));
348    }
349
350    #[test]
351    fn test_connection_current_request() {
352        let mut conn = Http1Connection::new(Http1Config::new());
353        assert!(conn.current_request().is_none());
354
355        let input = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n";
356        conn.on_data(input).unwrap();
357        assert!(conn.current_request().is_some());
358        assert_eq!(conn.current_request().unwrap().line.method.as_ref(), "GET");
359    }
360
361    #[test]
362    fn test_connection_chunked_body_state() {
363        let mut conn = Http1Connection::new(Http1Config::new());
364        // 完整 chunked 请求(RFC 7230 §4.1):headers + chunk + last-chunk + trailer CRLF
365        let input = b"POST /upload HTTP/1.1\r\nHost: example.com\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nHello\r\n0\r\n\r\n";
366        let (req, _) = conn.on_data(input).unwrap();
367        assert!(req.is_some());
368        let req = req.unwrap();
369        assert_eq!(conn.state(), Http1ConnectionState::Processing);
370        assert_eq!(req.body, b"Hello");
371    }
372
373    #[test]
374    fn test_connection_chunked_body_partial() {
375        let mut conn = Http1Connection::new(Http1Config::new());
376        // 仅 headers,未包含 chunk 数据 → parser 返回 None,连接进入 ReadingBody
377        let part1 = b"POST /upload HTTP/1.1\r\nHost: example.com\r\nTransfer-Encoding: chunked\r\n\r\n";
378        let (req, _) = conn.on_data(part1).unwrap();
379        assert!(req.is_none());
380        assert_eq!(conn.state(), Http1ConnectionState::ReadingBody);
381
382        // 后续 chunk 数据到达 → parser 完成解析,连接进入 Processing
383        let part2 = b"5\r\nHello\r\n0\r\n\r\n";
384        let (req, _) = conn.on_data(part2).unwrap();
385        assert!(req.is_some());
386        assert_eq!(conn.state(), Http1ConnectionState::Processing);
387        assert_eq!(req.unwrap().body, b"Hello");
388    }
389
390    #[test]
391    fn test_connection_zero_content_length() {
392        let mut conn = Http1Connection::new(Http1Config::new());
393        let input = b"POST /api HTTP/1.1\r\nHost: example.com\r\nContent-Length: 0\r\n\r\n";
394        let (req, _) = conn.on_data(input).unwrap();
395        assert!(req.is_some());
396        assert_eq!(conn.state(), Http1ConnectionState::Processing);
397    }
398
399    #[test]
400    fn test_connection_put_method() {
401        let mut conn = Http1Connection::new(Http1Config::new());
402        // Http1Parser 同步读取 Content-Length body,提供完整 headers+body 直接进入 Processing
403        let input =
404            b"PUT /resource HTTP/1.1\r\nHost: example.com\r\nContent-Length: 5\r\n\r\nworld";
405        let (req, _) = conn.on_data(input).unwrap();
406        let req = req.unwrap();
407        assert_eq!(req.line.method.as_ref(), "PUT");
408        assert_eq!(req.body, b"world");
409        assert_eq!(conn.state(), Http1ConnectionState::Processing);
410    }
411
412    #[test]
413    fn test_connection_head_method() {
414        let mut conn = Http1Connection::new(Http1Config::new());
415        let input = b"HEAD / HTTP/1.1\r\nHost: example.com\r\n\r\n";
416        let (req, _) = conn.on_data(input).unwrap();
417        assert!(req.is_some());
418        assert_eq!(req.unwrap().line.method.as_ref(), "HEAD");
419        assert_eq!(conn.state(), Http1ConnectionState::Processing);
420    }
421
422    #[test]
423    fn test_connection_on_error_closes_connection() {
424        let mut conn = Http1Connection::new(Http1Config::new());
425        conn.on_error(&Http1Error::SyntaxError("test".into()));
426        assert!(conn.is_closed());
427        assert_eq!(conn.state(), Http1ConnectionState::Closing);
428    }
429
430    #[test]
431    fn test_connection_body_complete_no_current_request() {
432        let mut conn = Http1Connection::new(Http1Config::new());
433        conn.body_complete(b"test".to_vec());
434        assert_eq!(conn.state(), Http1ConnectionState::Waiting);
435    }
436
437    #[test]
438    fn test_connection_response_sent_clears_request() {
439        let mut conn = Http1Connection::new(Http1Config::new());
440        let input = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n";
441        conn.on_data(input).unwrap();
442        assert!(conn.current_request().is_some());
443        conn.response_sent();
444        assert!(conn.current_request().is_none());
445    }
446
447    #[test]
448    fn test_connection_closing_state() {
449        let mut conn = Http1Connection::new(Http1Config::new());
450        let input = b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n";
451        conn.on_data(input).unwrap();
452        conn.response_sent();
453        assert_eq!(conn.state(), Http1ConnectionState::Closing);
454        assert!(conn.is_closed());
455    }
456
457    #[test]
458    fn test_connection_debug_format() {
459        let conn = Http1Connection::new(Http1Config::new());
460        let s = format!("{:?}", conn);
461        assert!(!s.is_empty());
462    }
463
464    #[test]
465    fn test_connection_idle_timeout_during_body_read() {
466        // M-9:body 中途静默超过 idle_timeout → 连接层 IdleTimeout 并关闭
467        let config = Http1Config::new().with_idle_timeout_ms(30_000);
468        let mut conn = Http1Connection::new(config);
469        conn.update_time(0);
470        // 仅头部到达(CL=10,body 未到)→ ReadingBody
471        let (req, _) = conn
472            .on_data(b"POST / HTTP/1.1\r\nHost: example.com\r\nContent-Length: 10\r\n\r\n")
473            .unwrap();
474        assert!(req.is_none());
475        assert_eq!(conn.state(), Http1ConnectionState::ReadingBody);
476        // 30s+ 未再收到 body → IdleTimeout,连接 fail-closed
477        conn.update_time(30_001);
478        let r = conn.check_timeout();
479        assert!(matches!(r, Err(Http1Error::IdleTimeout)), "实际 {r:?}");
480        assert!(conn.is_closed());
481    }
482
483    #[test]
484    fn test_connection_body_activity_prevents_timeout() {
485        // M-9 对照:body 分片持续到达刷新活跃,不得误判超时
486        let config = Http1Config::new().with_idle_timeout_ms(30_000);
487        let mut conn = Http1Connection::new(config);
488        conn.update_time(0);
489        let (req, _) = conn
490            .on_data(b"POST / HTTP/1.1\r\nHost: example.com\r\nContent-Length: 6\r\n\r\nhe")
491            .unwrap();
492        assert!(req.is_none());
493        // 20s 后 body 第二片到达
494        conn.update_time(20_000);
495        let (req, _) = conn.on_data(b"ll").unwrap();
496        assert!(req.is_none());
497        // 活跃后 25s:不得超时
498        conn.update_time(45_000);
499        assert!(conn.check_timeout().is_ok(), "活跃刷新后不得超时");
500        // 最后一片凑满 6 字节 body 完成请求
501        let (req, _) = conn.on_data(b"lo").unwrap();
502        assert!(req.is_some());
503    }
504}