diff options
| -rw-r--r-- | src/api/mod.rs | 6 | ||||
| -rw-r--r-- | src/api/stats/prometheus.rs | 9 | ||||
| -rw-r--r-- | src/api/store.rs | 12 |
3 files changed, 15 insertions, 12 deletions
diff --git a/src/api/mod.rs b/src/api/mod.rs index 021bc52..fb860c7 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -209,3 +209,9 @@ pub(crate) fn store_status(error: StoreError, context: &str) -> ApiError { }; ApiError(status, Some(error.to_string())) } + +/// A media type without its parameters: `text/plain; charset=utf-8` is `text/plain`. +/// For `Content-Type`, and each item of an `Accept` (split at `,`). +pub(crate) fn media_type(value: &str) -> &str { + value.split(';').next().unwrap_or("").trim() +} diff --git a/src/api/stats/prometheus.rs b/src/api/stats/prometheus.rs index 0b770bd..8f7538f 100644 --- a/src/api/stats/prometheus.rs +++ b/src/api/stats/prometheus.rs @@ -5,6 +5,7 @@ use std::fmt::Write; use super::StatsResponse; +use crate::api::media_type; use crate::api::peers::{PeerListResponse, PeerLivenessStatus}; use crate::state::Incidents; use crate::transport::Destination; @@ -17,10 +18,10 @@ pub(super) const CONTENT_TYPE: &str = "text/plain; version=0.0.4; charset=utf-8" /// plain text; browsers and curl don't name either. pub(super) fn wanted(accept: Option<&str>) -> bool { accept.is_some_and(|accept| { - accept.split(',').any(|item| { - let media = item.split(';').next().unwrap_or("").trim(); - media == "application/openmetrics-text" || media == "text/plain" - }) + accept + .split(',') + .map(media_type) + .any(|media| media == "application/openmetrics-text" || media == "text/plain") }) } diff --git a/src/api/store.rs b/src/api/store.rs index c67df85..274ca70 100644 --- a/src/api/store.rs +++ b/src/api/store.rs @@ -20,7 +20,7 @@ use tokio::sync::broadcast; use tracing::{debug, error, instrument, warn}; use super::auth::AuthenticatedUser; -use super::{ApiError, store_status}; +use super::{ApiError, media_type, store_status}; use crate::document::meta; use crate::document::store::{self, StoreError, paths_related}; use crate::state::{AppState, ReadSource}; @@ -258,7 +258,7 @@ fn response_for_value( .is_some_and(|value| { value .split(',') - .any(|item| item.trim().starts_with("text/plain")) + .any(|item| media_type(item) == "text/plain") }); let (content_type, body) = if wants_text { @@ -296,12 +296,8 @@ fn body_value(headers: &HeaderMap, body: &Bytes) -> Result<JsonValue, StatusCode let content_type = headers .get(CONTENT_TYPE) .and_then(|value| value.to_str().ok()) - .unwrap_or("application/json") - .split(';') - .next() - .unwrap_or("") - .trim(); - match content_type { + .unwrap_or("application/json"); + match media_type(content_type) { "application/json" => { serde_json::from_slice::<JsonValue>(body).map_err(|_| StatusCode::BAD_REQUEST) } |
