use crate::util::cookie::Cookie;
use crate::security::safety::HttpSafety;
use crate::message::body::HttpBody;
use crate::message::meta::HttpMeta;
use crate::message::start_line::HttpStartLine;
use crate::message::http_value::*;
use crate::context::io;
use std::collections::HashMap;
use hotaru_core::connection::{HotaruBufRead, HotaruWrite};
#[derive(Debug, Clone)]
pub struct HttpRequest {
pub meta: HttpMeta,
pub body: HttpBody,
}
impl HttpRequest {
pub fn new(meta: HttpMeta, body: HttpBody) -> Self {
HttpRequest { meta, body }
}
pub fn meta(&self) -> &HttpMeta {
&self.meta
}
pub async fn parse_lazy<R: HotaruBufRead<Error = std::io::Error> + Unpin + Send>(
stream: &mut R,
config: &HttpSafety,
print_raw: bool,
) -> Self {
match io::parse_lazy(stream, config, true, print_raw).await {
Ok((meta, body)) => Self::new(meta, body),
Err(_) => Self::default(),
}
}
pub async fn parse_body(&mut self, safety_setting: &HttpSafety) {
let body = std::mem::take(&mut self.body);
self.body = body.parse_buffer(safety_setting);
}
pub fn add_cookie<T: Into<String>>(mut self, key: T, cookie: Cookie) -> Self {
self.meta.add_cookie(key, cookie);
self
}
pub fn content_type(mut self, content_type: HttpContentType) -> Self {
self.meta.set_content_type(content_type);
self
}
pub fn add_header<T: Into<String>, U: Into<String>>(mut self, key: T, value: U) -> Self {
self.meta.set_attribute(key, value.into());
self
}
pub fn content_disposition(mut self, disposition: ContentDisposition) -> Self {
self.meta.set_content_disposition(disposition);
self
}
pub async fn send<W: HotaruWrite<Error = std::io::Error> + Unpin + Send>(self, writer: &mut W) -> std::io::Result<()> {
io::send(self.meta, self.body, writer).await
}
}
impl Default for HttpRequest {
fn default() -> Self {
let meta = HttpMeta::new(
HttpStartLine::new_request(HttpVersion::Http11, HttpMethod::GET, "/".to_string()),
HashMap::new(),
);
let body = HttpBody::default();
HttpRequest::new(meta, body)
}
}
pub mod request_templates {
use std::collections::HashMap;
use akari::Value;
use crate::message::body::HttpBody;
use crate::util::form::UrlEncodedForm;
use crate::message::http_value::{HttpContentType, HttpMethod, HttpVersion};
use crate::message::meta::HttpMeta;
use crate::message::start_line::HttpStartLine;
use super::HttpRequest;
pub fn get_request<T: Into<String>>(url: T) -> HttpRequest {
let meta = HttpMeta::new(
HttpStartLine::new_request(HttpVersion::Http11, HttpMethod::GET, url.into()),
HashMap::new(),
);
let body = HttpBody::Unparsed;
HttpRequest::new(meta, body)
}
pub fn json_request<T: Into<String>>(url: T, body: Value) -> HttpRequest {
let start_line =
HttpStartLine::new_request(HttpVersion::Http11, HttpMethod::POST, url.into());
let mut meta = HttpMeta::new(start_line, HashMap::new());
meta.set_content_type(HttpContentType::ApplicationJson());
HttpRequest::new(meta, HttpBody::Json(body))
}
pub fn form_post<T: Into<String>>(url: T, form: UrlEncodedForm) -> HttpRequest {
let start_line =
HttpStartLine::new_request(HttpVersion::Http11, HttpMethod::POST, url.into());
let meta = HttpMeta::new(start_line, HashMap::new());
HttpRequest::new(meta, HttpBody::Form(form))
}
pub fn get_with_params<T: Into<String>>(
url: T,
params: HashMap<String, String>,
) -> HttpRequest {
let base_url = url.into();
let query = if params.is_empty() {
String::new()
} else {
let form = UrlEncodedForm::from(params);
let encoded = form.to_string();
if base_url.contains('?') {
format!("&{}", encoded)
} else {
format!("?{}", encoded)
}
};
let full_url = format!("{}{}", base_url, query);
get_request(full_url)
}
pub fn text_post<T: Into<String>, B: Into<String>>(url: T, text: B) -> HttpRequest {
let start_line =
HttpStartLine::new_request(HttpVersion::Http11, HttpMethod::POST, url.into());
let mut meta = HttpMeta::new(start_line, HashMap::new());
meta.set_content_type(HttpContentType::Text {
subtype: "plain".to_string(),
charset: Some("utf-8".to_string()),
});
HttpRequest::new(meta, HttpBody::Binary(text.into().into_bytes()))
}
pub fn json_put<T: Into<String>>(url: T, body: Value) -> HttpRequest {
let start_line =
HttpStartLine::new_request(HttpVersion::Http11, HttpMethod::PUT, url.into());
let mut meta = HttpMeta::new(start_line, HashMap::new());
meta.set_content_type(HttpContentType::ApplicationJson());
HttpRequest::new(meta, HttpBody::Json(body))
}
pub fn json_patch<T: Into<String>>(url: T, body: Value) -> HttpRequest {
let start_line =
HttpStartLine::new_request(HttpVersion::Http11, HttpMethod::PATCH, url.into());
let mut meta = HttpMeta::new(start_line, HashMap::new());
meta.set_content_type(HttpContentType::ApplicationJson());
HttpRequest::new(meta, HttpBody::Json(body))
}
pub fn delete<T: Into<String>>(url: T) -> HttpRequest {
let start_line =
HttpStartLine::new_request(HttpVersion::Http11, HttpMethod::DELETE, url.into());
let meta = HttpMeta::new(start_line, HashMap::new());
HttpRequest::new(meta, HttpBody::Unparsed)
}
pub fn head<T: Into<String>>(url: T) -> HttpRequest {
let start_line =
HttpStartLine::new_request(HttpVersion::Http11, HttpMethod::HEAD, url.into());
let meta = HttpMeta::new(start_line, HashMap::new());
HttpRequest::new(meta, HttpBody::Unparsed)
}
}