1use std::fmt::{Display, Error, Formatter};
5use std::str::Utf8Error;
6
7pub mod headers;
8pub mod sock_ctrl_msg;
9
10pub mod ascii {
11 pub const CR: u8 = b'\r';
12 pub const COLON: u8 = b':';
13 pub const LF: u8 = b'\n';
14 pub const SP: u8 = b' ';
15 pub const CRLF_LEN: usize = 2;
16}
17
18#[derive(Debug, Eq, PartialEq)]
20pub enum HttpHeaderError {
21 InvalidFormat(String),
23 InvalidUtf8String(Utf8Error),
25 InvalidValue(String, String),
27 SizeLimitExceeded(String),
29 UnsupportedFeature(String, String),
31 UnsupportedName(String),
33 UnsupportedValue(String, String),
35}
36
37impl Display for HttpHeaderError {
38 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
39 match self {
40 Self::InvalidFormat(header_key) => {
41 write!(f, "Header is incorrectly formatted. Key: {}", header_key)
42 }
43 Self::InvalidUtf8String(header_key) => {
44 write!(f, "Header contains invalid characters. Key: {}", header_key)
45 }
46 Self::InvalidValue(header_name, value) => {
47 write!(f, "Invalid value. Key:{}; Value:{}", header_name, value)
48 }
49 Self::SizeLimitExceeded(inner) => {
50 write!(f, "Invalid content length. Header: {}", inner)
51 }
52 Self::UnsupportedFeature(header_key, header_value) => write!(
53 f,
54 "Unsupported feature. Key: {}; Value: {}",
55 header_key, header_value
56 ),
57 Self::UnsupportedName(inner) => write!(f, "Unsupported header name. Key: {}", inner),
58 Self::UnsupportedValue(header_key, header_value) => write!(
59 f,
60 "Unsupported value. Key:{}; Value:{}",
61 header_key, header_value
62 ),
63 }
64 }
65}
66
67#[derive(Debug, Eq, PartialEq)]
69pub enum RequestError {
70 BodyWithoutPendingRequest,
72 HeaderError(HttpHeaderError),
74 HeadersWithoutPendingRequest,
76 InvalidHttpMethod(&'static str),
78 InvalidHttpVersion(&'static str),
80 InvalidRequest,
82 InvalidUri(&'static str),
84 Overflow,
86 Underflow,
88 SizeLimitExceeded(usize, usize),
90}
91
92impl Display for RequestError {
93 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
94 match self {
95 Self::BodyWithoutPendingRequest => write!(
96 f,
97 "No request was pending while the request body was being parsed."
98 ),
99 Self::HeaderError(inner) => write!(f, "Invalid header. Reason: {}", inner),
100 Self::HeadersWithoutPendingRequest => write!(
101 f,
102 "No request was pending while the request headers were being parsed."
103 ),
104 Self::InvalidHttpMethod(inner) => write!(f, "Invalid HTTP Method: {}", inner),
105 Self::InvalidHttpVersion(inner) => write!(f, "Invalid HTTP Version: {}", inner),
106 Self::InvalidRequest => write!(f, "Invalid request."),
107 Self::InvalidUri(inner) => write!(f, "Invalid URI: {}", inner),
108 Self::Overflow => write!(f, "Overflow occurred when parsing a request."),
109 Self::Underflow => write!(f, "Underflow occurred when parsing a request."),
110 Self::SizeLimitExceeded(limit, size) => write!(
111 f,
112 "Request payload with size {} is larger than the limit of {} \
113 allowed by server.",
114 size, limit
115 ),
116 }
117 }
118}
119
120#[derive(Debug)]
122pub enum ConnectionError {
123 ConnectionClosed,
125 InvalidWrite,
127 ParseError(RequestError),
129 StreamReadError(SysError),
131 StreamWriteError(std::io::Error),
133}
134
135impl Display for ConnectionError {
136 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
137 match self {
138 Self::ConnectionClosed => write!(f, "Connection closed."),
139 Self::InvalidWrite => write!(f, "Invalid write attempt."),
140 Self::ParseError(inner) => write!(f, "Parsing error: {}", inner),
141 Self::StreamReadError(inner) => write!(f, "Reading stream error: {}", inner),
142 Self::StreamWriteError(inner) => write!(f, "Writing stream error: {}", inner),
144 }
145 }
146}
147
148#[derive(Debug)]
150#[allow(dead_code)]
151pub enum RouteError {
152 HandlerExist(String),
154}
155
156impl Display for RouteError {
157 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
158 match self {
159 RouteError::HandlerExist(p) => write!(f, "handler for {} already exists", p),
160 }
161 }
162}
163
164#[derive(Debug)]
166pub enum ServerError {
167 ConnectionError(ConnectionError),
169 IOError(std::io::Error),
171 Overflow,
173 ServerFull,
175 Underflow,
177}
178
179impl Display for ServerError {
180 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
181 match self {
182 Self::ConnectionError(inner) => write!(f, "Connection error: {}", inner),
183 Self::IOError(inner) => write!(f, "IO error: {}", inner),
184 Self::Overflow => write!(f, "Overflow occured while processing messages."),
185 Self::ServerFull => write!(f, "Server is full."),
186 Self::Underflow => write!(f, "Underflow occured while processing messages."),
187 }
188 }
189}
190
191#[derive(Clone, Debug, Eq, PartialEq)]
201pub struct Body {
202 pub body: Vec<u8>,
204}
205
206impl Body {
207 pub fn new<T: Into<Vec<u8>>>(body: T) -> Self {
209 Self { body: body.into() }
210 }
211
212 pub fn raw(&self) -> &[u8] {
214 self.body.as_slice()
215 }
216
217 pub fn len(&self) -> usize {
219 self.body.len()
220 }
221
222 pub fn is_empty(&self) -> bool {
224 self.body.len() == 0
225 }
226}
227
228#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
230pub enum Method {
231 Get,
233 Head,
235 Post,
237 Put,
239 Patch,
241 Delete,
243}
244
245impl Method {
246 pub fn try_from(bytes: &[u8]) -> Result<Self, RequestError> {
254 match bytes {
255 b"GET" => Ok(Self::Get),
256 b"HEAD" => Ok(Self::Head),
257 b"POST" => Ok(Self::Post),
258 b"PUT" => Ok(Self::Put),
259 b"PATCH" => Ok(Self::Patch),
260 b"DELETE" => Ok(Self::Delete),
261 _ => Err(RequestError::InvalidHttpMethod("Unsupported HTTP method.")),
262 }
263 }
264
265 pub fn raw(self) -> &'static [u8] {
267 match self {
268 Self::Get => b"GET",
269 Self::Head => b"HEAD",
270 Self::Post => b"POST",
271 Self::Put => b"PUT",
272 Self::Patch => b"PATCH",
273 Self::Delete => b"DELETE",
274 }
275 }
276
277 pub fn to_str(self) -> &'static str {
279 match self {
280 Method::Get => "GET",
281 Method::Head => "HEAD",
282 Method::Post => "POST",
283 Method::Put => "PUT",
284 Method::Patch => "PATCH",
285 Method::Delete => "DELETE",
286 }
287 }
288}
289
290#[derive(Clone, Copy, Debug, Eq, PartialEq)]
302pub enum Version {
303 Http10,
305 Http11,
307}
308
309impl Default for Version {
310 fn default() -> Self {
312 Self::Http11
313 }
314}
315
316impl Version {
317 pub fn raw(self) -> &'static [u8] {
319 match self {
320 Self::Http10 => b"HTTP/1.0",
321 Self::Http11 => b"HTTP/1.1",
322 }
323 }
324
325 pub fn try_from(bytes: &[u8]) -> Result<Self, RequestError> {
333 match bytes {
334 b"HTTP/1.0" => Ok(Self::Http10),
335 b"HTTP/1.1" => Ok(Self::Http11),
336 _ => Err(RequestError::InvalidHttpVersion(
337 "Unsupported HTTP version.",
338 )),
339 }
340 }
341}
342
343#[derive(Clone, Copy, Debug, Eq, PartialEq)]
345pub struct SysError(i32);
346
347impl SysError {
348 pub fn new(errno: i32) -> SysError {
350 SysError(errno)
351 }
352
353 pub fn last() -> SysError {
355 SysError(std::io::Error::last_os_error().raw_os_error().unwrap())
356 }
357
358 pub fn errno(self) -> i32 {
360 self.0
361 }
362}
363
364impl Display for SysError {
365 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
366 std::io::Error::from_raw_os_error(self.0).fmt(f)
367 }
368}
369
370impl std::error::Error for SysError {}
371
372impl From<std::io::Error> for SysError {
373 fn from(e: std::io::Error) -> Self {
374 SysError::new(e.raw_os_error().unwrap_or_default())
375 }
376}
377
378impl From<SysError> for std::io::Error {
379 fn from(err: SysError) -> std::io::Error {
380 std::io::Error::from_raw_os_error(err.0)
381 }
382}
383
384pub type SysResult<T> = std::result::Result<T, SysError>;
385
386#[cfg(test)]
387mod tests {
388 use super::*;
389
390 impl PartialEq for ConnectionError {
391 fn eq(&self, other: &Self) -> bool {
392 use self::ConnectionError::*;
393 match (self, other) {
394 (ParseError(ref e), ParseError(ref other_e)) => e.eq(other_e),
395 (ConnectionClosed, ConnectionClosed) => true,
396 (StreamReadError(ref e), StreamReadError(ref other_e)) => {
397 format!("{}", e).eq(&format!("{}", other_e))
398 }
399 (StreamWriteError(ref e), StreamWriteError(ref other_e)) => {
400 format!("{}", e).eq(&format!("{}", other_e))
401 }
402 (InvalidWrite, InvalidWrite) => true,
403 _ => false,
404 }
405 }
406 }
407
408 #[test]
409 fn test_version() {
410 assert_eq!(Version::Http10.raw(), b"HTTP/1.0");
412 assert_eq!(Version::Http11.raw(), b"HTTP/1.1");
413
414 assert_eq!(Version::try_from(b"HTTP/1.0").unwrap(), Version::Http10);
416 assert_eq!(Version::try_from(b"HTTP/1.1").unwrap(), Version::Http11);
417 assert_eq!(
418 Version::try_from(b"HTTP/2.0").unwrap_err(),
419 RequestError::InvalidHttpVersion("Unsupported HTTP version.")
420 );
421
422 assert_eq!(Version::default(), Version::Http11);
424 }
425
426 #[test]
427 fn test_method() {
428 assert_eq!(Method::Get.raw(), b"GET");
430 assert_eq!(Method::Head.raw(), b"HEAD");
431 assert_eq!(Method::Post.raw(), b"POST");
432 assert_eq!(Method::Put.raw(), b"PUT");
433 assert_eq!(Method::Patch.raw(), b"PATCH");
434 assert_eq!(Method::Post.raw(), b"POST");
435 assert_eq!(Method::Delete.raw(), b"DELETE");
436
437 assert_eq!(Method::try_from(b"GET").unwrap(), Method::Get);
439 assert_eq!(Method::try_from(b"HEAD").unwrap(), Method::Head);
440 assert_eq!(Method::try_from(b"POST").unwrap(), Method::Post);
441 assert_eq!(Method::try_from(b"PUT").unwrap(), Method::Put);
442 assert_eq!(Method::try_from(b"PATCH").unwrap(), Method::Patch);
443 assert_eq!(Method::try_from(b"DELETE").unwrap(), Method::Delete);
444 assert_eq!(
445 Method::try_from(b"CONNECT").unwrap_err(),
446 RequestError::InvalidHttpMethod("Unsupported HTTP method.")
447 );
448 assert_eq!(Method::try_from(b"POST").unwrap(), Method::Post);
449 assert_eq!(Method::try_from(b"DELETE").unwrap(), Method::Delete);
450 }
451
452 #[test]
453 fn test_body() {
454 let body = Body::new("".to_string());
455 assert!(body.is_empty());
457 let body = Body::new("This is a body.".to_string());
458 assert_eq!(body.len(), 15);
460 assert_eq!(body.raw(), b"This is a body.");
462 }
463
464 #[test]
465 fn test_display_request_error() {
466 assert_eq!(
467 format!("{}", RequestError::BodyWithoutPendingRequest),
468 "No request was pending while the request body was being parsed."
469 );
470 assert_eq!(
471 format!("{}", RequestError::HeadersWithoutPendingRequest),
472 "No request was pending while the request headers were being parsed."
473 );
474 assert_eq!(
475 format!("{}", RequestError::InvalidHttpMethod("test")),
476 "Invalid HTTP Method: test"
477 );
478 assert_eq!(
479 format!("{}", RequestError::InvalidHttpVersion("test")),
480 "Invalid HTTP Version: test"
481 );
482 assert_eq!(
483 format!("{}", RequestError::InvalidRequest),
484 "Invalid request."
485 );
486 assert_eq!(
487 format!("{}", RequestError::InvalidUri("test")),
488 "Invalid URI: test"
489 );
490 assert_eq!(
491 format!("{}", RequestError::Overflow),
492 "Overflow occurred when parsing a request."
493 );
494 assert_eq!(
495 format!("{}", RequestError::Underflow),
496 "Underflow occurred when parsing a request."
497 );
498 assert_eq!(
499 format!("{}", RequestError::SizeLimitExceeded(4, 10)),
500 "Request payload with size 10 is larger than the limit of 4 allowed by server."
501 );
502 }
503
504 #[test]
505 fn test_display_header_error() {
506 assert_eq!(
507 format!(
508 "{}",
509 RequestError::HeaderError(HttpHeaderError::InvalidFormat("test".to_string()))
510 ),
511 "Invalid header. Reason: Header is incorrectly formatted. Key: test"
512 );
513 let value = String::from_utf8(vec![0, 159]);
514 assert_eq!(
515 format!(
516 "{}",
517 RequestError::HeaderError(HttpHeaderError::InvalidUtf8String(
518 value.unwrap_err().utf8_error()
519 ))
520 ),
521 "Invalid header. Reason: Header contains invalid characters. Key: invalid utf-8 sequence of 1 bytes from index 1"
522 );
523 assert_eq!(
524 format!(
525 "{}",
526 RequestError::HeaderError(HttpHeaderError::SizeLimitExceeded("test".to_string()))
527 ),
528 "Invalid header. Reason: Invalid content length. Header: test"
529 );
530 assert_eq!(
531 format!(
532 "{}",
533 RequestError::HeaderError(HttpHeaderError::UnsupportedFeature(
534 "test".to_string(),
535 "test".to_string()
536 ))
537 ),
538 "Invalid header. Reason: Unsupported feature. Key: test; Value: test"
539 );
540 assert_eq!(
541 format!(
542 "{}",
543 RequestError::HeaderError(HttpHeaderError::UnsupportedName("test".to_string()))
544 ),
545 "Invalid header. Reason: Unsupported header name. Key: test"
546 );
547 assert_eq!(
548 format!(
549 "{}",
550 RequestError::HeaderError(HttpHeaderError::UnsupportedValue(
551 "test".to_string(),
552 "test".to_string()
553 ))
554 ),
555 "Invalid header. Reason: Unsupported value. Key:test; Value:test"
556 );
557 }
558
559 #[test]
560 fn test_display_connection_error() {
561 assert_eq!(
562 format!("{}", ConnectionError::ConnectionClosed),
563 "Connection closed."
564 );
565 assert_eq!(
566 format!(
567 "{}",
568 ConnectionError::ParseError(RequestError::InvalidRequest)
569 ),
570 "Parsing error: Invalid request."
571 );
572 assert_eq!(
573 format!("{}", ConnectionError::InvalidWrite),
574 "Invalid write attempt."
575 );
576 #[cfg(target_os = "linux")]
577 assert_eq!(
578 format!(
579 "{}",
580 ConnectionError::StreamWriteError(std::io::Error::from_raw_os_error(11))
581 ),
582 "Writing stream error: Resource temporarily unavailable (os error 11)"
583 );
584 #[cfg(target_os = "macos")]
585 assert_eq!(
586 format!(
587 "{}",
588 ConnectionError::StreamWriteError(std::io::Error::from_raw_os_error(11))
589 ),
590 "Writing stream error: Resource deadlock avoided (os error 11)"
591 );
592 }
593
594 #[test]
595 fn test_display_server_error() {
596 assert_eq!(
597 format!(
598 "{}",
599 ServerError::ConnectionError(ConnectionError::ConnectionClosed)
600 ),
601 "Connection error: Connection closed."
602 );
603 #[cfg(target_os = "linux")]
604 assert_eq!(
605 format!(
606 "{}",
607 ServerError::IOError(std::io::Error::from_raw_os_error(11))
608 ),
609 "IO error: Resource temporarily unavailable (os error 11)"
610 );
611 #[cfg(target_os = "macos")]
612 assert_eq!(
613 format!(
614 "{}",
615 ServerError::IOError(std::io::Error::from_raw_os_error(11))
616 ),
617 "IO error: Resource deadlock avoided (os error 11)"
618 );
619 assert_eq!(
620 format!("{}", ServerError::Overflow),
621 "Overflow occured while processing messages."
622 );
623 assert_eq!(format!("{}", ServerError::ServerFull), "Server is full.");
624 assert_eq!(
625 format!("{}", ServerError::Underflow),
626 "Underflow occured while processing messages."
627 );
628 }
629
630 #[test]
631 fn test_display_route_error() {
632 assert_eq!(
633 format!("{}", RouteError::HandlerExist("test".to_string())),
634 "handler for test already exists"
635 );
636 }
637
638 #[test]
639 fn test_method_to_str() {
640 let val = Method::Get;
641 assert_eq!(val.to_str(), "GET");
642
643 let val = Method::Head;
644 assert_eq!(val.to_str(), "HEAD");
645
646 let val = Method::Post;
647 assert_eq!(val.to_str(), "POST");
648
649 let val = Method::Put;
650 assert_eq!(val.to_str(), "PUT");
651
652 let val = Method::Patch;
653 assert_eq!(val.to_str(), "PATCH");
654
655 let val = Method::Delete;
656 assert_eq!(val.to_str(), "DELETE");
657 }
658}