Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/cf-workers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gcp = ["multistore/gcp"]
multistore.workspace = true
bytes.workspace = true
http.workspace = true
percent-encoding = "2"
tracing.workspace = true
object_store.workspace = true
futures.workspace = true
Expand Down
56 changes: 56 additions & 0 deletions crates/cf-workers/src/cors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//! CORS header utilities for browser-accessible S3 proxies.

use http::HeaderMap;

/// Set permissive CORS headers suitable for public, browser-accessible
/// S3-compatible read-only proxies.
///
/// Sets:
/// - `access-control-allow-origin: *`
/// - `access-control-allow-methods: GET, HEAD, OPTIONS`
/// - `access-control-allow-headers: *`
/// - `access-control-expose-headers: *`
///
/// Existing CORS headers in the map are overwritten.
pub fn add_cors_headers(headers: &mut HeaderMap) {
let pairs = [
("access-control-allow-origin", "*"),
("access-control-allow-methods", "GET, HEAD, OPTIONS"),
("access-control-allow-headers", "*"),
("access-control-expose-headers", "*"),
];
for (name, value) in pairs {
if let Ok(v) = value.parse() {
headers.insert(name, v);
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn sets_all_four_cors_headers() {
let mut h = HeaderMap::new();
add_cors_headers(&mut h);
assert_eq!(h.get("access-control-allow-origin").unwrap(), "*");
assert_eq!(
h.get("access-control-allow-methods").unwrap(),
"GET, HEAD, OPTIONS"
);
assert_eq!(h.get("access-control-allow-headers").unwrap(), "*");
assert_eq!(h.get("access-control-expose-headers").unwrap(), "*");
}

#[test]
fn overwrites_existing() {
let mut h = HeaderMap::new();
h.insert(
"access-control-allow-origin",
"https://example.com".parse().unwrap(),
);
add_cors_headers(&mut h);
assert_eq!(h.get("access-control-allow-origin").unwrap(), "*");
}
}
3 changes: 3 additions & 0 deletions crates/cf-workers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
//! - [`WorkerSubscriber`] — `tracing::Subscriber` routing to `console.log`
//! - [`NoopCredentialRegistry`] — anonymous-only credential registry
//! - [`response`] — helpers for building `web_sys::Response` from proxy results
//! - [`add_cors_headers`] — set permissive CORS headers on a `HeaderMap`

pub(crate) mod fetch_connector;

pub mod backend;
pub mod body;
pub mod cors;
pub mod headers;
pub mod noop_creds;
pub mod request;
Expand All @@ -22,6 +24,7 @@ pub mod tracing_layer;

pub use backend::WorkerBackend;
pub use body::{collect_js_body, JsBody};
pub use cors::add_cors_headers;
pub use headers::WsHeaders;
pub use noop_creds::NoopCredentialRegistry;
pub use request::RequestParts;
Expand Down
4 changes: 3 additions & 1 deletion crates/cf-workers/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ impl RequestParts {

let uri: Uri = req.url().parse().map_err(|e| format!("invalid URL: {e}"))?;

let path = uri.path().to_string();
let path = percent_encoding::percent_decode_str(uri.path())
.decode_utf8_lossy()
.to_string();
let query = uri.query().map(|q| q.to_string());
let headers = headermap_from_js(&req.headers());

Expand Down
Loading