use crate::{Body, BoxStdError, Mime, Response, StatusCode};
use std::{collections::HashMap, convert::TryFrom};
use hyper::header::{self, HeaderName, HeaderValue, InvalidHeaderValue};
use xml::{common::XmlVersion, writer::XmlEvent, EventWriter};
pub trait ResponseExt {
fn new_with_status(body: impl Into<Body>, status: StatusCode) -> Self;
fn set_optional_header(
&mut self,
name: impl HeaderExt,
value: Option<String>,
) -> Result<(), InvalidHeaderValue>;
fn set_mime(&mut self, mime: &Mime) -> Result<(), InvalidHeaderValue>;
fn set_status(&mut self, status: StatusCode);
fn set_xml_body<F>(&mut self, cap: usize, f: F) -> Result<(), BoxStdError>
where
F: FnOnce(&mut EventWriter<&mut Vec<u8>>) -> Result<(), xml::writer::Error>;
fn set_metadata_headers(
&mut self,
metadata: &HashMap<String, String>,
) -> Result<(), BoxStdError>;
}
impl ResponseExt for Response {
fn new_with_status(body: impl Into<Body>, status: StatusCode) -> Self {
let mut res = Self::new(body.into());
*res.status_mut() = status;
res
}
fn set_optional_header(
&mut self,
name: impl HeaderExt,
value: Option<String>,
) -> Result<(), InvalidHeaderValue> {
if let Some(value) = value {
let val = HeaderValue::try_from(value)?;
let _prev = self.headers_mut().insert(name.into_owned_name(), val);
}
Ok(())
}
fn set_mime(&mut self, mime: &Mime) -> Result<(), InvalidHeaderValue> {
let val = HeaderValue::try_from(mime.as_ref())?;
let _prev = self.headers_mut().insert(header::CONTENT_TYPE, val);
Ok(())
}
fn set_status(&mut self, status: StatusCode) {
*self.status_mut() = status;
}
fn set_xml_body<F>(&mut self, cap: usize, f: F) -> Result<(), BoxStdError>
where
F: FnOnce(&mut EventWriter<&mut Vec<u8>>) -> Result<(), xml::writer::Error>,
{
let mut body = Vec::with_capacity(cap);
{
let mut w = EventWriter::new(&mut body);
w.write(XmlEvent::StartDocument {
version: XmlVersion::Version10,
encoding: Some("UTF-8"),
standalone: None,
})?;
f(&mut w)?;
}
*self.body_mut() = Body::from(body);
self.set_mime(&mime::TEXT_XML)?;
Ok(())
}
fn set_metadata_headers(
&mut self,
metadata: &HashMap<String, String>,
) -> Result<(), BoxStdError> {
let headers = self.headers_mut();
for (name, value) in metadata {
let header_name = HeaderName::from_bytes(format!("x-amz-meta-{}", name).as_bytes())?;
let header_value = HeaderValue::from_bytes(value.as_bytes())?;
let _prev = headers.insert(header_name, header_value);
}
Ok(())
}
}
pub trait HeaderExt {
fn into_owned_name(self) -> HeaderName;
}
impl HeaderExt for &'_ HeaderName {
fn into_owned_name(self) -> HeaderName {
self.clone()
}
}
impl HeaderExt for HeaderName {
fn into_owned_name(self) -> HeaderName {
self
}
}