Skip to content

Commit 39186a3

Browse files
committed
Use tower-http corslayer for handling cors
This pr addresses part of #941. it replaces the custom cors handling with tower-http corslayer
1 parent 895d677 commit 39186a3

6 files changed

Lines changed: 18 additions & 29 deletions

File tree

Cargo-minimal.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2900,6 +2900,7 @@ dependencies = [
29002900
"tokio-stream",
29012901
"tokio-tungstenite",
29022902
"tower",
2903+
"tower-http",
29032904
"tracing",
29042905
"tracing-subscriber",
29052906
"unicode-segmentation",

Cargo-recent.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2876,6 +2876,7 @@ dependencies = [
28762876
"tokio-stream",
28772877
"tokio-tungstenite",
28782878
"tower",
2879+
"tower-http",
28792880
"tracing",
28802881
"tracing-subscriber",
28812882
"unicode-segmentation",

payjoin-mailroom/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ tokio-rustls-acme = { version = "0.9.0", features = ["axum"], optional = true }
7373
tokio-stream = { version = "0.1.17", features = ["net"] }
7474
tokio-tungstenite = { version = "0.27.0", optional = true }
7575
tower = "0.5"
76+
tower-http = { version = "0.6", features = ["cors"] }
7677
tracing = "0.1"
7778
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
7879
unicode-segmentation = "=1.12.0"

payjoin-mailroom/src/directory.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::task::{Context, Poll};
55

66
use anyhow::Result;
77
use axum::body::{Body, Bytes};
8-
use axum::http::header::{HeaderValue, ACCESS_CONTROL_ALLOW_ORIGIN, CONTENT_TYPE};
8+
use axum::http::header::{HeaderValue, CONTENT_TYPE};
99
use axum::http::{Method, Request, Response, StatusCode, Uri};
1010
use http_body_util::BodyExt;
1111
use payjoin::directory::{ShortId, ShortIdError, ENCAPSULATED_MESSAGE_BYTES};
@@ -148,7 +148,7 @@ impl<D: Db> Service<D> {
148148
}
149149
}
150150

151-
let mut response = match (parts.method, path_segments.as_slice()) {
151+
let response = match (parts.method, path_segments.as_slice()) {
152152
(Method::POST, ["", ".well-known", "ohttp-gateway"]) =>
153153
self.handle_ohttp_gateway(body).await,
154154
(Method::GET, ["", ".well-known", "ohttp-gateway"]) =>
@@ -162,8 +162,6 @@ impl<D: Db> Service<D> {
162162
}
163163
.unwrap_or_else(|e| e.to_response());
164164

165-
// Allow CORS for third-party access
166-
response.headers_mut().insert(ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static("*"));
167165
Ok(response)
168166
}
169167

payjoin-mailroom/src/lib.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[cfg(feature = "access-control")]
22
use axum::extract::connect_info::Connected;
33
use axum::extract::State;
4+
use axum::http::header::{CONTENT_LENGTH, CONTENT_TYPE};
45
use axum::http::Method;
56
use axum::response::{IntoResponse, Response};
67
#[cfg(feature = "access-control")]
@@ -11,6 +12,7 @@ use opentelemetry_sdk::metrics::SdkMeterProvider;
1112
use rand::Rng;
1213
use tokio_listener::{Listener, SystemOptions, UserOptions};
1314
use tower::{Service, ServiceBuilder};
15+
use tower_http::cors::{Any, CorsLayer};
1416
use tracing::info;
1517

1618
use crate::ohttp_relay::SentinelTag;
@@ -363,13 +365,19 @@ fn build_app(services: Services) -> Router {
363365
#[cfg(feature = "access-control")]
364366
let geoip = services.geoip.clone();
365367

368+
let cors = CorsLayer::new()
369+
.allow_origin(Any)
370+
.allow_methods([Method::CONNECT, Method::GET, Method::OPTIONS, Method::POST])
371+
.allow_headers([CONTENT_TYPE, CONTENT_LENGTH]);
372+
366373
#[allow(unused_mut)]
367374
let mut router = Router::new()
368375
.fallback(route_request)
369376
.layer(
370377
ServiceBuilder::new()
371378
.layer(axum::middleware::from_fn_with_state(metrics.clone(), track_metrics))
372-
.layer(axum::middleware::from_fn_with_state(metrics, track_connections)),
379+
.layer(axum::middleware::from_fn_with_state(metrics, track_connections))
380+
.layer(cors),
373381
)
374382
.with_state(services);
375383

@@ -405,17 +413,17 @@ async fn route_request(
405413
/// Determines if a request should be routed to the OHTTP relay service.
406414
///
407415
/// Routing rules:
408-
/// - `(OPTIONS, _)` => CORS preflight handling
409416
/// - `(CONNECT, _)` => OHTTP bootstrap tunneling
410417
/// - `(POST, "/")` => relay to default gateway (needed for backwards-compatibility only)
411418
/// - `(POST, /http(s)://...)` => RFC 9540 opt-in gateway specified in path
412419
/// - `(GET, /http(s)://...)` => OHTTP bootstrap via WebSocket with opt-in gateway
420+
/// - `(OPTIONS, _)` => CORS preflight handling (handled by `tower_http::cors::CorsLayer`)
413421
fn is_relay_request(req: &axum::extract::Request) -> bool {
414422
let method = req.method();
415423
let path = req.uri().path();
416424

417425
match (method, path) {
418-
(&Method::OPTIONS, _) | (&Method::CONNECT, _) | (&Method::POST, "/") => true,
426+
(&Method::CONNECT, _) | (&Method::POST, "/") => true,
419427
(&Method::POST, p) | (&Method::GET, p)
420428
if p.starts_with("/http://") || p.starts_with("/https://") =>
421429
true,

payjoin-mailroom/src/ohttp_relay/mod.rs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@ use http::uri::Authority;
1010
use http_body_util::combinators::BoxBody;
1111
use http_body_util::{BodyExt, Empty, Full};
1212
use hyper::body::{Bytes, Incoming};
13-
use hyper::header::{
14-
HeaderValue, ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_METHODS,
15-
ACCESS_CONTROL_ALLOW_ORIGIN, CONTENT_LENGTH, CONTENT_TYPE,
16-
};
13+
use hyper::header::{HeaderValue, CONTENT_LENGTH, CONTENT_TYPE};
1714
use hyper::{Method, Request, Response};
1815
use hyper_rustls::builderstates::WantsSchemes;
1916
use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder};
@@ -160,8 +157,7 @@ where
160157
let path = req.uri().path();
161158
let authority = req.uri().authority().cloned();
162159

163-
let mut res = match (&method, path) {
164-
(&Method::OPTIONS, _) => Ok(handle_preflight()),
160+
let res = match (&method, path) {
165161
(&Method::GET, "/health") => Ok(health_check().await),
166162
(&Method::POST, _) => match parse_gateway_uri(&method, path, authority, config).await {
167163
Ok(gateway_uri) => handle_ohttp_relay(req, config, gateway_uri).await,
@@ -178,7 +174,6 @@ where
178174
_ => Err(Error::NotFound),
179175
}
180176
.unwrap_or_else(|e| e.to_response());
181-
res.headers_mut().insert(ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static("*"));
182177
Ok(res)
183178
}
184179

@@ -227,21 +222,6 @@ fn parse_gateway_uri_from_path(path: &str, default: &GatewayUri) -> Result<Gatew
227222
}
228223
}
229224

230-
fn handle_preflight() -> Response<BoxBody<Bytes, hyper::Error>> {
231-
let mut res = Response::new(empty());
232-
*res.status_mut() = hyper::StatusCode::NO_CONTENT;
233-
res.headers_mut().insert(ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static("*"));
234-
res.headers_mut().insert(
235-
ACCESS_CONTROL_ALLOW_METHODS,
236-
HeaderValue::from_static("CONNECT, GET, OPTIONS, POST"),
237-
);
238-
res.headers_mut().insert(
239-
ACCESS_CONTROL_ALLOW_HEADERS,
240-
HeaderValue::from_static("Content-Type, Content-Length"),
241-
);
242-
res
243-
}
244-
245225
async fn health_check() -> Response<BoxBody<Bytes, hyper::Error>> { Response::new(empty()) }
246226

247227
#[instrument]

0 commit comments

Comments
 (0)