sip_codec/
response.rs

1use std::io::Write;
2
3use bytes::BytesMut;
4use http::HeaderMap;
5
6use crate::Version;
7
8fn code_str(code: u16) -> Option<&'static str> {
9	match code {
10		100 => Some("Trying"),
11		180 => Some("Ringing"),
12		181 => Some("Call is Being Forwarded"),
13		182 => Some("Queued"),
14		183 => Some("Session Progress"),
15		199 => Some("Early Dialog Terminated"),
16		200 => Some("OK"),
17		202 => Some("Accepted"),
18		204 => Some("No Notification"),
19		300 => Some("Multiple Choices"),
20		301 => Some("Moved Permanently"),
21		302 => Some("Moved Temporarily"),
22		305 => Some("Use Proxy"),
23		380 => Some("Alternative Service"),
24		400 => Some("Bad Request"),
25		401 => Some("Unauthorized"),
26		402 => Some("Payment Required"),
27		403 => Some("Forbidden"),
28		404 => Some("Not Found"),
29		405 => Some("Method Not Allowed"),
30		406 => Some("Not Acceptable"),
31		407 => Some("Proxy Authentication Required"),
32		408 => Some("Request Timeout"),
33		409 => Some("Conflict"),
34		410 => Some("Gone"),
35		411 => Some("Length Required"),
36		412 => Some("Conditional Request Failed"),
37		413 => Some("Request Entity Too Large"),
38		414 => Some("Request-URI Too Long"),
39		415 => Some("Unsupported Media Type"),
40		416 => Some("Unsupported URI Scheme"),
41		417 => Some("Unknown Resource-Priority"),
42		420 => Some("Bad Extension"),
43		421 => Some("Extension Required"),
44		422 => Some("Session Interval Too Small"),
45		423 => Some("Interval Too Brief"),
46		424 => Some("Bad Location Information"),
47		428 => Some("Use Identity Header"),
48		429 => Some("Provide Referrer Identity"),
49		433 => Some("Anonymity Disallowed"),
50		436 => Some("Bad Identity-Info"),
51		437 => Some("Unsupported Certificate"),
52		438 => Some("Invalid Identity Header"),
53		439 => Some("First Hop Lacks Outbound Support"),
54		440 => Some("Max-Breadth Exceeded"),
55		469 => Some("Bad Info Package"),
56		470 => Some("Consent Needed"),
57		480 => Some("Temporarily Unavailable"),
58		481 => Some("Call/Transaction Does Not Exist"),
59		482 => Some("Loop Detected"),
60		483 => Some("Too Many Hops"),
61		484 => Some("Address Incomplete"),
62		485 => Some("Ambiguous"),
63		486 => Some("Busy Here"),
64		487 => Some("Request Terminated"),
65		488 => Some("Not Acceptable Here"),
66		489 => Some("Bad Event"),
67		491 => Some("Request Pending"),
68		493 => Some("Undecipherable"),
69		494 => Some("Security Agreement Required"),
70		500 => Some("Server Internal Error"),
71		501 => Some("Not Implemented"),
72		502 => Some("Bad Gateway"),
73		503 => Some("Service Unavailable"),
74		504 => Some("Server Time-out"),
75		505 => Some("Version Not Supported"),
76		513 => Some("Message Too Large"),
77		580 => Some("Precondition Failure"),
78		600 => Some("Busy Everywhere"),
79		603 => Some("Decline"),
80		604 => Some("Does Not Exist Anywhere"),
81		606 => Some("Not Acceptable"),
82		607 => Some("Unwanted"),
83		_ => None,
84	}
85}
86
87#[derive(Debug, Clone, PartialEq, Eq)]
88pub struct Response {
89	pub version: Version,
90	pub code: u16,
91	pub headers: HeaderMap,
92	pub body: Vec<u8>,
93}
94
95impl Response {
96	pub fn new(code: u16) -> Self {
97		Self {
98			version: Default::default(),
99			code,
100			headers: HeaderMap::new(),
101			body: vec![],
102		}
103	}
104
105	pub fn write(&self, f: &mut impl Write) -> Result<(), std::io::Error> {
106		let code: &str = code_str(self.code).unwrap_or("");
107		write!(
108			f,
109			"SIP/{major}.{minor} {code}",
110			major = self.version.major,
111			minor = self.version.minor,
112			code = self.code,
113		)?;
114		// If there's a string for the corresponding code, add a space and add it
115		write!(
116			f,
117			"{space}{code_string}\r\n",
118			space = if code.is_empty() { "" } else { " " },
119			code_string = code,
120		)?;
121		for (key, value) in self.headers.iter() {
122			if key == "content-length" {
123				continue;
124			}
125			write!(f, "{}: {}\r\n", key, value.to_str().unwrap())?;
126		}
127		write!(f, "content-length: {}\r\n", self.body.len())?;
128		write!(f, "\r\n")?;
129		for letter in self.body.iter() {
130			write!(f, "{}", *letter as char)?;
131		}
132		Ok(())
133	}
134
135	pub fn write_buf(&self, buf: &mut BytesMut) {
136		let mut f = buf_writer::BufWriter::new(buf);
137		self.write(&mut f).unwrap();
138	}
139}
140
141
142/// This wraps a BytesMut and lets you use it with the `format!` macro. It will automatically
143/// expand the buffer, unlike the preexisting `writer` function of BytesMut.
144/// For example:
145///
146/// ```rust,ignore
147/// let mut buf = bytes::BytesMut::new();
148/// let mut f = BufWriter::new(&mut buf);
149/// write!(f, "test");
150/// assert_eq!(&b"test"[..], buf);
151/// ```
152mod buf_writer {
153	use std::io;
154
155	use bytes::BytesMut;
156	pub struct BufWriter<'a> {
157		buf: &'a mut BytesMut,
158	}
159
160	impl<'a> BufWriter<'a> {
161		pub fn new(buf: &'a mut BytesMut) -> Self {
162			Self { buf }
163		}
164	}
165
166	impl<'a> io::Write for BufWriter<'a> {
167		fn write(&mut self, src: &[u8]) -> io::Result<usize> {
168			self.buf.extend_from_slice(src);
169			Ok(src.len())
170		}
171
172		fn flush(&mut self) -> io::Result<()> {
173			Ok(())
174		}
175	}
176}
177
178#[cfg(test)]
179mod tests {
180	use bytes::BytesMut;
181	use http::header::HeaderValue;
182
183	use super::Response;
184
185	#[test]
186	fn test() {
187		let mut res = Response::new(200);
188
189		res.headers.insert("a", HeaderValue::from_static("b"));
190		res.headers
191			.insert("content-length", HeaderValue::from_static("7"));
192		res.body = b"abcdefg".to_vec();
193		let mut buf = BytesMut::new();
194		res.write_buf(&mut buf);
195		let expected = b"SIP/2.0 200 OK\r\na: b\r\ncontent-length: 7\r\n\r\nabcdefg";
196		assert_eq!(&expected[..], buf);
197	}
198}