use http::{HeaderMap, HeaderValue};
use std::fmt::Debug;
use url::Url;
use crate::{HttpError, Result};
#[non_exhaustive]
#[derive(Clone, Debug, Default)]
pub struct Config {
pub base_url: Option<Url>,
pub headers: HeaderMap,
}
impl Config {
#[must_use]
pub fn new() -> Self {
Self::default()
}
}
impl Config {
pub fn add_header(
mut self,
name: impl http::header::IntoHeaderName,
value: impl AsRef<str>,
) -> Result<Self> {
let value =
HeaderValue::from_str(value.as_ref()).map_err(|e| HttpError::Io(e.to_string()))?;
self.headers.append(name, value);
Ok(self)
}
#[must_use]
pub fn set_base_url(mut self, base: Url) -> Self {
self.base_url = Some(base);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn add_header_stores_valid_value() {
let config = Config::default().add_header("x-api-key", "secret").unwrap();
let val = config.headers.get("x-api-key").unwrap();
assert_eq!(val.to_str().unwrap(), "secret");
}
#[test]
fn add_header_called_twice_preserves_both_values() {
let config = Config::default()
.add_header("accept", "text/html")
.unwrap()
.add_header("accept", "application/json")
.unwrap();
let values: Vec<&str> = config
.headers
.get_all("accept")
.iter()
.map(|v| v.to_str().unwrap())
.collect();
assert_eq!(values, ["text/html", "application/json"]);
}
#[test]
fn add_header_rejects_invalid_value() {
let result = Config::default().add_header("x-bad", "val\x00ue");
assert!(
matches!(result, Err(HttpError::Io(_))),
"invalid header value must return HttpError::Io"
);
}
}