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 pub raw_headers: Option<Vec<(String, String)>>,
21}
22
23impl RequestHead {
24 pub fn new(method: Method, target: impl Into<String>) -> Self {
25 Self {
26 method,
27 target: target.into(),
28 headers: HeaderMap::new(),
29 raw_headers: None,
30 }
31 }
32
33 pub fn with_header(mut self, name: impl AsRef<str>, value: impl AsRef<str>) -> Self {
37 if let (Ok(name), Ok(value)) = (
38 http::header::HeaderName::try_from(name.as_ref()),
39 http::header::HeaderValue::try_from(value.as_ref()),
40 ) {
41 self.headers.insert(name, value);
42 }
43 self
44 }
45
46 pub fn with_raw_header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
52 let name_str = name.into();
53 let value_str = value.into();
54 if let (Ok(hname), Ok(hval)) = (
55 http::header::HeaderName::try_from(name_str.as_str()),
56 http::header::HeaderValue::try_from(value_str.as_str()),
57 ) {
58 self.headers.append(hname, hval);
59 }
60 let raw = self.raw_headers.get_or_insert_with(Vec::new);
61 raw.push((name_str, value_str));
62 self
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum BodyKind {
69 Empty,
71 Length(u64),
73 Chunked,
75 UntilClose,
77}
78
79#[derive(Debug, Clone)]
81pub struct ResponseHead {
82 pub version: Version,
83 pub status: StatusCode,
84 pub headers: HeaderMap,
85 pub body: BodyKind,
86}
87
88impl ResponseHead {
89 pub fn status_forbids_body(status: StatusCode) -> bool {
91 status.is_informational()
92 || status == StatusCode::NO_CONTENT
93 || status == StatusCode::NOT_MODIFIED
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn request_head_writes_headers_it_was_given() {
103 let head = RequestHead::new(Method::POST, "/v1/chat/completions")
104 .with_header("content-type", "application/json")
105 .with_header("authorization", "Bearer secret");
106 assert_eq!(head.target, "/v1/chat/completions");
107 assert_eq!(
108 head.headers
109 .get("content-type")
110 .map(|v| v.to_str().unwrap()),
111 Some("application/json")
112 );
113 }
114
115 #[test]
116 fn no_body_statuses_are_recognized() {
117 assert!(ResponseHead::status_forbids_body(StatusCode::NO_CONTENT));
118 assert!(ResponseHead::status_forbids_body(StatusCode::NOT_MODIFIED));
119 assert!(ResponseHead::status_forbids_body(StatusCode::CONTINUE));
120 assert!(!ResponseHead::status_forbids_body(StatusCode::OK));
121 assert!(!ResponseHead::status_forbids_body(StatusCode::BAD_REQUEST));
122 }
123}