#[cfg(any(feature = "json", feature = "form", feature = "query"))]
use crate::Error;
use crate::Method;
use crate::Response;
use crate::Result;
use crate::body::Body;
#[cfg(any(feature = "json", feature = "form"))]
use crate::message_headers_ext::MessageHeadersExt as _;
use crate::session_ext::SessionExt;
use crate::uri_builder::UriBuilder;
use soup::glib;
use soup::glib::Uri;
use soup::{Message, Session};
use std::fmt::Display;
#[cfg(any(feature = "json", feature = "form"))]
const CONTENT_TYPE: &str = "Content-Type";
const AUTHORIZATION: &str = "Authorization";
#[derive(Debug, Clone)]
pub struct Request {
message: Message,
io_priority: glib::Priority,
}
impl Request {
pub fn message(&self) -> &Message {
&self.message
}
pub fn io_priority(&self) -> glib::Priority {
self.io_priority
}
pub fn into_message(self) -> Message {
self.message
}
}
#[derive(Debug)]
pub struct RequestBuilder {
message: Result<Message>,
uri_builder: UriBuilder,
session: Session,
io_priority: glib::Priority,
}
impl RequestBuilder {
pub(crate) fn new(session: Session, method: Method, uri: Result<Uri>) -> Self {
match uri {
Ok(uri) => Self {
message: Ok(Message::from_uri(method.as_str(), &uri)),
uri_builder: UriBuilder::from(&uri),
session,
io_priority: glib::Priority::DEFAULT,
},
Err(error) => Self {
message: Err(error),
uri_builder: UriBuilder::default(),
session,
io_priority: glib::Priority::DEFAULT,
},
}
}
pub fn header(self, name: &str, value: &str) -> Self {
if let Ok(message) = &self.message {
let headers = message
.request_headers()
.expect("request headers to be set");
headers.append(name, value);
}
self
}
pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> Self
where
U: Display,
P: Display,
{
let header_value = {
let header_value = if let Some(password) = password {
format!("{username}:{password}")
} else {
username.to_string()
};
glib::base64_encode(header_value.as_bytes())
};
self.header(AUTHORIZATION, &header_value)
}
pub fn bearer_auth<T>(self, token: T) -> Self
where
T: Display,
{
self.header(AUTHORIZATION, &format!("Bearer {token}"))
}
pub fn body<T>(self, body: T) -> Self
where
T: Into<Body>,
{
if let Ok(message) = &self.message {
body.into().set_as_request_body(message);
}
self
}
pub fn flags(self, flags: soup::MessageFlags) -> Self {
if let Ok(message) = &self.message {
message.add_flags(flags);
}
self
}
pub fn no_redirect(self) -> Self {
self.flags(soup::MessageFlags::NO_REDIRECT)
}
#[cfg(feature = "json")]
pub fn json<T>(mut self, body: &T) -> Self
where
T: serde::Serialize + ?Sized,
{
if let Ok(message) = &self.message {
match json::to_vec(body) {
Err(error) => {
self.message = Err(Error::new(error));
}
Ok(bytes) => {
self.set_header_if_not_set(CONTENT_TYPE, "application/json");
Body::from(bytes).set_as_request_body(message);
}
};
}
self
}
#[cfg(feature = "form")]
pub fn form<T>(mut self, body: &T) -> Self
where
T: serde::Serialize + ?Sized,
{
if let Ok(message) = &self.message {
match serde_urlencoded::to_string(body) {
Err(error) => {
self.message = Err(Error::new(error));
}
Ok(body) => {
self.set_header_if_not_set(CONTENT_TYPE, "application/x-www-form-urlencoded");
Body::from(body).set_as_request_body(message);
}
};
}
self
}
#[cfg(feature = "query")]
pub fn query<T>(mut self, query: &T) -> Self
where
T: serde::Serialize + ?Sized,
{
if self.message.is_ok() {
match serde_urlencoded::to_string(query) {
Err(error) => {
self.message = Err(Error::new(error));
}
Ok(query) => {
self.uri_builder = self.uri_builder.append_query(&query);
}
};
}
self
}
pub fn io_priority(mut self, priority: glib::Priority) -> Self {
self.io_priority = priority;
self
}
pub async fn send(self) -> Result<Response> {
let (session, request) = self.build_split();
session.execute(request?).await
}
pub fn build(self) -> Result<Request> {
let (_, message) = self.build_split();
message
}
pub fn build_split(self) -> (Session, Result<Request>) {
let message = self
.message
.inspect(|message| message.set_uri(&self.uri_builder.build()))
.map(|message| Request {
message,
io_priority: self.io_priority,
});
(self.session, message)
}
#[cfg(any(feature = "json", feature = "form"))]
fn set_header_if_not_set(&self, name: &str, value: &str) {
if let Ok(message) = &self.message {
let headers = message
.request_headers()
.expect("request headers to be set");
if !headers.contains(name) {
headers.append(name, value);
}
}
}
}