feature-2924: Add an option to suppress server identification headers (#3770)
Co-authored-by: Gerard Guillemas Martos <gguillemas@users.noreply.github.com> Co-authored-by: Micha de Vries <micha@devrie.sh>
This commit is contained in:
parent
2913917284
commit
a11f1bc82f
5 changed files with 54 additions and 9 deletions
|
@ -18,4 +18,5 @@ pub struct Config {
|
||||||
pub key: Option<PathBuf>,
|
pub key: Option<PathBuf>,
|
||||||
pub tick_interval: Duration,
|
pub tick_interval: Duration,
|
||||||
pub engine: Option<EngineOptions>,
|
pub engine: Option<EngineOptions>,
|
||||||
|
pub no_identification_headers: bool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,10 @@ pub struct StartCommandArguments {
|
||||||
#[arg(env = "SURREAL_BIND", short = 'b', long = "bind")]
|
#[arg(env = "SURREAL_BIND", short = 'b', long = "bind")]
|
||||||
#[arg(default_value = "127.0.0.1:8000")]
|
#[arg(default_value = "127.0.0.1:8000")]
|
||||||
listen_addresses: Vec<SocketAddr>,
|
listen_addresses: Vec<SocketAddr>,
|
||||||
|
#[arg(help = "Whether to suppress the server name and version headers")]
|
||||||
|
#[arg(env = "SURREAL_NO_IDENTIFICATION_HEADERS", long)]
|
||||||
|
#[arg(default_value_t = false)]
|
||||||
|
no_identification_headers: bool,
|
||||||
//
|
//
|
||||||
// Database options
|
// Database options
|
||||||
//
|
//
|
||||||
|
@ -142,6 +145,7 @@ pub async fn init(
|
||||||
log,
|
log,
|
||||||
tick_interval,
|
tick_interval,
|
||||||
no_banner,
|
no_banner,
|
||||||
|
no_identification_headers,
|
||||||
..
|
..
|
||||||
}: StartCommandArguments,
|
}: StartCommandArguments,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
@ -171,6 +175,7 @@ pub async fn init(
|
||||||
user,
|
user,
|
||||||
pass,
|
pass,
|
||||||
tick_interval,
|
tick_interval,
|
||||||
|
no_identification_headers,
|
||||||
crt: web.as_ref().and_then(|x| x.web_crt.clone()),
|
crt: web.as_ref().and_then(|x| x.web_crt.clone()),
|
||||||
key: web.as_ref().and_then(|x| x.web_key.clone()),
|
key: web.as_ref().and_then(|x| x.web_key.clone()),
|
||||||
engine: None,
|
engine: None,
|
||||||
|
|
|
@ -27,13 +27,25 @@ pub use db::SurrealDatabase;
|
||||||
pub use id::SurrealId;
|
pub use id::SurrealId;
|
||||||
pub use ns::SurrealNamespace;
|
pub use ns::SurrealNamespace;
|
||||||
|
|
||||||
pub fn add_version_header() -> SetResponseHeaderLayer<HeaderValue> {
|
pub fn add_version_header(enabled: bool) -> SetResponseHeaderLayer<Option<HeaderValue>> {
|
||||||
let val = format!("{PKG_NAME}-{}", *PKG_VERSION);
|
let header_value = if enabled {
|
||||||
SetResponseHeaderLayer::if_not_present(VERSION.to_owned(), HeaderValue::try_from(val).unwrap())
|
let val = format!("{PKG_NAME}-{}", *PKG_VERSION);
|
||||||
|
Some(HeaderValue::try_from(val).unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
SetResponseHeaderLayer::if_not_present(VERSION.to_owned(), header_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_server_header() -> SetResponseHeaderLayer<HeaderValue> {
|
pub fn add_server_header(enabled: bool) -> SetResponseHeaderLayer<Option<HeaderValue>> {
|
||||||
SetResponseHeaderLayer::if_not_present(SERVER, HeaderValue::try_from(SERVER_NAME).unwrap())
|
let header_value = if enabled {
|
||||||
|
Some(HeaderValue::try_from(SERVER_NAME).unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
SetResponseHeaderLayer::if_not_present(SERVER, header_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a TypedHeader, returning None if the header is missing and an error if the header is invalid.
|
// Parse a TypedHeader, returning None if the header is missing and an error if the header is invalid.
|
||||||
|
|
|
@ -137,8 +137,8 @@ pub async fn init(ct: CancellationToken) -> Result<(), Error> {
|
||||||
.layer(HttpMetricsLayer)
|
.layer(HttpMetricsLayer)
|
||||||
.layer(SetSensitiveResponseHeadersLayer::from_shared(headers))
|
.layer(SetSensitiveResponseHeadersLayer::from_shared(headers))
|
||||||
.layer(AsyncRequireAuthorizationLayer::new(auth::SurrealAuth))
|
.layer(AsyncRequireAuthorizationLayer::new(auth::SurrealAuth))
|
||||||
.layer(headers::add_server_header())
|
.layer(headers::add_server_header(!opt.no_identification_headers))
|
||||||
.layer(headers::add_version_header())
|
.layer(headers::add_version_header(!opt.no_identification_headers))
|
||||||
.layer(
|
.layer(
|
||||||
CorsLayer::new()
|
CorsLayer::new()
|
||||||
.allow_methods([
|
.allow_methods([
|
||||||
|
|
|
@ -11,7 +11,7 @@ mod http_integration {
|
||||||
use test_log::test;
|
use test_log::test;
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
|
|
||||||
use super::common::{self, PASS, USER};
|
use super::common::{self, StartServerArguments, PASS, USER};
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn basic_auth() -> Result<(), Box<dyn std::error::Error>> {
|
async fn basic_auth() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
@ -352,6 +352,33 @@ mod http_integration {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test(tokio::test)]
|
||||||
|
async fn no_server_id_headers() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// default server has the id headers
|
||||||
|
{
|
||||||
|
let (addr, _server) = common::start_server_with_defaults().await.unwrap();
|
||||||
|
let url = &format!("http://{addr}/health");
|
||||||
|
|
||||||
|
let res = Client::default().get(url).send().await?;
|
||||||
|
assert!(res.headers().contains_key("server"));
|
||||||
|
assert!(res.headers().contains_key("surreal-version"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn on the no-identification-headers option to suppress headers
|
||||||
|
{
|
||||||
|
let mut start_server_arguments = StartServerArguments::default();
|
||||||
|
start_server_arguments.args.push_str(" --no-identification-headers");
|
||||||
|
let (addr, _server) = common::start_server(start_server_arguments).await.unwrap();
|
||||||
|
let url = &format!("http://{addr}/health");
|
||||||
|
|
||||||
|
let res = Client::default().get(url).send().await?;
|
||||||
|
assert!(!res.headers().contains_key("server"));
|
||||||
|
assert!(!res.headers().contains_key("surreal-version"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn import_endpoint() -> Result<(), Box<dyn std::error::Error>> {
|
async fn import_endpoint() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let (addr, _server) = common::start_server_with_defaults().await.unwrap();
|
let (addr, _server) = common::start_server_with_defaults().await.unwrap();
|
||||||
|
|
Loading…
Reference in a new issue