use crate::error::*;
use reqwest::header::HeaderValue;
use reqwest::{Response, StatusCode};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum HttpData {
Text(String),
Binary(Vec<u8>),
}
impl HttpData {
pub fn try_into_string(self) -> Result<String> {
Ok(match self {
HttpData::Text(s) => s,
HttpData::Binary(b) => String::from_utf8(b)?,
})
}
}
impl PartialEq for HttpData {
fn eq(&self, other: &HttpData) -> bool {
(match self {
HttpData::Text(s) => s.as_bytes(),
HttpData::Binary(b) => b.as_slice(),
}) == (match other {
HttpData::Text(s) => s.as_bytes(),
HttpData::Binary(b) => b.as_slice(),
})
}
}
impl Eq for HttpData {}
impl From<&HeaderValue> for HttpData {
fn from(value: &HeaderValue) -> HttpData {
match value.to_str() {
Ok(s) => HttpData::Text(s.to_owned()),
Err(_) => HttpData::Binary(value.as_bytes().to_vec()),
}
}
}
impl From<&[u8]> for HttpData {
fn from(bytes: &[u8]) -> Self {
match std::str::from_utf8(bytes) {
Ok(text) => HttpData::Text(text.to_owned()),
Err(_) => HttpData::Binary(bytes.to_vec()),
}
}
}
pub type HeaderMap = HashMap<String, Vec<HttpData>>;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ResponseMetadata {
pub(crate) status: u16,
pub(crate) headers: HeaderMap,
}
impl ResponseMetadata {
pub fn get_status(&self) -> Result<StatusCode> {
match StatusCode::from_u16(self.status) {
Err(_) => Err(Error::Internal(format!(
"invalid ResponseMetadata status code representation {}",
self.status
))),
Ok(status) => Ok(status),
}
}
pub fn get_headers(&self) -> &HashMap<String, Vec<HttpData>> {
&self.headers
}
}
impl<'a> From<&'a Response> for ResponseMetadata {
fn from(res: &'a Response) -> Self {
let mut headers = HashMap::new();
for (name, value) in res.headers().iter() {
let value: HttpData = match value.to_str() {
Ok(s) => HttpData::Text(s.to_owned()),
Err(_) => HttpData::Binary(value.as_bytes().to_vec()),
};
let entry = headers
.entry(name.as_str().to_owned())
.or_insert_with(Vec::new);
(*entry).push(value);
}
ResponseMetadata {
status: res.status().as_u16(),
headers: headers,
}
}
}