Skip to content

Commit 990b2f3

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 9abce7b commit 990b2f3

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
@@ -2895,6 +2895,7 @@ dependencies = [
28952895
"tokio-stream",
28962896
"tokio-tungstenite",
28972897
"tower",
2898+
"tower-http",
28982899
"tracing",
28992900
"tracing-subscriber",
29002901
"unicode-segmentation",

Cargo-recent.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3008,6 +3008,7 @@ dependencies = [
30083008
"tokio-stream",
30093009
"tokio-tungstenite",
30103010
"tower",
3011+
"tower-http",
30113012
"tracing",
30123013
"tracing-subscriber",
30133014
"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.2"
76+
tower-http = { version = "0.6.6", features = ["cors"] }
7677
tracing = "0.1.41"
7778
tracing-subscriber = { version = "0.3.19", 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;
@@ -370,13 +372,19 @@ fn build_app(services: Services) -> Router {
370372
#[cfg(feature = "access-control")]
371373
let geoip = services.geoip.clone();
372374

375+
let cors = CorsLayer::new()
376+
.allow_origin(Any)
377+
.allow_methods([Method::CONNECT, Method::GET, Method::OPTIONS, Method::POST])
378+
.allow_headers([CONTENT_TYPE, CONTENT_LENGTH]);
379+
373380
#[allow(unused_mut)]
374381
let mut router = Router::new()
375382
.fallback(route_request)
376383
.layer(
377384
ServiceBuilder::new()
378385
.layer(axum::middleware::from_fn_with_state(metrics.clone(), track_metrics))
379-
.layer(axum::middleware::from_fn_with_state(metrics, track_connections)),
386+
.layer(axum::middleware::from_fn_with_state(metrics, track_connections))
387+
.layer(cors),
380388
)
381389
.with_state(services);
382390

@@ -412,17 +420,17 @@ async fn route_request(
412420
/// Determines if a request should be routed to the OHTTP relay service.
413421
///
414422
/// Routing rules:
415-
/// - `(OPTIONS, _)` => CORS preflight handling
416423
/// - `(CONNECT, _)` => OHTTP bootstrap tunneling
417424
/// - `(POST, "/")` => relay to default gateway (needed for backwards-compatibility only)
418425
/// - `(POST, /http(s)://...)` => RFC 9540 opt-in gateway specified in path
419426
/// - `(GET, /http(s)://...)` => OHTTP bootstrap via WebSocket with opt-in gateway
427+
/// - `(OPTIONS, _)` => CORS preflight handling (handled by `tower_http::cors::CorsLayer`)
420428
fn is_relay_request(req: &axum::extract::Request) -> bool {
421429
let method = req.method();
422430
let path = req.uri().path();
423431

424432
match (method, path) {
425-
(&Method::OPTIONS, _) | (&Method::CONNECT, _) | (&Method::POST, "/") => true,
433+
(&Method::CONNECT, _) | (&Method::POST, "/") => true,
426434
(&Method::POST, p) | (&Method::GET, p)
427435
if p.starts_with("/http://") || p.starts_with("/https://") =>
428436
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)