Skip to content

Commit

Permalink
fix(ws server): support * in host and origin filtering (#781)
Browse files Browse the repository at this point in the history
* initial rewrite to re-use HTTP access control

* clean things up

* Update core/src/error.rs

* Update core/src/error.rs

* allow origin: add back removed Display impl

* cleanup again

* Update http-server/src/lib.rs

* Update examples/examples/cors_server.rs

* Update core/src/server/access_control/mod.rs

Co-authored-by: Tarik Gul <[email protected]>

* Update http-server/src/server.rs

Co-authored-by: Tarik Gul <[email protected]>

* fix bad comment

* remove todo

* fix grumbles

* more grumbles

* rename and document a bit

* remove `Access-Control-Allow-Origin` in whitelist

* fix nit: pub(super)

* fix bad naming

Co-authored-by: Tarik Gul <[email protected]>
  • Loading branch information
niklasad1 and TarikGul authored Jun 13, 2022
1 parent 6888804 commit 600cad0
Show file tree
Hide file tree
Showing 16 changed files with 431 additions and 488 deletions.
6 changes: 6 additions & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,25 @@ parking_lot = { version = "0.12", optional = true }
tokio = { version = "1.16", optional = true }
wasm-bindgen-futures = { version = "0.4.19", optional = true }
futures-timer = { version = "3", optional = true }
globset = { version = "0.4", optional = true }
lazy_static = { version = "1", optional = true }
unicase = { version = "2.6.0", optional = true }

[features]
default = []
http-helpers = ["hyper", "futures-util"]
server = [
"arrayvec",
"futures-util/alloc",
"globset",
"rustc-hash/std",
"tracing",
"parking_lot",
"rand",
"tokio/rt",
"tokio/sync",
"lazy_static",
"unicase",
]
client = ["futures-util/sink", "futures-channel/sink", "futures-channel/std"]
async-client = [
Expand Down
5 changes: 4 additions & 1 deletion core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,12 @@ pub enum Error {
/// Attempted to stop server that is already stopped.
#[error("Attempted to stop server that is already stopped")]
AlreadyStopped,
/// List passed into `set_allowed_origins` was empty
/// List passed into access control based on HTTP header verification.
#[error("Must set at least one allowed value for the {0} header")]
EmptyAllowList(&'static str),
/// Access control verification of HTTP headers failed.
#[error("HTTP header: `{0}` value: `{1}` verification failed")]
HttpHeaderRejected(&'static str, String),
/// Failed to execute a method because a resource was already at capacity
#[error("Resource at capacity: {0}")]
ResourceAtCapacity(&'static str),
Expand Down
37 changes: 34 additions & 3 deletions core/src/http_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,25 @@ pub fn read_header_value<'a>(headers: &'a hyper::header::HeaderMap, header_name:
pub fn read_header_values<'a>(
headers: &'a hyper::header::HeaderMap,
header_name: &str,
) -> hyper::header::ValueIter<'a, hyper::header::HeaderValue> {
headers.get_all(header_name).iter()
) -> hyper::header::GetAll<'a, hyper::header::HeaderValue> {
headers.get_all(header_name)
}

/// Get the header values from the `access-control-request-headers` header.
pub fn get_cors_request_headers<'a>(headers: &'a hyper::header::HeaderMap) -> impl Iterator<Item = &str> {
const ACCESS_CONTROL_REQUEST_HEADERS: &str = "access-control-request-headers";

read_header_values(headers, ACCESS_CONTROL_REQUEST_HEADERS)
.iter()
.filter_map(|val| val.to_str().ok())
.flat_map(|val| val.split(","))
// The strings themselves might contain leading and trailing whitespaces
.map(|s| s.trim())
}

#[cfg(test)]
mod tests {
use super::{read_body, read_header_content_length};
use super::{get_cors_request_headers, read_body, read_header_content_length};

#[tokio::test]
async fn body_to_bytes_size_limit_works() {
Expand All @@ -132,4 +144,23 @@ mod tests {
headers.insert(hyper::header::CONTENT_LENGTH, "18446744073709551616".parse().unwrap());
assert_eq!(read_header_content_length(&headers), None);
}

#[test]
fn get_cors_headers_works() {
let mut headers = hyper::header::HeaderMap::new();

// access-control-request-headers
headers.insert(hyper::header::ACCESS_CONTROL_REQUEST_HEADERS, "Content-Type,x-requested-with".parse().unwrap());

let values: Vec<&str> = get_cors_request_headers(&headers).collect();
assert_eq!(values, vec!["Content-Type", "x-requested-with"]);

headers.insert(
hyper::header::ACCESS_CONTROL_REQUEST_HEADERS,
"Content-Type, x-requested-with ".parse().unwrap(),
);

let values: Vec<&str> = get_cors_request_headers(&headers).collect();
assert_eq!(values, vec!["Content-Type", "x-requested-with"]);
}
}
Loading

0 comments on commit 600cad0

Please sign in to comment.