This commit is contained in:
Mateusz Gruszczyński committed 2026-10-03 18:53:51 +02:00
1 parent d3f0f060bf
commit 2e4aa4df4d
33 files changed
+3704 -3566

No files matched your search

+103 -2
View File
@@ -1447,6 +1447,13 @@ struct ResponseSection {
compression: crate::compression::Settings,
}
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct LoggingSection {
logging: crate::logging::Settings,
error_log: crate::logging::ErrorLogSettings,
}
fn invalid_section(section: &str, error: serde_json::Error) -> ApiError {
ApiError(
StatusCode::BAD_REQUEST,
@@ -1502,8 +1509,17 @@ async fn update_section(
serde_json::from_value(value).map_err(|e| invalid_section(&section, e))?
}
"logging" => {
config.logging =
serde_json::from_value(value).map_err(|e| invalid_section(&section, e))?
if value.get("logging").is_some() || value.get("error_log").is_some() {
let part: LoggingSection =
serde_json::from_value(value).map_err(|e| invalid_section(&section, e))?;
config.logging = part.logging;
config.error_log = part.error_log;
} else {
// Backward compatibility for clients that still send only the
// historical access-logging object to /api/config/logging.
config.logging =
serde_json::from_value(value).map_err(|e| invalid_section(&section, e))?;
}
}
"forwarding" => {
config.forwarding =
@@ -2387,6 +2403,91 @@ mod tests {
store.close().await;
}
#[tokio::test]
async fn logging_section_persists_error_log_settings_atomically() {
let (router, store, dir, secret, csrf) = fixture().await;
let cookie = format!("{}={secret}", auth::COOKIE_NAME);
let logging = Config::default().logging;
let mut error_log = Config::default().error_log;
error_log.enabled = true;
error_log.path = "/tmp/rustproxy-error.log".into();
let response = router
.clone()
.oneshot(
request("/api/config/logging")
.method("PUT")
.header("content-type", "application/json")
.header("cookie", &cookie)
.header("origin", "http://127.0.0.1:9090")
.header("x-rustproxy-request", "1")
.header("x-csrf-token", &csrf)
.body(Body::from(
serde_json::to_vec(&json!({
"expected_revision": 0,
"value": {
"logging": logging,
"error_log": error_log,
},
}))
.unwrap(),
))
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let updated = json_body(response).await;
assert_eq!(updated["revision"], 1);
assert_eq!(updated["config"]["error_log"]["enabled"], true);
assert_eq!(updated["config"]["error_log"]["path"], "/tmp/rustproxy-error.log");
let configuration = router
.oneshot(
request("/api/config")
.header("cookie", &cookie)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
let persisted = json_body(configuration).await;
assert_eq!(persisted["config"]["error_log"]["enabled"], true);
assert_eq!(persisted["config"]["error_log"]["path"], "/tmp/rustproxy-error.log");
drop(router);
store.close().await;
let reopened = Store::open(&dir.path().join("db"), &Config::default())
.await
.unwrap();
let persisted = reopened.load().await.unwrap();
assert_eq!(persisted.revision, 1);
assert!(persisted.config.error_log.enabled);
assert_eq!(persisted.config.error_log.path, "/tmp/rustproxy-error.log");
reopened.close().await;
}
#[tokio::test]
async fn error_log_is_not_a_standalone_configuration_section() {
let (router, store, _dir, secret, csrf) = fixture().await;
let cookie = format!("{}={secret}", auth::COOKIE_NAME);
let response = router
.oneshot(
request("/api/config/error_log")
.method("PUT")
.header("content-type", "application/json")
.header("cookie", &cookie)
.header("origin", "http://127.0.0.1:9090")
.header("x-rustproxy-request", "1")
.header("x-csrf-token", &csrf)
.body(Body::from(r#"{"expected_revision":0,"value":{}}"#))
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::NOT_FOUND);
store.close().await;
}
#[tokio::test]
async fn default_pages_section_accepts_the_standard_value_payload() {
let (router, store, _dir, secret, csrf) = fixture().await;