use std::fmt;
use std::rc::Rc;
use std::net::SocketAddr;
use std::ops::{Deref, DerefMut};
use std::borrow::Cow;
use {Request, Response, Data};
use http::{Status, Method, Header, Cookie, uri::Origin, ext::IntoOwned};
use local::Client;
pub struct LocalRequest<'c> {
client: &'c Client,
ptr: *mut Request<'c>,
request: Rc<Request<'c>>,
data: Vec<u8>,
uri: Cow<'c, str>,
}
impl<'c> LocalRequest<'c> {
#[inline(always)]
crate fn new(
client: &'c Client,
method: Method,
uri: Cow<'c, str>
) -> LocalRequest<'c> {
let request = Request::new(client.rocket(), method, Origin::dummy());
if let Some(ref jar) = client.cookies {
let cookies = jar.read().expect("LocalRequest::new() read lock");
for cookie in cookies.iter() {
request.cookies().add_original(cookie.clone().into_owned());
}
}
let mut request = Rc::new(request);
let ptr = Rc::get_mut(&mut request).unwrap() as *mut Request;
LocalRequest { client, ptr, request, uri, data: vec![] }
}
#[inline]
pub fn inner(&self) -> &Request<'c> {
&*self.request
}
#[inline(always)]
fn request_mut(&mut self) -> &mut Request<'c> {
unsafe { &mut *self.ptr }
}
#[inline(always)]
fn long_lived_request<'a>(&mut self) -> &'a mut Request<'c> {
unsafe { &mut *self.ptr }
}
#[inline]
pub fn header<H: Into<Header<'static>>>(mut self, header: H) -> Self {
self.request_mut().add_header(header.into());
self
}
#[inline]
pub fn add_header<H: Into<Header<'static>>>(&mut self, header: H) {
self.request_mut().add_header(header.into());
}
#[inline]
pub fn remote(mut self, address: SocketAddr) -> Self {
self.request_mut().set_remote(address);
self
}
#[inline]
pub fn cookie(self, cookie: Cookie) -> Self {
self.request.cookies().add_original(cookie.into_owned());
self
}
#[inline]
pub fn cookies(self, cookies: Vec<Cookie>) -> Self {
for cookie in cookies {
self.request.cookies().add_original(cookie.into_owned());
}
self
}
#[inline]
#[cfg(feature = "private-cookies")]
pub fn private_cookie(self, cookie: Cookie<'static>) -> Self {
self.request.cookies().add_original_private(cookie);
self
}
#[inline]
pub fn body<S: AsRef<[u8]>>(mut self, body: S) -> Self {
self.data = body.as_ref().into();
self
}
#[inline]
pub fn set_body<S: AsRef<[u8]>>(&mut self, body: S) {
self.data = body.as_ref().into();
}
#[inline(always)]
pub fn dispatch(mut self) -> LocalResponse<'c> {
let r = self.long_lived_request();
LocalRequest::_dispatch(self.client, r, self.request, &self.uri, self.data)
}
#[inline(always)]
pub fn mut_dispatch(&mut self) -> LocalResponse<'c> {
let req = self.long_lived_request();
let data = ::std::mem::replace(&mut self.data, vec![]);
let rc_req = self.request.clone();
LocalRequest::_dispatch(self.client, req, rc_req, &self.uri, data)
}
fn _dispatch(
client: &'c Client,
request: &'c mut Request<'c>,
owned_request: Rc<Request<'c>>,
uri: &str,
data: Vec<u8>
) -> LocalResponse<'c> {
if let Ok(uri) = Origin::parse(uri) {
request.set_uri(uri.into_owned());
} else {
error!("Malformed request URI: {}", uri);
let res = client.rocket().handle_error(Status::BadRequest, request);
return LocalResponse { _request: owned_request, response: res };
}
let response = client.rocket().dispatch(request, Data::local(data));
if let Some(ref jar) = client.cookies {
let mut jar = jar.write().expect("LocalRequest::_dispatch() write lock");
let current_time = ::time::now();
for cookie in response.cookies() {
if let Some(expires) = cookie.expires() {
if expires <= current_time {
jar.force_remove(cookie);
continue;
}
}
jar.add(cookie.into_owned());
}
}
LocalResponse {
_request: owned_request,
response: response
}
}
}
impl<'c> fmt::Debug for LocalRequest<'c> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.request, f)
}
}
pub struct LocalResponse<'c> {
_request: Rc<Request<'c>>,
response: Response<'c>,
}
impl<'c> Deref for LocalResponse<'c> {
type Target = Response<'c>;
#[inline(always)]
fn deref(&self) -> &Response<'c> {
&self.response
}
}
impl<'c> DerefMut for LocalResponse<'c> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Response<'c> {
&mut self.response
}
}
impl<'c> fmt::Debug for LocalResponse<'c> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.response, f)
}
}
impl<'c> Clone for LocalRequest<'c> {
fn clone(&self) -> LocalRequest<'c> {
let mut request = Rc::new(self.inner().clone());
let ptr = Rc::get_mut(&mut request).unwrap() as *mut Request<'_>;
LocalRequest {
ptr, request,
client: self.client,
data: self.data.clone(),
uri: self.uri.clone()
}
}
}
#[cfg(test)]
mod tests {
use crate::Request;
use crate::local::Client;
#[test]
fn clone_unique_ptr() {
let client = Client::new(crate::ignite()).unwrap();
let r1 = client.get("/");
let r2 = r1.clone();
assert_ne!(
r1.inner() as *const Request<'_>,
r2.inner() as *const Request<'_>
);
}
}