1
0
mirror of https://github.com/actix/actix-extras.git synced 2025-02-03 03:09:04 +01:00

249 lines
7.4 KiB
Rust
Raw Normal View History

2019-01-28 20:41:09 -08:00
use std::{io, time};
2018-11-13 22:53:30 -08:00
2018-12-10 18:08:33 -08:00
use actix_codec::{AsyncRead, AsyncWrite, Framed};
2018-11-13 22:53:30 -08:00
use bytes::Bytes;
use futures::future::{ok, Either};
2018-11-13 22:53:30 -08:00
use futures::{Async, Future, Poll, Sink, Stream};
use crate::error::PayloadError;
use crate::h1;
use crate::message::{RequestHead, ResponseHead};
use crate::payload::{Payload, PayloadStream};
2019-01-28 20:41:09 -08:00
use super::connection::{ConnectionLifetime, ConnectionType, IoConnection};
2019-03-13 14:41:40 -07:00
use super::error::{ConnectError, SendRequestError};
2019-01-28 20:41:09 -08:00
use super::pool::Acquired;
2019-02-12 11:07:42 -08:00
use crate::body::{BodyLength, MessageBody};
2018-11-13 22:53:30 -08:00
2019-01-28 20:41:09 -08:00
pub(crate) fn send_request<T, B>(
io: T,
2018-11-13 22:53:30 -08:00
head: RequestHead,
body: B,
2019-01-28 20:41:09 -08:00
created: time::Instant,
pool: Option<Acquired<T>>,
) -> impl Future<Item = (ResponseHead, Payload), Error = SendRequestError>
2018-11-13 22:53:30 -08:00
where
2019-01-28 20:41:09 -08:00
T: AsyncRead + AsyncWrite + 'static,
2018-11-13 22:53:30 -08:00
B: MessageBody,
{
2019-01-28 20:41:09 -08:00
let io = H1Connection {
2019-01-29 10:14:00 -08:00
created,
pool,
2019-01-28 20:41:09 -08:00
io: Some(io),
};
let len = body.length();
2018-11-13 22:53:30 -08:00
2019-01-28 20:41:09 -08:00
// create Framed and send reqest
Framed::new(io, h1::ClientCodec::default())
.send((head, len).into())
2018-11-13 22:53:30 -08:00
.from_err()
2018-11-15 11:10:23 -08:00
// send request body
.and_then(move |framed| match body.length() {
BodyLength::None | BodyLength::Empty | BodyLength::Sized(0) => {
Either::A(ok(framed))
}
2018-11-13 22:53:30 -08:00
_ => Either::B(SendBody::new(body, framed)),
2018-11-15 11:10:23 -08:00
})
// read response and init read body
.and_then(|framed| {
2018-11-13 22:53:30 -08:00
framed
.into_future()
.map_err(|(e, _)| SendRequestError::from(e))
.and_then(|(item, framed)| {
if let Some(res) = item {
2018-11-13 22:53:30 -08:00
match framed.get_codec().message_type() {
2018-11-19 14:57:12 -08:00
h1::MessageType::None => {
let force_close = !framed.get_codec().keepalive();
release_connection(framed, force_close);
Ok((res, Payload::None))
2018-11-19 14:57:12 -08:00
}
2018-11-14 10:52:40 -08:00
_ => {
let pl: PayloadStream = Box::new(PlStream::new(framed));
Ok((res, pl.into()))
2018-11-14 10:52:40 -08:00
}
2018-11-13 22:53:30 -08:00
}
} else {
Err(ConnectError::Disconnected.into())
2018-11-13 22:53:30 -08:00
}
})
})
}
2019-01-28 20:41:09 -08:00
#[doc(hidden)]
/// HTTP client connection
pub struct H1Connection<T> {
io: Option<T>,
created: time::Instant,
pool: Option<Acquired<T>>,
}
impl<T: AsyncRead + AsyncWrite + 'static> ConnectionLifetime for H1Connection<T> {
/// Close connection
fn close(&mut self) {
if let Some(mut pool) = self.pool.take() {
if let Some(io) = self.io.take() {
pool.close(IoConnection::new(
ConnectionType::H1(io),
self.created,
None,
));
}
}
}
/// Release this connection to the connection pool
fn release(&mut self) {
if let Some(mut pool) = self.pool.take() {
if let Some(io) = self.io.take() {
pool.release(IoConnection::new(
ConnectionType::H1(io),
self.created,
None,
));
}
}
}
}
impl<T: AsyncRead + AsyncWrite + 'static> io::Read for H1Connection<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.io.as_mut().unwrap().read(buf)
}
}
impl<T: AsyncRead + AsyncWrite + 'static> AsyncRead for H1Connection<T> {}
impl<T: AsyncRead + AsyncWrite + 'static> io::Write for H1Connection<T> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.io.as_mut().unwrap().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.io.as_mut().unwrap().flush()
}
}
impl<T: AsyncRead + AsyncWrite + 'static> AsyncWrite for H1Connection<T> {
fn shutdown(&mut self) -> Poll<(), io::Error> {
self.io.as_mut().unwrap().shutdown()
}
}
2018-11-15 11:10:23 -08:00
/// Future responsible for sending request body to the peer
2019-01-28 20:41:09 -08:00
pub(crate) struct SendBody<I, B> {
2018-11-13 22:53:30 -08:00
body: Option<B>,
2018-11-15 11:10:23 -08:00
framed: Option<Framed<I, h1::ClientCodec>>,
2018-11-13 22:53:30 -08:00
flushed: bool,
}
2018-11-15 11:10:23 -08:00
impl<I, B> SendBody<I, B>
2018-11-13 22:53:30 -08:00
where
2018-11-15 11:10:23 -08:00
I: AsyncRead + AsyncWrite + 'static,
2018-11-13 22:53:30 -08:00
B: MessageBody,
{
2019-01-28 20:41:09 -08:00
pub(crate) fn new(body: B, framed: Framed<I, h1::ClientCodec>) -> Self {
2018-11-13 22:53:30 -08:00
SendBody {
body: Some(body),
framed: Some(framed),
flushed: true,
}
}
}
2018-11-15 11:10:23 -08:00
impl<I, B> Future for SendBody<I, B>
2018-11-13 22:53:30 -08:00
where
2019-01-28 20:41:09 -08:00
I: ConnectionLifetime,
2018-11-13 22:53:30 -08:00
B: MessageBody,
{
2018-11-15 11:10:23 -08:00
type Item = Framed<I, h1::ClientCodec>;
2018-11-13 22:53:30 -08:00
type Error = SendRequestError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let mut body_ready = true;
loop {
while body_ready
&& self.body.is_some()
&& !self.framed.as_ref().unwrap().is_write_buf_full()
{
match self.body.as_mut().unwrap().poll_next()? {
2018-11-14 10:52:40 -08:00
Async::Ready(item) => {
2018-11-17 20:21:28 -08:00
// check if body is done
if item.is_none() {
let _ = self.body.take();
}
2018-11-13 22:53:30 -08:00
self.flushed = false;
self.framed
.as_mut()
.unwrap()
2018-11-14 10:52:40 -08:00
.force_send(h1::Message::Chunk(item))?;
2018-11-13 22:53:30 -08:00
break;
}
Async::NotReady => body_ready = false,
}
}
if !self.flushed {
match self.framed.as_mut().unwrap().poll_complete()? {
Async::Ready(_) => {
self.flushed = true;
continue;
}
Async::NotReady => return Ok(Async::NotReady),
}
}
if self.body.is_none() {
return Ok(Async::Ready(self.framed.take().unwrap()));
}
return Ok(Async::NotReady);
}
}
}
pub(crate) struct PlStream<Io> {
2018-11-15 11:10:23 -08:00
framed: Option<Framed<Io, h1::ClientPayloadCodec>>,
}
impl<Io: ConnectionLifetime> PlStream<Io> {
fn new(framed: Framed<Io, h1::ClientCodec>) -> Self {
PlStream {
framed: Some(framed.map_codec(|codec| codec.into_payload_codec())),
}
2018-11-13 22:53:30 -08:00
}
}
impl<Io: ConnectionLifetime> Stream for PlStream<Io> {
2018-11-13 22:53:30 -08:00
type Item = Bytes;
type Error = PayloadError;
2018-11-13 22:53:30 -08:00
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
2018-11-13 22:53:30 -08:00
match self.framed.as_mut().unwrap().poll()? {
Async::NotReady => Ok(Async::NotReady),
2018-12-06 14:32:52 -08:00
Async::Ready(Some(chunk)) => {
if let Some(chunk) = chunk {
Ok(Async::Ready(Some(chunk)))
} else {
let framed = self.framed.take().unwrap();
let force_close = framed.get_codec().keepalive();
release_connection(framed, force_close);
Ok(Async::Ready(None))
}
}
2018-11-13 22:53:30 -08:00
Async::Ready(None) => Ok(Async::Ready(None)),
}
}
}
2018-11-19 14:57:12 -08:00
fn release_connection<T, U>(framed: Framed<T, U>, force_close: bool)
2018-11-13 22:53:30 -08:00
where
2019-01-28 20:41:09 -08:00
T: ConnectionLifetime,
2018-11-13 22:53:30 -08:00
{
2018-11-15 11:10:23 -08:00
let mut parts = framed.into_parts();
2018-11-19 14:57:12 -08:00
if !force_close && parts.read_buf.is_empty() && parts.write_buf.is_empty() {
2018-11-13 22:53:30 -08:00
parts.io.release()
} else {
parts.io.close()
}
}