logo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use poem::{error::StaticFileError, Body};

use crate::{
    payload::{Binary, PlainText},
    ApiResponse,
};

/// A static file response.
#[cfg_attr(docsrs, doc(cfg(feature = "static-files")))]
#[derive(ApiResponse)]
#[oai(internal)]
pub enum StaticFileResponse {
    /// Ok
    #[oai(status = 200)]
    Ok(
        Binary<Body>,
        /// The ETag (or entity tag) HTTP response header is an identifier for a
        /// specific version of a resource. It lets caches be more efficient and
        /// save bandwidth, as a web server does not need to resend a full
        /// response if the content was not changed. Additionally, etags help to
        /// prevent simultaneous updates of a resource from overwriting each
        /// other ("mid-air collisions").
        ///
        /// Reference: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag>
        #[oai(header = "etag")]
        Option<String>,
        /// The Last-Modified response HTTP header contains a date and time when
        /// the origin server believes the resource was last modified. It is
        /// used as a validator to determine if the resource is the same as the
        /// previously stored one. Less accurate than an ETag header, it is a
        /// fallback mechanism. Conditional requests containing
        /// If-Modified-Since or If-Unmodified-Since headers make use of this
        /// field.
        ///
        /// Reference: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified>
        #[oai(header = "last-modified")]
        Option<String>,
        /// The Content-Type representation header is used to indicate the
        /// original media type of the resource (prior to any content encoding
        /// applied for sending).
        ///
        /// Reference: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type>
        #[oai(header = "content-type")]
        Option<String>,
    ),
    /// Not modified
    ///
    /// Reference: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304>
    #[oai(status = 304)]
    NotModified,
    /// Bad request
    ///
    /// Reference: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400>
    #[oai(status = 400)]
    BadRequest,
    /// Resource was not found
    #[oai(status = 404)]
    NotFound,
    /// Precondition failed
    ///
    /// Reference: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/412>
    #[oai(status = 412)]
    PreconditionFailed,
    /// Range not satisfiable
    ///
    /// Reference: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/416>
    #[oai(status = 416)]
    RangeNotSatisfiable(
        /// The Content-Range response HTTP header indicates where in a full
        /// body message a partial message belongs.
        ///
        /// Reference: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range>
        #[oai(header = "content-range")]
        String,
    ),
    /// Internal server error
    #[oai(status = 500)]
    InternalServerError(PlainText<String>),
}

impl StaticFileResponse {
    /// Create a static file response.
    pub fn new(res: Result<poem::web::StaticFileResponse, StaticFileError>) -> Self {
        res.into()
    }
}

impl From<Result<poem::web::StaticFileResponse, StaticFileError>> for StaticFileResponse {
    fn from(res: Result<poem::web::StaticFileResponse, StaticFileError>) -> Self {
        match res {
            Ok(poem::web::StaticFileResponse::Ok {
                body,
                etag,
                last_modified,
                content_type,
                ..
            }) => StaticFileResponse::Ok(Binary(body), etag, last_modified, content_type),
            Ok(poem::web::StaticFileResponse::NotModified) => StaticFileResponse::NotModified,
            Err(
                StaticFileError::MethodNotAllowed(_)
                | StaticFileError::NotFound
                | StaticFileError::InvalidPath
                | StaticFileError::Forbidden(_),
            ) => StaticFileResponse::NotFound,
            Err(StaticFileError::PreconditionFailed) => StaticFileResponse::PreconditionFailed,
            Err(StaticFileError::RangeNotSatisfiable { size }) => {
                StaticFileResponse::RangeNotSatisfiable(format!("*/{}", size))
            }
            Err(StaticFileError::Io(_)) => StaticFileResponse::BadRequest,
        }
    }
}