1use http::{HeaderMap, Method, StatusCode, Version};
4
5#[derive(Debug, Clone)]
11pub struct RequestHead {
12 pub method: Method,
13 pub target: String,
16 pub headers: HeaderMap,
17}
18
19impl RequestHead {
20 pub fn new(method: Method, target: impl Into<String>) -> Self {
21 Self {
22 method,
23 target: target.into(),
24 headers: HeaderMap::new(),
25 }
26 }
27
28 pub fn with_header(mut self, name: impl AsRef<str>, value: impl AsRef<str>) -> Self {
32 if let (Ok(name), Ok(value)) = (
33 http::header::HeaderName::try_from(name.as_ref()),
34 http::header::HeaderValue::try_from(value.as_ref()),
35 ) {
36 self.headers.insert(name, value);
37 }
38 self
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum BodyKind {
45 Empty,
47 Length(u64),
49 Chunked,
51 UntilClose,
53}
54
55#[derive(Debug, Clone)]
57pub struct ResponseHead {
58 pub version: Version,
59 pub status: StatusCode,
60 pub headers: HeaderMap,
61 pub body: BodyKind,
62}
63
64impl ResponseHead {
65 pub fn status_forbids_body(status: StatusCode) -> bool {
67 status.is_informational()
68 || status == StatusCode::NO_CONTENT
69 || status == StatusCode::NOT_MODIFIED
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn request_head_writes_headers_it_was_given() {
79 let head = RequestHead::new(Method::POST, "/v1/chat/completions")
80 .with_header("content-type", "application/json")
81 .with_header("authorization", "Bearer secret");
82 assert_eq!(head.target, "/v1/chat/completions");
83 assert_eq!(
84 head.headers
85 .get("content-type")
86 .map(|v| v.to_str().unwrap()),
87 Some("application/json")
88 );
89 }
90
91 #[test]
92 fn no_body_statuses_are_recognized() {
93 assert!(ResponseHead::status_forbids_body(StatusCode::NO_CONTENT));
94 assert!(ResponseHead::status_forbids_body(StatusCode::NOT_MODIFIED));
95 assert!(ResponseHead::status_forbids_body(StatusCode::CONTINUE));
96 assert!(!ResponseHead::status_forbids_body(StatusCode::OK));
97 assert!(!ResponseHead::status_forbids_body(StatusCode::BAD_REQUEST));
98 }
99}