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
149 changes: 149 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions dropshot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,12 @@ features = [ "uuid" ]

[dev-dependencies]
expectorate = "1.0.4"
hyper-staticfile = "0.8"
lazy_static = "1.4.0"
libc = "0.2.112"
mime_guess = "2.0.3"
subprocess = "0.2.8"
tempfile = "3.2"
trybuild = "1.0.53"

[dev-dependencies.schemars]
Expand Down
5 changes: 3 additions & 2 deletions dropshot/examples/file_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,10 @@ async fn static_content(
.header(http::header::CONTENT_TYPE, "text/html")
.body(body.into())?)
} else {
let body = tokio::fs::read(&entry).await.map_err(|_| {
let file = tokio::fs::File::open(&entry).await.map_err(|_| {
HttpError::for_bad_request(None, "EBADF".to_string())
})?;
let file_stream = hyper_staticfile::FileBytesStream::new(file);

/* Derive the MIME type from the file name */
let content_type = mime_guess::from_path(&entry)
Expand All @@ -151,7 +152,7 @@ async fn static_content(
Ok(Response::builder()
.status(StatusCode::OK)
.header(http::header::CONTENT_TYPE, content_type)
.body(body.into())?)
.body(file_stream.into_body())?)
}
}

Expand Down
55 changes: 45 additions & 10 deletions dropshot/src/test_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,37 @@ use crate::logging::ConfigLogging;
use crate::pagination::ResultsPage;
use crate::server::{HttpServer, HttpServerStarter, ServerContext};

/**
* List of allowed HTTP headers in responses. This is used to make sure we
* don't leak headers unexpectedly.
*/
const ALLOWED_HEADER_NAMES: [&str; 4] =
["content-length", "content-type", "date", "x-request-id"];
enum AllowedValue<'a> {
Any,
OneOf(&'a [&'a str]),
}

struct AllowedHeader<'a> {
name: &'a str,
value: AllowedValue<'a>,
}

impl<'a> AllowedHeader<'a> {
const fn new(name: &'a str) -> Self {
Self {
name,
value: AllowedValue::Any,
}
}
}

// List of allowed HTTP headers in responsees.
// Used to make sure we don't leak headers unexpectedly.
const ALLOWED_HEADERS: [AllowedHeader<'static>; 5] = [
AllowedHeader::new("content-length"),
AllowedHeader::new("content-type"),
AllowedHeader::new("date"),
AllowedHeader::new("x-request-id"),
AllowedHeader {
name: "transfer-encoding",
value: AllowedValue::OneOf(&["chunked"]),
},
];

/**
* ClientTestContext encapsulates several facilities associated with using an
Expand Down Expand Up @@ -199,11 +224,21 @@ impl ClientTestContext {
* statically-defined above.
*/
let headers = response.headers();
for header_name in headers.keys() {
for (header_name, header_value) in headers {
let mut okay = false;
for allowed_name in ALLOWED_HEADER_NAMES.iter() {
if header_name == allowed_name {
okay = true;
for allowed_header in ALLOWED_HEADERS.iter() {
if header_name == allowed_header.name {
match allowed_header.value {
AllowedValue::Any => {
okay = true;
}
AllowedValue::OneOf(allowed_values) => {
let header = header_value
.to_str()
.expect("Cannot turn header value to string");
okay = allowed_values.contains(&header);
}
}
break;
}
}
Expand Down
Loading