dbs_uhttp/common/
mod.rs

1// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use 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///Errors associated with a header that is invalid.
19#[derive(Debug, Eq, PartialEq)]
20pub enum HttpHeaderError {
21    /// The header is misformatted.
22    InvalidFormat(String),
23    /// The specified header contains illegal characters.
24    InvalidUtf8String(Utf8Error),
25    ///The value specified is not valid.
26    InvalidValue(String, String),
27    /// The content length specified is longer than the limit imposed by Micro Http.
28    SizeLimitExceeded(String),
29    /// The requested feature is not currently supported.
30    UnsupportedFeature(String, String),
31    /// The header specified is not supported.
32    UnsupportedName(String),
33    /// The value for the specified header is not supported.
34    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/// Errors associated with parsing the HTTP Request from a u8 slice.
68#[derive(Debug, Eq, PartialEq)]
69pub enum RequestError {
70    /// No request was pending while the request body was being parsed.
71    BodyWithoutPendingRequest,
72    /// Header specified is either invalid or not supported by this HTTP implementation.
73    HeaderError(HttpHeaderError),
74    /// No request was pending while the request headers were being parsed.
75    HeadersWithoutPendingRequest,
76    /// The HTTP Method is not supported or it is invalid.
77    InvalidHttpMethod(&'static str),
78    /// The HTTP Version in the Request is not supported or it is invalid.
79    InvalidHttpVersion(&'static str),
80    /// The Request is invalid and cannot be served.
81    InvalidRequest,
82    /// Request URI is invalid.
83    InvalidUri(&'static str),
84    /// Overflow occurred when parsing a request.
85    Overflow,
86    /// Underflow occurred when parsing a request.
87    Underflow,
88    /// Payload too large.
89    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/// Errors associated with a HTTP Connection.
121#[derive(Debug)]
122pub enum ConnectionError {
123    /// Attempted to read or write on a closed connection.
124    ConnectionClosed,
125    /// Attempted to write on a stream when there was nothing to write.
126    InvalidWrite,
127    /// The request parsing has failed.
128    ParseError(RequestError),
129    /// Could not perform a read operation from stream successfully.
130    StreamReadError(SysError),
131    /// Could not perform a write operation to stream successfully.
132    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::StreamReadError2(inner) => write!(f, "Reading stream error: {}", inner),
143            Self::StreamWriteError(inner) => write!(f, "Writing stream error: {}", inner),
144        }
145    }
146}
147
148/// Errors pertaining to `HttpRoute`.
149#[derive(Debug)]
150#[allow(dead_code)]
151pub enum RouteError {
152    /// Handler for http routing path already exists.
153    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/// Errors pertaining to `HttpServer`.
165#[derive(Debug)]
166pub enum ServerError {
167    /// Error from one of the connections.
168    ConnectionError(ConnectionError),
169    /// Epoll operations failed.
170    IOError(std::io::Error),
171    /// Overflow occured while processing messages.
172    Overflow,
173    /// Server maximum capacity has been reached.
174    ServerFull,
175    /// Underflow occured while processing mesagges.
176    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/// The Body associated with an HTTP Request or Response.
192///
193/// ## Examples
194/// ```
195/// use dbs_uhttp::Body;
196/// let body = Body::new("This is a test body.".to_string());
197/// assert_eq!(body.raw(), b"This is a test body.");
198/// assert_eq!(body.len(), 20);
199/// ```
200#[derive(Clone, Debug, Eq, PartialEq)]
201pub struct Body {
202    /// Body of the HTTP message as bytes.
203    pub body: Vec<u8>,
204}
205
206impl Body {
207    /// Creates a new `Body` from a `String` input.
208    pub fn new<T: Into<Vec<u8>>>(body: T) -> Self {
209        Self { body: body.into() }
210    }
211
212    /// Returns the body as an `u8 slice`.
213    pub fn raw(&self) -> &[u8] {
214        self.body.as_slice()
215    }
216
217    /// Returns the length of the `Body`.
218    pub fn len(&self) -> usize {
219        self.body.len()
220    }
221
222    /// Checks if the body is empty, ie with zero length
223    pub fn is_empty(&self) -> bool {
224        self.body.len() == 0
225    }
226}
227
228/// Supported HTTP Methods.
229#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
230pub enum Method {
231    /// GET Method.
232    Get,
233    /// HEAD Method.
234    Head,
235    /// POST Method.
236    Post,
237    /// PUT Method.
238    Put,
239    /// PATCH Method.
240    Patch,
241    /// Delete Method.
242    Delete,
243}
244
245impl Method {
246    /// Returns a `Method` object if the parsing of `bytes` is successful.
247    ///
248    /// The method is case sensitive. A call to try_from with the input b"get" will return
249    /// an error, but when using the input b"GET", it returns Method::Get.
250    ///
251    /// # Errors
252    /// `InvalidHttpMethod` is returned if the specified HTTP method is unsupported.
253    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    /// Returns an `u8 slice` corresponding to the Method.
266    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    /// Returns an &str corresponding to the Method.
278    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/// Supported HTTP Versions.
291///
292/// # Examples
293/// ```
294/// use dbs_uhttp::Version;
295/// let version = Version::try_from(b"HTTP/1.1");
296/// assert!(version.is_ok());
297///
298/// let version = Version::try_from(b"http/1.1");
299/// assert!(version.is_err());
300/// ```
301#[derive(Clone, Copy, Debug, Eq, PartialEq)]
302pub enum Version {
303    /// HTTP/1.0
304    Http10,
305    /// HTTP/1.1
306    Http11,
307}
308
309impl Default for Version {
310    /// Returns the default HTTP version = HTTP/1.1.
311    fn default() -> Self {
312        Self::Http11
313    }
314}
315
316impl Version {
317    /// HTTP Version as an `u8 slice`.
318    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    /// Creates a new HTTP Version from an `u8 slice`.
326    ///
327    /// The supported versions are HTTP/1.0 and HTTP/1.1.
328    /// The version is case sensitive and the accepted input is upper case.
329    ///
330    /// # Errors
331    /// Returns a `InvalidHttpVersion` when the HTTP version is not supported.
332    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///Errors associated with a sys errno
344#[derive(Clone, Copy, Debug, Eq, PartialEq)]
345pub struct SysError(i32);
346
347impl SysError {
348    /// create SysError from errno
349    pub fn new(errno: i32) -> SysError {
350        SysError(errno)
351    }
352
353    /// create SysError from last_os_error
354    pub fn last() -> SysError {
355        SysError(std::io::Error::last_os_error().raw_os_error().unwrap())
356    }
357
358    /// get internal errno
359    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        // Tests for raw()
411        assert_eq!(Version::Http10.raw(), b"HTTP/1.0");
412        assert_eq!(Version::Http11.raw(), b"HTTP/1.1");
413
414        // Tests for try_from()
415        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        // Test for default()
423        assert_eq!(Version::default(), Version::Http11);
424    }
425
426    #[test]
427    fn test_method() {
428        // Test for raw
429        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        // Tests for try_from
438        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        // Test for is_empty
456        assert!(body.is_empty());
457        let body = Body::new("This is a body.".to_string());
458        // Test for len
459        assert_eq!(body.len(), 15);
460        // Test for raw
461        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}