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
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>,
    ),
    /// 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,
                ..
            }) => StaticFileResponse::Ok(Binary(body), etag, last_modified),
            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,
        }
    }
}