nntp_proxy/protocol/
responses.rs1pub const MULTILINE_TERMINATOR: &[u8] = b"\r\n.\r\n";
8
9pub const CRLF: &[u8] = b"\r\n";
11
12pub const TERMINATOR_TAIL_SIZE: usize = 4;
14
15pub const MIN_RESPONSE_LENGTH: usize = 5;
17
18pub const AUTH_REQUIRED: &[u8] = b"381 Password required\r\n";
22
23pub const AUTH_ACCEPTED: &[u8] = b"281 Authentication accepted\r\n";
25
26pub const PROXY_GREETING_PCR: &[u8] = b"200 NNTP Proxy Ready (Per-Command Routing)\r\n";
30
31pub const CONNECTION_CLOSING: &[u8] = b"205 Connection closing\r\n";
33
34pub const GOODBYE: &[u8] = b"205 Goodbye\r\n";
36
37pub const COMMAND_NOT_SUPPORTED: &[u8] = b"500 Command not supported by this proxy\r\n";
41
42pub const BACKEND_ERROR: &[u8] = b"503 Backend error\r\n";
44
45pub const BACKEND_UNAVAILABLE: &[u8] = b"400 Backend server unavailable\r\n";
47
48pub const COMMAND_NOT_SUPPORTED_STATELESS: &[u8] =
50 b"500 Command not supported by this proxy (stateless proxy mode)\r\n";
51
52#[inline]
64pub fn greeting(message: &str) -> String {
65 format!("200 {}\r\n", message)
66}
67
68#[inline]
70pub fn greeting_readonly(message: &str) -> String {
71 format!("201 {}\r\n", message)
72}
73
74#[inline]
76pub fn ok_response(message: &str) -> String {
77 format!("200 {}\r\n", message)
78}
79
80#[inline]
90pub fn error_response(code: u16, message: &str) -> String {
91 format!("{} {}\r\n", code, message)
92}
93
94#[inline]
96pub fn response(code: u16, message: &str) -> String {
97 format!("{} {}\r\n", code, message)
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn test_constants() {
106 assert_eq!(CRLF, b"\r\n");
107 assert_eq!(MULTILINE_TERMINATOR, b"\r\n.\r\n");
108 assert_eq!(MULTILINE_TERMINATOR.len(), 5);
109 assert_eq!(TERMINATOR_TAIL_SIZE, 4);
110 }
111
112 #[test]
113 fn test_greeting() {
114 assert_eq!(greeting("Ready"), "200 Ready\r\n");
115 assert_eq!(
116 greeting("news.example.com ready"),
117 "200 news.example.com ready\r\n"
118 );
119 assert_eq!(greeting_readonly("Read only"), "201 Read only\r\n");
120 }
121
122 #[test]
123 fn test_ok_response() {
124 assert_eq!(ok_response("OK"), "200 OK\r\n");
125 assert_eq!(ok_response("Command accepted"), "200 Command accepted\r\n");
126 }
127
128 #[test]
129 fn test_error_response() {
130 assert_eq!(
131 error_response(430, "No such article"),
132 "430 No such article\r\n"
133 );
134 assert_eq!(
135 error_response(500, "Command not recognized"),
136 "500 Command not recognized\r\n"
137 );
138 }
139
140 #[test]
141 fn test_response() {
142 assert_eq!(
143 response(215, "Newsgroups follow"),
144 "215 Newsgroups follow\r\n"
145 );
146 assert_eq!(
147 response(381, "Password required"),
148 "381 Password required\r\n"
149 );
150 }
151
152 #[test]
153 fn test_auth_constants() {
154 assert_eq!(AUTH_REQUIRED, b"381 Password required\r\n");
155 assert_eq!(AUTH_ACCEPTED, b"281 Authentication accepted\r\n");
156 }
157
158 #[test]
159 fn test_standard_responses() {
160 assert!(PROXY_GREETING_PCR.starts_with(b"200"));
161 assert!(CONNECTION_CLOSING.starts_with(b"205"));
162 assert!(GOODBYE.starts_with(b"205"));
163 }
164
165 #[test]
166 fn test_error_constants() {
167 assert!(COMMAND_NOT_SUPPORTED.starts_with(b"500"));
168 assert!(BACKEND_ERROR.starts_with(b"503"));
169 assert!(BACKEND_UNAVAILABLE.starts_with(b"400"));
170 assert!(COMMAND_NOT_SUPPORTED_STATELESS.starts_with(b"500"));
171 }
172
173 #[test]
174 fn test_all_responses_end_with_crlf() {
175 assert!(AUTH_REQUIRED.ends_with(CRLF));
176 assert!(AUTH_ACCEPTED.ends_with(CRLF));
177 assert!(PROXY_GREETING_PCR.ends_with(CRLF));
178 assert!(CONNECTION_CLOSING.ends_with(CRLF));
179 assert!(GOODBYE.ends_with(CRLF));
180 assert!(COMMAND_NOT_SUPPORTED.ends_with(CRLF));
181 assert!(BACKEND_ERROR.ends_with(CRLF));
182 assert!(BACKEND_UNAVAILABLE.ends_with(CRLF));
183 assert!(COMMAND_NOT_SUPPORTED_STATELESS.ends_with(CRLF));
184 }
185}