use std::fmt;
use rkt_http::HttpVersion;
use crate::http::uri::Origin;
use crate::http::{Method, Status};
use crate::{Data, Request};
use super::{Client, LocalResponse};
pub struct LocalRequest<'c> {
pub(super) client: &'c Client,
pub(super) request: Request<'c>,
data: Vec<u8>,
uri: Result<Origin<'c>, Origin<'static>>,
}
impl<'c> LocalRequest<'c> {
pub(crate) fn new<'u: 'c, U>(client: &'c Client, method: Method, uri: U) -> Self
where
U: TryInto<Origin<'u>> + fmt::Display,
{
let uri_str = uri.to_string();
let try_origin = uri.try_into().map_err(|_| Origin::path_only(uri_str));
let origin = try_origin.clone().unwrap_or_else(|bad| bad);
let mut request = Request::new(client.rocket(), method, origin, None);
if client.tracked {
client._with_raw_cookies(|jar| {
for cookie in jar.iter() {
request.cookies_mut().add_original(cookie.clone());
}
})
}
LocalRequest {
client,
request,
uri: try_origin,
data: vec![],
}
}
#[inline]
pub fn override_version(&mut self, version: HttpVersion) {
self.version = Some(version);
}
pub(crate) fn _request(&self) -> &Request<'c> {
&self.request
}
pub(crate) fn _request_mut(&mut self) -> &mut Request<'c> {
&mut self.request
}
pub(crate) fn _body_mut(&mut self) -> &mut Vec<u8> {
&mut self.data
}
async fn _dispatch(mut self) -> LocalResponse<'c> {
let rocket = self.client.rocket();
if let Err(ref invalid) = self.uri {
if self.inner().uri() == invalid {
error!("invalid request URI: {:?}", invalid.path());
return LocalResponse::new(self.request, move |req| {
rocket.dispatch_error(Status::BadRequest, req)
})
.await;
}
}
let mut data = Data::local(self.data);
let token = rocket.preprocess(&mut self.request, &mut data).await;
let response =
LocalResponse::new(self.request, move |req| rocket.dispatch(token, req, data)).await;
if self.client.tracked {
self.client._with_raw_cookies_mut(|jar| {
let current_time = time::OffsetDateTime::now_utc();
for cookie in response.cookies().iter() {
if let Some(expires) = cookie.expires_datetime() {
if expires <= current_time {
jar.force_remove(cookie.name());
continue;
}
}
jar.add_original(cookie.clone());
}
})
}
response
}
pub_request_impl!("# use rkt::local::asynchronous::Client;\n\
use rkt::local::asynchronous::LocalRequest;" async await);
}
impl<'c> Clone for LocalRequest<'c> {
fn clone(&self) -> Self {
LocalRequest {
client: self.client,
request: self.request.clone(),
data: self.data.clone(),
uri: self.uri.clone(),
}
}
}
impl std::fmt::Debug for LocalRequest<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self._request().fmt(f)
}
}
impl<'c> std::ops::Deref for LocalRequest<'c> {
type Target = Request<'c>;
fn deref(&self) -> &Self::Target {
self.inner()
}
}
impl<'c> std::ops::DerefMut for LocalRequest<'c> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner_mut()
}
}