restrepo 0.5.12

A collection of components for building restful webservices with actix-web
Documentation
//! Contains a builder for a customizable [actix_cors::Cors] middleware
use actix_cors::Cors;
use actix_web::http::Method;

/// Can be used to create a [actix_cors::Cors] middleware with a REST friendly default config.
///
/// * Allowed headers: `AUTHORIZATION`, `ACCEPT`, `CONTENT-TYPE`, `USER-AGENT`
/// * Allowed methods: `GET`, `POST`, `PUT`, `DELETE`, `HEAD`, `OPTIONS`
/// * Maximal request cache age: 3600 s
///
/// ### Example
/// ```no_run
/// use actix_web::{App, HttpServer, HttpResponse, web::get};
/// use restrepo::security::create_cors_middleware_builder;
///
/// #[actix_web::main]
/// async fn main() -> Result<(), impl std::error::Error> {
///     HttpServer::new(move || {
///         let cors = create_cors_middleware_builder().send_wildcard();
///         App::new()
///             .wrap(cors)
///             .route("/", get().to(HttpResponse::Ok))
///     })
///     .bind("127.0.0.1:8000".to_string())?
///     .run()
///     .await
/// }
/// ```
pub fn create_cors_middleware_builder() -> Cors {
    Cors::default()
        .block_on_origin_mismatch(true)
        .allowed_methods(vec![
            Method::GET,
            Method::POST,
            Method::DELETE,
            Method::PUT,
            Method::PATCH,
        ])
        .allowed_headers(vec![
            actix_web::http::header::AUTHORIZATION,
            actix_web::http::header::ACCEPT,
            actix_web::http::header::CONTENT_TYPE,
            actix_web::http::header::USER_AGENT,
        ])
        .max_age(3600)
}

#[cfg(test)]
mod tests {
    use super::*;
    use actix_web::{App, HttpResponse, http, test, web};

    #[actix_web::test]
    async fn test_cors_middleware_builder() {
        let cors = create_cors_middleware_builder().allowed_origin("https://foo.xz");
        let app = test::init_service(
            App::new().wrap(cors).service(
                web::resource("/test")
                    .get(HttpResponse::Ok)
                    .post(HttpResponse::Created)
                    .delete(HttpResponse::NoContent)
                    .put(HttpResponse::Ok)
                    .patch(HttpResponse::Accepted),
            ),
        )
        .await;
        for (m, s) in [
            (Method::GET, http::StatusCode::OK),
            (Method::POST, http::StatusCode::CREATED),
            (Method::DELETE, http::StatusCode::NO_CONTENT),
            (Method::PUT, http::StatusCode::OK),
            (Method::PATCH, http::StatusCode::ACCEPTED),
        ] {
            let req = test::TestRequest::default()
                .uri("/test")
                .insert_header(("Origin", "https://foo.xz"))
                .insert_header(("Authorization", "12345"))
                .insert_header(("Content-Type", "application/json"))
                .insert_header(("Accept", "application/json"))
                .method(m)
                .to_request();
            let resp = test::call_service(&app, req).await;
            assert_eq!(resp.status(), s);
            assert_eq!(
                resp.headers().get("vary").unwrap(),
                "Origin, Access-Control-Request-Method, Access-Control-Request-Headers"
            );
        }
        let bad_origin_req = test::TestRequest::default()
            .uri("/test")
            .insert_header(("Origin", "https://bar.xz"))
            .to_request();
        let bad_origin_resp = test::call_service(&app, bad_origin_req).await;
        assert_eq!(bad_origin_resp.status(), http::StatusCode::BAD_REQUEST);
    }
}