From 9d2cb9293deecd7eccde6c3d318c745e584b66f6 Mon Sep 17 00:00:00 2001 From: Lionel Sambuc Date: Wed, 11 Sep 2019 10:28:30 +0200 Subject: [PATCH] Add basic CORS support --- src/main.rs | 27 +++++++++- src/rest_api/mod.rs | 125 ++++++++++++++++++++++++++------------------ 2 files changed, 99 insertions(+), 53 deletions(-) diff --git a/src/main.rs b/src/main.rs index 57213cd..87fb7c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,6 +45,11 @@ fn main() { if std::env::var("MERCATOR_BASE").is_err() { std::env::set_var("MERCATOR_BASE", "/spatial-search"); } + + if std::env::var("MERCATOR_ALLOWED_ORIGINS").is_err() { + // Allow by default access from a locally running Swagger Editor instance. + std::env::set_var("MERCATOR_ALLOWED_ORIGINS", "http://localhost:3200"); + } /* UNUSED FOR NOW if std::env::var("MERCATOR_DATA").is_err() { std::env::set_var("MERCATOR_DATA", "."); @@ -54,6 +59,7 @@ fn main() { let hostname; let port; let base; + let allowed_origins: Vec; //let data; match std::env::var("MERCATOR_HOST") { @@ -86,6 +92,19 @@ fn main() { } }; + match std::env::var("MERCATOR_ALLOWED_ORIGINS") { + Ok(val) => { + allowed_origins = val + .split(',') + .map(|s| s.trim().to_string()) + .collect::>() + } + Err(val) => { + error!("Could not fetch {} : `{}`", "MERCATOR_ALLOWED_ORIGINS", val); + exit(1); + } + }; + /* UNUSED FOR NOW match std::env::var("MERCATOR_DATA") { Ok(val) => data = val, @@ -149,5 +168,11 @@ fn main() { // END of Temporary bloc } - rest_api::run(hostname, port, base, Arc::new(RwLock::new(db))); + rest_api::run( + hostname, + port, + base, + allowed_origins, + Arc::new(RwLock::new(db)), + ); } diff --git a/src/rest_api/mod.rs b/src/rest_api/mod.rs index bf91ee3..b4a93ad 100644 --- a/src/rest_api/mod.rs +++ b/src/rest_api/mod.rs @@ -15,9 +15,10 @@ use std::sync::Arc; use std::sync::RwLock; use actix_web::fs; +use actix_web::http; use actix_web::http::Method; use actix_web::http::StatusCode; -use actix_web::middleware; +use actix_web::middleware::cors::Cors; use actix_web::pred; use actix_web::server; use actix_web::server::HttpHandler; @@ -87,6 +88,7 @@ where fn get_app( prefix: S, + allowed_origins: &[&'static str], state: Arc>, ) -> Vec>>> where @@ -94,9 +96,6 @@ where { vec![ App::with_state(AppState { shared: state }) - .middleware( - middleware::DefaultHeaders::new().header("Access-Control-Allow-Origin", "*"), - ) .prefix(into_static(prefix).to_string()) .middleware(middleware::Logger::new( r#"%a "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T[s] %D[ms]"#, @@ -108,55 +107,67 @@ where .filter(pred::Not(pred::Get())) .f(default::page_400); }) - .resource("/queries", |r| { - r.method(Method::POST).f(actions::query); - r.route() - .filter(pred::Not(pred::Post())) - .f(default::page_400); - }) - // SPACES ------------------------------------------------------------------- - .resource("/spaces", |r| { - r.method(Method::POST).f(spaces::post); - r.method(Method::PUT).f(spaces::put); - r.method(Method::PATCH).f(spaces::patch); - r.method(Method::DELETE).f(spaces::delete); - }) - .resource("/spaces/{name}", |r| { - r.method(Method::PUT).with(space::put); - r.method(Method::PATCH).with(space::patch); - r.method(Method::GET).with(space::get); - r.method(Method::DELETE).with(space::delete); - }) - // DATASETS ------------------------------------------------------------------- - .resource("/cores", |r| { - r.method(Method::POST).f(&cores::post); - r.method(Method::PUT).f(&cores::put); - r.method(Method::PATCH).f(&cores::patch); - r.method(Method::DELETE).f(&cores::delete); - }) - .resource("/cores/{name}", |r| { - r.method(Method::PUT).with(core::put); - r.method(Method::GET).with(core::get); - r.method(Method::PATCH).with(core::patch); - r.method(Method::DELETE).with(core::delete); - }) - // SPATIAL OBJECTS ------------------------------------------------------------------- - .resource("/cores/{name}/spatial_objects", |r| { - r.method(Method::POST).with(spatial_objects::post); - r.method(Method::PUT).with(spatial_objects::put); - r.method(Method::PATCH).with(spatial_objects::patch); - r.method(Method::DELETE).with(spatial_objects::delete); - }) - .resource("/cores/{name}/spatial_objects/{id}", |r| { - r.method(Method::PUT).with(spatial_object::put); - r.method(Method::GET).with(spatial_object::get); - r.method(Method::PATCH).with(spatial_object::patch); - r.method(Method::DELETE).with(spatial_object::delete); - }) // DEFAULT ------------------------------------------------------------------- .default_resource(|r| { r.f(default::page_400); }) + // REQUIRES CORS Support --------------------------------------------------------------- + .configure(|app| { + let mut cors = Cors::for_app(app); + for origin in allowed_origins { + cors.allowed_origin(origin); + } + cors.allowed_methods(vec!["GET", "POST", "UPDATE", "PATCH", "DELETE", "OPTIONS"]) + .allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT]) + .allowed_header(http::header::CONTENT_TYPE) + .max_age(60) + .resource("/queries", |r| { + r.method(Method::POST).f(actions::query); + r.route() + .filter(pred::Not(pred::Post())) + .f(default::page_400); + }) + // SPACES ------------------------------------------------------------------- + .resource("/spaces", |r| { + r.method(Method::POST).f(spaces::post); + r.method(Method::PUT).f(spaces::put); + r.method(Method::PATCH).f(spaces::patch); + r.method(Method::DELETE).f(spaces::delete); + }) + .resource("/spaces/{name}", |r| { + r.method(Method::PUT).with(space::put); + r.method(Method::PATCH).with(space::patch); + r.method(Method::GET).with(space::get); + r.method(Method::DELETE).with(space::delete); + }) + // DATASETS ------------------------------------------------------------------- + .resource("/cores", |r| { + r.method(Method::POST).f(&cores::post); + r.method(Method::PUT).f(&cores::put); + r.method(Method::PATCH).f(&cores::patch); + r.method(Method::DELETE).f(&cores::delete); + }) + .resource("/cores/{name}", |r| { + r.method(Method::PUT).with(core::put); + r.method(Method::GET).with(core::get); + r.method(Method::PATCH).with(core::patch); + r.method(Method::DELETE).with(core::delete); + }) + // SPATIAL OBJECTS ------------------------------------------------------------------- + .resource("/cores/{name}/spatial_objects", |r| { + r.method(Method::POST).with(spatial_objects::post); + r.method(Method::PUT).with(spatial_objects::put); + r.method(Method::PATCH).with(spatial_objects::patch); + r.method(Method::DELETE).with(spatial_objects::delete); + }) + .resource("/cores/{name}/spatial_objects/{id}", |r| { + r.method(Method::PUT).with(spatial_object::put); + r.method(Method::GET).with(spatial_object::get); + r.method(Method::PATCH).with(spatial_object::patch); + r.method(Method::DELETE).with(spatial_object::delete); + }) + .register() + }) .boxed(), App::new() .resource("/static/{file}", |r| { @@ -175,8 +186,13 @@ where ] } -pub fn run(host: S, port: u16, prefix: S, state: Arc>) -where +pub fn run( + host: S, + port: u16, + prefix: S, + allowed_origins: Vec, + state: Arc>, +) where S: Into, { info!("Initializing server..."); @@ -185,7 +201,12 @@ where let prefix = into_static(prefix); let host = host.into(); - server::new(move || get_app(prefix, state.clone())) + let mut origins = Vec::with_capacity(allowed_origins.len()); + for origin in allowed_origins { + origins.push(into_static(origin)); + } + + server::new(move || get_app(prefix, &origins, state.clone())) .bind(format!("{}:{}", host, port)) .unwrap() .start();