mirror of
https://github.com/fafhrd91/actix-web
synced 2024-12-01 02:54:36 +01:00
refactor response body management
This commit is contained in:
parent
e73a97884a
commit
7fed50bcae
118
src/body.rs
118
src/body.rs
@ -1,5 +1,5 @@
|
|||||||
|
use std::mem;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{fmt, mem};
|
|
||||||
|
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
use futures::{Async, Poll, Stream};
|
use futures::{Async, Poll, Stream};
|
||||||
@ -19,7 +19,8 @@ pub enum BodyLength {
|
|||||||
Zero,
|
Zero,
|
||||||
Sized(usize),
|
Sized(usize),
|
||||||
Sized64(u64),
|
Sized64(u64),
|
||||||
Unsized,
|
Chunked,
|
||||||
|
Stream,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type that provides this trait can be streamed to a peer.
|
/// Type that provides this trait can be streamed to a peer.
|
||||||
@ -39,17 +40,6 @@ impl MessageBody for () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents various types of http message body.
|
|
||||||
pub enum Body {
|
|
||||||
/// Empty response. `Content-Length` header is set to `0`
|
|
||||||
Empty,
|
|
||||||
/// Specific response body.
|
|
||||||
Binary(Binary),
|
|
||||||
/// Unspecified streaming response. Developer is responsible for setting
|
|
||||||
/// right `Content-Length` or `Transfer-Encoding` headers.
|
|
||||||
Streaming(BodyStream),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents various types of binary body.
|
/// Represents various types of binary body.
|
||||||
/// `Content-Length` header is set to length of the body.
|
/// `Content-Length` header is set to length of the body.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -65,84 +55,6 @@ pub enum Binary {
|
|||||||
SharedVec(Arc<Vec<u8>>),
|
SharedVec(Arc<Vec<u8>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Body {
|
|
||||||
/// Does this body streaming.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_streaming(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
Body::Streaming(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is this binary body.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_binary(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
Body::Binary(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is this binary empy.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
Body::Empty => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create body from slice (copy)
|
|
||||||
pub fn from_slice(s: &[u8]) -> Body {
|
|
||||||
Body::Binary(Binary::Bytes(Bytes::from(s)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is this binary body.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn into_binary(self) -> Option<Binary> {
|
|
||||||
match self {
|
|
||||||
Body::Binary(b) => Some(b),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Body {
|
|
||||||
fn eq(&self, other: &Body) -> bool {
|
|
||||||
match *self {
|
|
||||||
Body::Empty => match *other {
|
|
||||||
Body::Empty => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
Body::Binary(ref b) => match *other {
|
|
||||||
Body::Binary(ref b2) => b == b2,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
Body::Streaming(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Body {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
Body::Empty => write!(f, "Body::Empty"),
|
|
||||||
Body::Binary(ref b) => write!(f, "Body::Binary({:?})", b),
|
|
||||||
Body::Streaming(_) => write!(f, "Body::Streaming(_)"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<T> for Body
|
|
||||||
where
|
|
||||||
T: Into<Binary>,
|
|
||||||
{
|
|
||||||
fn from(b: T) -> Body {
|
|
||||||
Body::Binary(b.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Binary {
|
impl Binary {
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Returns `true` if body is empty
|
/// Returns `true` if body is empty
|
||||||
@ -286,6 +198,22 @@ impl MessageBody for Bytes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MessageBody for BytesMut {
|
||||||
|
fn length(&self) -> BodyLength {
|
||||||
|
BodyLength::Sized(self.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
|
||||||
|
if self.is_empty() {
|
||||||
|
Ok(Async::Ready(None))
|
||||||
|
} else {
|
||||||
|
Ok(Async::Ready(Some(
|
||||||
|
mem::replace(self, BytesMut::new()).freeze(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MessageBody for &'static str {
|
impl MessageBody for &'static str {
|
||||||
fn length(&self) -> BodyLength {
|
fn length(&self) -> BodyLength {
|
||||||
BodyLength::Sized(self.len())
|
BodyLength::Sized(self.len())
|
||||||
@ -370,7 +298,7 @@ where
|
|||||||
S: Stream<Item = Bytes, Error = Error>,
|
S: Stream<Item = Bytes, Error = Error>,
|
||||||
{
|
{
|
||||||
fn length(&self) -> BodyLength {
|
fn length(&self) -> BodyLength {
|
||||||
BodyLength::Unsized
|
BodyLength::Chunked
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
|
fn poll_next(&mut self) -> Poll<Option<Bytes>, Error> {
|
||||||
@ -382,12 +310,6 @@ where
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_body_is_streaming() {
|
|
||||||
assert_eq!(Body::Empty.is_streaming(), false);
|
|
||||||
assert_eq!(Body::Binary(Binary::from("")).is_streaming(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_empty() {
|
fn test_is_empty() {
|
||||||
assert_eq!(Binary::from("").is_empty(), true);
|
assert_eq!(Binary::from("").is_empty(), true);
|
||||||
|
@ -100,6 +100,10 @@ where
|
|||||||
{
|
{
|
||||||
match self.body.as_mut().unwrap().poll_next()? {
|
match self.body.as_mut().unwrap().poll_next()? {
|
||||||
Async::Ready(item) => {
|
Async::Ready(item) => {
|
||||||
|
// check if body is done
|
||||||
|
if item.is_none() {
|
||||||
|
let _ = self.body.take();
|
||||||
|
}
|
||||||
self.flushed = false;
|
self.flushed = false;
|
||||||
self.framed
|
self.framed
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -51,12 +51,6 @@ pub struct ClientRequest<B: MessageBody = ()> {
|
|||||||
body: B,
|
body: B,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RequestHead {
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.headers.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClientRequest<()> {
|
impl ClientRequest<()> {
|
||||||
/// Create client request builder
|
/// Create client request builder
|
||||||
pub fn build() -> ClientRequestBuilder {
|
pub fn build() -> ClientRequestBuilder {
|
||||||
|
@ -100,11 +100,10 @@ impl Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Converts error to a response instance and set error message as response body
|
/// Converts error to a response instance and set error message as response body
|
||||||
pub fn response_with_message(self) -> Response {
|
pub fn response_with_message(self) -> Response<String> {
|
||||||
let message = format!("{}", self);
|
let message = format!("{}", self);
|
||||||
let mut resp: Response = self.into();
|
let resp: Response = self.into();
|
||||||
resp.set_body(message);
|
resp.set_body(message)
|
||||||
resp
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,7 +636,7 @@ where
|
|||||||
InternalErrorType::Status(st) => Response::new(st),
|
InternalErrorType::Status(st) => Response::new(st),
|
||||||
InternalErrorType::Response(ref resp) => {
|
InternalErrorType::Response(ref resp) => {
|
||||||
if let Some(resp) = resp.lock().unwrap().take() {
|
if let Some(resp) = resp.lock().unwrap().take() {
|
||||||
Response::from_parts(resp)
|
Response::<()>::from_parts(resp)
|
||||||
} else {
|
} else {
|
||||||
Response::new(StatusCode::INTERNAL_SERVER_ERROR)
|
Response::new(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use tokio_codec::{Decoder, Encoder};
|
|||||||
use super::decoder::{MessageDecoder, PayloadDecoder, PayloadItem, PayloadType};
|
use super::decoder::{MessageDecoder, PayloadDecoder, PayloadItem, PayloadType};
|
||||||
use super::encoder::RequestEncoder;
|
use super::encoder::RequestEncoder;
|
||||||
use super::{Message, MessageType};
|
use super::{Message, MessageType};
|
||||||
use body::{Binary, Body, BodyLength};
|
use body::{Binary, BodyLength};
|
||||||
use client::ClientResponse;
|
use client::ClientResponse;
|
||||||
use config::ServiceConfig;
|
use config::ServiceConfig;
|
||||||
use error::{ParseError, PayloadError};
|
use error::{ParseError, PayloadError};
|
||||||
@ -164,14 +164,16 @@ impl ClientCodecInner {
|
|||||||
write!(buffer.writer(), "{}", len)?;
|
write!(buffer.writer(), "{}", len)?;
|
||||||
buffer.extend_from_slice(b"\r\n");
|
buffer.extend_from_slice(b"\r\n");
|
||||||
}
|
}
|
||||||
BodyLength::Unsized => {
|
BodyLength::Chunked => {
|
||||||
buffer.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n")
|
buffer.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n")
|
||||||
}
|
}
|
||||||
BodyLength::Zero => {
|
BodyLength::Zero => {
|
||||||
len_is_set = false;
|
len_is_set = false;
|
||||||
buffer.extend_from_slice(b"\r\n")
|
buffer.extend_from_slice(b"\r\n")
|
||||||
}
|
}
|
||||||
BodyLength::None => buffer.extend_from_slice(b"\r\n"),
|
BodyLength::None | BodyLength::Stream => {
|
||||||
|
buffer.extend_from_slice(b"\r\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut has_date = false;
|
let mut has_date = false;
|
||||||
|
@ -8,12 +8,13 @@ use tokio_codec::{Decoder, Encoder};
|
|||||||
use super::decoder::{MessageDecoder, PayloadDecoder, PayloadItem, PayloadType};
|
use super::decoder::{MessageDecoder, PayloadDecoder, PayloadItem, PayloadType};
|
||||||
use super::encoder::ResponseEncoder;
|
use super::encoder::ResponseEncoder;
|
||||||
use super::{Message, MessageType};
|
use super::{Message, MessageType};
|
||||||
use body::{Binary, Body, BodyLength};
|
use body::{Binary, BodyLength};
|
||||||
use config::ServiceConfig;
|
use config::ServiceConfig;
|
||||||
use error::ParseError;
|
use error::ParseError;
|
||||||
use helpers;
|
use helpers;
|
||||||
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
|
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
|
||||||
use http::{Method, Version};
|
use http::{Method, Version};
|
||||||
|
use message::ResponseHead;
|
||||||
use request::Request;
|
use request::Request;
|
||||||
use response::Response;
|
use response::Response;
|
||||||
|
|
||||||
@ -98,9 +99,9 @@ impl Codec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// prepare transfer encoding
|
/// prepare transfer encoding
|
||||||
pub fn prepare_te(&mut self, res: &mut Response) {
|
pub fn prepare_te(&mut self, head: &mut ResponseHead, length: &mut BodyLength) {
|
||||||
self.te
|
self.te
|
||||||
.update(res, self.flags.contains(Flags::HEAD), self.version);
|
.update(head, self.flags.contains(Flags::HEAD), self.version, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_response(
|
fn encode_response(
|
||||||
@ -135,17 +136,8 @@ impl Codec {
|
|||||||
// render message
|
// render message
|
||||||
{
|
{
|
||||||
let reason = msg.reason().as_bytes();
|
let reason = msg.reason().as_bytes();
|
||||||
if let Body::Binary(ref bytes) = msg.body() {
|
buffer
|
||||||
buffer.reserve(
|
.reserve(256 + msg.headers().len() * AVERAGE_HEADER_SIZE + reason.len());
|
||||||
256 + msg.headers().len() * AVERAGE_HEADER_SIZE
|
|
||||||
+ bytes.len()
|
|
||||||
+ reason.len(),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
buffer.reserve(
|
|
||||||
256 + msg.headers().len() * AVERAGE_HEADER_SIZE + reason.len(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// status line
|
// status line
|
||||||
helpers::write_status_line(self.version, msg.status().as_u16(), buffer);
|
helpers::write_status_line(self.version, msg.status().as_u16(), buffer);
|
||||||
@ -154,7 +146,7 @@ impl Codec {
|
|||||||
// content length
|
// content length
|
||||||
let mut len_is_set = true;
|
let mut len_is_set = true;
|
||||||
match self.te.length {
|
match self.te.length {
|
||||||
BodyLength::Unsized => {
|
BodyLength::Chunked => {
|
||||||
buffer.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n")
|
buffer.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n")
|
||||||
}
|
}
|
||||||
BodyLength::Zero => {
|
BodyLength::Zero => {
|
||||||
@ -167,7 +159,9 @@ impl Codec {
|
|||||||
write!(buffer.writer(), "{}", len)?;
|
write!(buffer.writer(), "{}", len)?;
|
||||||
buffer.extend_from_slice(b"\r\n");
|
buffer.extend_from_slice(b"\r\n");
|
||||||
}
|
}
|
||||||
BodyLength::None => buffer.extend_from_slice(b"\r\n"),
|
BodyLength::None | BodyLength::Stream => {
|
||||||
|
buffer.extend_from_slice(b"\r\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// write headers
|
// write headers
|
||||||
|
@ -13,7 +13,7 @@ use tokio_timer::Delay;
|
|||||||
use error::{ParseError, PayloadError};
|
use error::{ParseError, PayloadError};
|
||||||
use payload::{Payload, PayloadSender, PayloadStatus, PayloadWriter};
|
use payload::{Payload, PayloadSender, PayloadStatus, PayloadWriter};
|
||||||
|
|
||||||
use body::{Body, BodyStream};
|
use body::{BodyLength, MessageBody};
|
||||||
use config::ServiceConfig;
|
use config::ServiceConfig;
|
||||||
use error::DispatchError;
|
use error::DispatchError;
|
||||||
use request::Request;
|
use request::Request;
|
||||||
@ -37,14 +37,14 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatcher for HTTP/1.1 protocol
|
/// Dispatcher for HTTP/1.1 protocol
|
||||||
pub struct Dispatcher<T, S: Service>
|
pub struct Dispatcher<T, S: Service, B: MessageBody>
|
||||||
where
|
where
|
||||||
S::Error: Debug,
|
S::Error: Debug,
|
||||||
{
|
{
|
||||||
inner: Option<InnerDispatcher<T, S>>,
|
inner: Option<InnerDispatcher<T, S, B>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InnerDispatcher<T, S: Service>
|
struct InnerDispatcher<T, S: Service, B: MessageBody>
|
||||||
where
|
where
|
||||||
S::Error: Debug,
|
S::Error: Debug,
|
||||||
{
|
{
|
||||||
@ -54,7 +54,7 @@ where
|
|||||||
error: Option<DispatchError<S::Error>>,
|
error: Option<DispatchError<S::Error>>,
|
||||||
config: ServiceConfig,
|
config: ServiceConfig,
|
||||||
|
|
||||||
state: State<S>,
|
state: State<S, B>,
|
||||||
payload: Option<PayloadSender>,
|
payload: Option<PayloadSender>,
|
||||||
messages: VecDeque<DispatcherMessage>,
|
messages: VecDeque<DispatcherMessage>,
|
||||||
unhandled: Option<Request>,
|
unhandled: Option<Request>,
|
||||||
@ -68,13 +68,13 @@ enum DispatcherMessage {
|
|||||||
Error(Response),
|
Error(Response),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum State<S: Service> {
|
enum State<S: Service, B: MessageBody> {
|
||||||
None,
|
None,
|
||||||
ServiceCall(S::Future),
|
ServiceCall(S::Future),
|
||||||
SendPayload(BodyStream),
|
SendPayload(B),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Service> State<S> {
|
impl<S: Service, B: MessageBody> State<S, B> {
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
if let State::None = self {
|
if let State::None = self {
|
||||||
true
|
true
|
||||||
@ -84,11 +84,12 @@ impl<S: Service> State<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Dispatcher<T, S>
|
impl<T, S, B> Dispatcher<T, S, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
S: Service<Request = Request, Response = Response>,
|
S: Service<Request = Request, Response = Response<B>>,
|
||||||
S::Error: Debug,
|
S::Error: Debug,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
/// Create http/1 dispatcher.
|
/// Create http/1 dispatcher.
|
||||||
pub fn new(stream: T, config: ServiceConfig, service: S) -> Self {
|
pub fn new(stream: T, config: ServiceConfig, service: S) -> Self {
|
||||||
@ -137,11 +138,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> InnerDispatcher<T, S>
|
impl<T, S, B> InnerDispatcher<T, S, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
S: Service<Request = Request, Response = Response>,
|
S: Service<Request = Request, Response = Response<B>>,
|
||||||
S::Error: Debug,
|
S::Error: Debug,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
fn can_read(&self) -> bool {
|
fn can_read(&self) -> bool {
|
||||||
if self.flags.contains(Flags::DISCONNECTED) {
|
if self.flags.contains(Flags::DISCONNECTED) {
|
||||||
@ -186,11 +188,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_response(
|
fn send_response<B1: MessageBody>(
|
||||||
&mut self,
|
&mut self,
|
||||||
message: Response,
|
message: Response,
|
||||||
body: Body,
|
body: B1,
|
||||||
) -> Result<State<S>, DispatchError<S::Error>> {
|
) -> Result<State<S, B1>, DispatchError<S::Error>> {
|
||||||
self.framed
|
self.framed
|
||||||
.force_send(Message::Item(message))
|
.force_send(Message::Item(message))
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@ -203,15 +205,9 @@ where
|
|||||||
self.flags
|
self.flags
|
||||||
.set(Flags::KEEPALIVE, self.framed.get_codec().keepalive());
|
.set(Flags::KEEPALIVE, self.framed.get_codec().keepalive());
|
||||||
self.flags.remove(Flags::FLUSHED);
|
self.flags.remove(Flags::FLUSHED);
|
||||||
match body {
|
match body.length() {
|
||||||
Body::Empty => Ok(State::None),
|
BodyLength::None | BodyLength::Zero => Ok(State::None),
|
||||||
Body::Streaming(stream) => Ok(State::SendPayload(stream)),
|
_ => Ok(State::SendPayload(body)),
|
||||||
Body::Binary(mut bin) => {
|
|
||||||
self.flags.remove(Flags::FLUSHED);
|
|
||||||
self.framed.force_send(Message::Chunk(Some(bin.take())))?;
|
|
||||||
self.framed.force_send(Message::Chunk(None))?;
|
|
||||||
Ok(State::None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,15 +220,18 @@ where
|
|||||||
Some(self.handle_request(req)?)
|
Some(self.handle_request(req)?)
|
||||||
}
|
}
|
||||||
Some(DispatcherMessage::Error(res)) => {
|
Some(DispatcherMessage::Error(res)) => {
|
||||||
Some(self.send_response(res, Body::Empty)?)
|
self.send_response(res, ())?;
|
||||||
|
None
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
State::ServiceCall(mut fut) => {
|
State::ServiceCall(mut fut) => {
|
||||||
match fut.poll().map_err(DispatchError::Service)? {
|
match fut.poll().map_err(DispatchError::Service)? {
|
||||||
Async::Ready(mut res) => {
|
Async::Ready(mut res) => {
|
||||||
self.framed.get_codec_mut().prepare_te(&mut res);
|
let (mut res, body) = res.replace_body(());
|
||||||
let body = res.replace_body(Body::Empty);
|
self.framed
|
||||||
|
.get_codec_mut()
|
||||||
|
.prepare_te(res.head_mut(), &mut body.length());
|
||||||
Some(self.send_response(res, body)?)
|
Some(self.send_response(res, body)?)
|
||||||
}
|
}
|
||||||
Async::NotReady => {
|
Async::NotReady => {
|
||||||
@ -244,7 +243,10 @@ where
|
|||||||
State::SendPayload(mut stream) => {
|
State::SendPayload(mut stream) => {
|
||||||
loop {
|
loop {
|
||||||
if !self.framed.is_write_buf_full() {
|
if !self.framed.is_write_buf_full() {
|
||||||
match stream.poll().map_err(|_| DispatchError::Unknown)? {
|
match stream
|
||||||
|
.poll_next()
|
||||||
|
.map_err(|_| DispatchError::Unknown)?
|
||||||
|
{
|
||||||
Async::Ready(Some(item)) => {
|
Async::Ready(Some(item)) => {
|
||||||
self.flags.remove(Flags::FLUSHED);
|
self.flags.remove(Flags::FLUSHED);
|
||||||
self.framed
|
self.framed
|
||||||
@ -290,12 +292,14 @@ where
|
|||||||
fn handle_request(
|
fn handle_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
req: Request,
|
req: Request,
|
||||||
) -> Result<State<S>, DispatchError<S::Error>> {
|
) -> Result<State<S, B>, DispatchError<S::Error>> {
|
||||||
let mut task = self.service.call(req);
|
let mut task = self.service.call(req);
|
||||||
match task.poll().map_err(DispatchError::Service)? {
|
match task.poll().map_err(DispatchError::Service)? {
|
||||||
Async::Ready(mut res) => {
|
Async::Ready(res) => {
|
||||||
self.framed.get_codec_mut().prepare_te(&mut res);
|
let (mut res, body) = res.replace_body(());
|
||||||
let body = res.replace_body(Body::Empty);
|
self.framed
|
||||||
|
.get_codec_mut()
|
||||||
|
.prepare_te(res.head_mut(), &mut body.length());
|
||||||
self.send_response(res, body)
|
self.send_response(res, body)
|
||||||
}
|
}
|
||||||
Async::NotReady => Ok(State::ServiceCall(task)),
|
Async::NotReady => Ok(State::ServiceCall(task)),
|
||||||
@ -436,10 +440,9 @@ where
|
|||||||
// timeout on first request (slow request) return 408
|
// timeout on first request (slow request) return 408
|
||||||
trace!("Slow request timeout");
|
trace!("Slow request timeout");
|
||||||
self.flags.insert(Flags::STARTED | Flags::DISCONNECTED);
|
self.flags.insert(Flags::STARTED | Flags::DISCONNECTED);
|
||||||
self.state = self.send_response(
|
let _ = self
|
||||||
Response::RequestTimeout().finish(),
|
.send_response(Response::RequestTimeout().finish(), ());
|
||||||
Body::Empty,
|
self.state = State::None;
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
} else if let Some(deadline) = self.config.keep_alive_expire() {
|
} else if let Some(deadline) = self.config.keep_alive_expire() {
|
||||||
self.ka_timer.as_mut().map(|timer| {
|
self.ka_timer.as_mut().map(|timer| {
|
||||||
@ -462,11 +465,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Future for Dispatcher<T, S>
|
impl<T, S, B> Future for Dispatcher<T, S, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
S: Service<Request = Request, Response = Response>,
|
S: Service<Request = Request, Response = Response<B>>,
|
||||||
S::Error: Debug,
|
S::Error: Debug,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
type Item = H1ServiceResult<T>;
|
type Item = H1ServiceResult<T>;
|
||||||
type Error = DispatchError<S::Error>;
|
type Error = DispatchError<S::Error>;
|
||||||
|
@ -8,10 +8,10 @@ use bytes::{Bytes, BytesMut};
|
|||||||
use http::header::{HeaderValue, ACCEPT_ENCODING, CONTENT_LENGTH};
|
use http::header::{HeaderValue, ACCEPT_ENCODING, CONTENT_LENGTH};
|
||||||
use http::{StatusCode, Version};
|
use http::{StatusCode, Version};
|
||||||
|
|
||||||
use body::{Binary, Body, BodyLength};
|
use body::{Binary, BodyLength};
|
||||||
use header::ContentEncoding;
|
use header::ContentEncoding;
|
||||||
use http::Method;
|
use http::Method;
|
||||||
use message::RequestHead;
|
use message::{RequestHead, ResponseHead};
|
||||||
use request::Request;
|
use request::Request;
|
||||||
use response::Response;
|
use response::Response;
|
||||||
|
|
||||||
@ -43,116 +43,36 @@ impl ResponseEncoder {
|
|||||||
self.te.encode_eof(buf)
|
self.te.encode_eof(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, resp: &mut Response, head: bool, version: Version) {
|
pub fn update(
|
||||||
|
&mut self,
|
||||||
|
resp: &mut ResponseHead,
|
||||||
|
head: bool,
|
||||||
|
version: Version,
|
||||||
|
length: &mut BodyLength,
|
||||||
|
) {
|
||||||
self.head = head;
|
self.head = head;
|
||||||
let mut len = 0;
|
let transfer = match length {
|
||||||
|
BodyLength::Zero => {
|
||||||
let has_body = match resp.body() {
|
match resp.status {
|
||||||
Body::Empty => false,
|
|
||||||
Body::Binary(ref bin) => {
|
|
||||||
len = bin.len();
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => true,
|
|
||||||
};
|
|
||||||
|
|
||||||
let has_body = match resp.body() {
|
|
||||||
Body::Empty => false,
|
|
||||||
_ => true,
|
|
||||||
};
|
|
||||||
|
|
||||||
let transfer = match resp.body() {
|
|
||||||
Body::Empty => {
|
|
||||||
self.length = match resp.status() {
|
|
||||||
StatusCode::NO_CONTENT
|
StatusCode::NO_CONTENT
|
||||||
| StatusCode::CONTINUE
|
| StatusCode::CONTINUE
|
||||||
| StatusCode::SWITCHING_PROTOCOLS
|
| StatusCode::SWITCHING_PROTOCOLS
|
||||||
| StatusCode::PROCESSING => BodyLength::None,
|
| StatusCode::PROCESSING => *length = BodyLength::None,
|
||||||
_ => BodyLength::Zero,
|
_ => (),
|
||||||
};
|
}
|
||||||
TransferEncoding::empty()
|
TransferEncoding::empty()
|
||||||
}
|
}
|
||||||
Body::Binary(_) => {
|
BodyLength::Sized(len) => TransferEncoding::length(*len as u64),
|
||||||
self.length = BodyLength::Sized(len);
|
BodyLength::Sized64(len) => TransferEncoding::length(*len),
|
||||||
TransferEncoding::length(len as u64)
|
BodyLength::Chunked => TransferEncoding::chunked(),
|
||||||
}
|
BodyLength::Stream => TransferEncoding::eof(),
|
||||||
Body::Streaming(_) => {
|
BodyLength::None => TransferEncoding::length(0),
|
||||||
if resp.upgrade() {
|
|
||||||
self.length = BodyLength::None;
|
|
||||||
TransferEncoding::eof()
|
|
||||||
} else {
|
|
||||||
self.streaming_encoding(version, resp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
// check for head response
|
// check for head response
|
||||||
if self.head {
|
if !self.head {
|
||||||
resp.set_body(Body::Empty);
|
|
||||||
} else {
|
|
||||||
self.te = transfer;
|
self.te = transfer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn streaming_encoding(
|
|
||||||
&mut self,
|
|
||||||
version: Version,
|
|
||||||
resp: &mut Response,
|
|
||||||
) -> TransferEncoding {
|
|
||||||
match resp.chunked() {
|
|
||||||
Some(true) => {
|
|
||||||
// Enable transfer encoding
|
|
||||||
if version == Version::HTTP_2 {
|
|
||||||
self.length = BodyLength::None;
|
|
||||||
TransferEncoding::eof()
|
|
||||||
} else {
|
|
||||||
self.length = BodyLength::Unsized;
|
|
||||||
TransferEncoding::chunked()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(false) => TransferEncoding::eof(),
|
|
||||||
None => {
|
|
||||||
// if Content-Length is specified, then use it as length hint
|
|
||||||
let (len, chunked) =
|
|
||||||
if let Some(len) = resp.headers().get(CONTENT_LENGTH) {
|
|
||||||
// Content-Length
|
|
||||||
if let Ok(s) = len.to_str() {
|
|
||||||
if let Ok(len) = s.parse::<u64>() {
|
|
||||||
(Some(len), false)
|
|
||||||
} else {
|
|
||||||
error!("illegal Content-Length: {:?}", len);
|
|
||||||
(None, false)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error!("illegal Content-Length: {:?}", len);
|
|
||||||
(None, false)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(None, true)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !chunked {
|
|
||||||
if let Some(len) = len {
|
|
||||||
self.length = BodyLength::Sized64(len);
|
|
||||||
TransferEncoding::length(len)
|
|
||||||
} else {
|
|
||||||
TransferEncoding::eof()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Enable transfer encoding
|
|
||||||
match version {
|
|
||||||
Version::HTTP_11 => {
|
|
||||||
self.length = BodyLength::Unsized;
|
|
||||||
TransferEncoding::chunked()
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.length = BodyLength::None;
|
|
||||||
TransferEncoding::eof()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -8,6 +8,7 @@ use futures::future::{ok, FutureResult};
|
|||||||
use futures::{Async, Future, Poll, Stream};
|
use futures::{Async, Future, Poll, Stream};
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
|
use body::MessageBody;
|
||||||
use config::{KeepAlive, ServiceConfig};
|
use config::{KeepAlive, ServiceConfig};
|
||||||
use error::{DispatchError, ParseError};
|
use error::{DispatchError, ParseError};
|
||||||
use request::Request;
|
use request::Request;
|
||||||
@ -18,17 +19,18 @@ use super::dispatcher::Dispatcher;
|
|||||||
use super::{H1ServiceResult, Message};
|
use super::{H1ServiceResult, Message};
|
||||||
|
|
||||||
/// `NewService` implementation for HTTP1 transport
|
/// `NewService` implementation for HTTP1 transport
|
||||||
pub struct H1Service<T, S> {
|
pub struct H1Service<T, S, B> {
|
||||||
srv: S,
|
srv: S,
|
||||||
cfg: ServiceConfig,
|
cfg: ServiceConfig,
|
||||||
_t: PhantomData<T>,
|
_t: PhantomData<(T, B)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> H1Service<T, S>
|
impl<T, S, B> H1Service<T, S, B>
|
||||||
where
|
where
|
||||||
S: NewService<Request = Request, Response = Response> + Clone,
|
S: NewService<Request = Request, Response = Response<B>> + Clone,
|
||||||
S::Service: Clone,
|
S::Service: Clone,
|
||||||
S::Error: Debug,
|
S::Error: Debug,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
/// Create new `HttpService` instance.
|
/// Create new `HttpService` instance.
|
||||||
pub fn new<F: IntoNewService<S>>(service: F) -> Self {
|
pub fn new<F: IntoNewService<S>>(service: F) -> Self {
|
||||||
@ -47,19 +49,20 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> NewService for H1Service<T, S>
|
impl<T, S, B> NewService for H1Service<T, S, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
S: NewService<Request = Request, Response = Response> + Clone,
|
S: NewService<Request = Request, Response = Response<B>> + Clone,
|
||||||
S::Service: Clone,
|
S::Service: Clone,
|
||||||
S::Error: Debug,
|
S::Error: Debug,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
type Request = T;
|
type Request = T;
|
||||||
type Response = H1ServiceResult<T>;
|
type Response = H1ServiceResult<T>;
|
||||||
type Error = DispatchError<S::Error>;
|
type Error = DispatchError<S::Error>;
|
||||||
type InitError = S::InitError;
|
type InitError = S::InitError;
|
||||||
type Service = H1ServiceHandler<T, S::Service>;
|
type Service = H1ServiceHandler<T, S::Service, B>;
|
||||||
type Future = H1ServiceResponse<T, S>;
|
type Future = H1ServiceResponse<T, S, B>;
|
||||||
|
|
||||||
fn new_service(&self) -> Self::Future {
|
fn new_service(&self) -> Self::Future {
|
||||||
H1ServiceResponse {
|
H1ServiceResponse {
|
||||||
@ -180,7 +183,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish service configuration and create `H1Service` instance.
|
/// Finish service configuration and create `H1Service` instance.
|
||||||
pub fn finish<F: IntoNewService<S>>(self, service: F) -> H1Service<T, S> {
|
pub fn finish<F, B>(self, service: F) -> H1Service<T, S, B>
|
||||||
|
where
|
||||||
|
B: MessageBody,
|
||||||
|
F: IntoNewService<S>,
|
||||||
|
{
|
||||||
let cfg = ServiceConfig::new(
|
let cfg = ServiceConfig::new(
|
||||||
self.keep_alive,
|
self.keep_alive,
|
||||||
self.client_timeout,
|
self.client_timeout,
|
||||||
@ -195,20 +202,21 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct H1ServiceResponse<T, S: NewService> {
|
pub struct H1ServiceResponse<T, S: NewService, B> {
|
||||||
fut: S::Future,
|
fut: S::Future,
|
||||||
cfg: Option<ServiceConfig>,
|
cfg: Option<ServiceConfig>,
|
||||||
_t: PhantomData<T>,
|
_t: PhantomData<(T, B)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Future for H1ServiceResponse<T, S>
|
impl<T, S, B> Future for H1ServiceResponse<T, S, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
S: NewService<Request = Request, Response = Response>,
|
S: NewService<Request = Request, Response = Response<B>>,
|
||||||
S::Service: Clone,
|
S::Service: Clone,
|
||||||
S::Error: Debug,
|
S::Error: Debug,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
type Item = H1ServiceHandler<T, S::Service>;
|
type Item = H1ServiceHandler<T, S::Service, B>;
|
||||||
type Error = S::InitError;
|
type Error = S::InitError;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
@ -221,18 +229,19 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `Service` implementation for HTTP1 transport
|
/// `Service` implementation for HTTP1 transport
|
||||||
pub struct H1ServiceHandler<T, S> {
|
pub struct H1ServiceHandler<T, S, B> {
|
||||||
srv: S,
|
srv: S,
|
||||||
cfg: ServiceConfig,
|
cfg: ServiceConfig,
|
||||||
_t: PhantomData<T>,
|
_t: PhantomData<(T, B)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> H1ServiceHandler<T, S>
|
impl<T, S, B> H1ServiceHandler<T, S, B>
|
||||||
where
|
where
|
||||||
S: Service<Request = Request, Response = Response> + Clone,
|
S: Service<Request = Request, Response = Response<B>> + Clone,
|
||||||
S::Error: Debug,
|
S::Error: Debug,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
fn new(cfg: ServiceConfig, srv: S) -> H1ServiceHandler<T, S> {
|
fn new(cfg: ServiceConfig, srv: S) -> H1ServiceHandler<T, S, B> {
|
||||||
H1ServiceHandler {
|
H1ServiceHandler {
|
||||||
srv,
|
srv,
|
||||||
cfg,
|
cfg,
|
||||||
@ -241,16 +250,17 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Service for H1ServiceHandler<T, S>
|
impl<T, S, B> Service for H1ServiceHandler<T, S, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
S: Service<Request = Request, Response = Response> + Clone,
|
S: Service<Request = Request, Response = Response<B>> + Clone,
|
||||||
S::Error: Debug,
|
S::Error: Debug,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
type Request = T;
|
type Request = T;
|
||||||
type Response = H1ServiceResult<T>;
|
type Response = H1ServiceResult<T>;
|
||||||
type Error = DispatchError<S::Error>;
|
type Error = DispatchError<S::Error>;
|
||||||
type Future = Dispatcher<T, S>;
|
type Future = Dispatcher<T, S, B>;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
self.srv.poll_ready().map_err(DispatchError::Service)
|
self.srv.poll_ready().map_err(DispatchError::Service)
|
||||||
|
@ -129,7 +129,7 @@ pub mod h1;
|
|||||||
pub(crate) mod helpers;
|
pub(crate) mod helpers;
|
||||||
pub mod test;
|
pub mod test;
|
||||||
pub mod ws;
|
pub mod ws;
|
||||||
pub use body::{Binary, Body};
|
pub use body::{Binary, MessageBody};
|
||||||
pub use error::{Error, ResponseError, Result};
|
pub use error::{Error, ResponseError, Result};
|
||||||
pub use extensions::Extensions;
|
pub use extensions::Extensions;
|
||||||
pub use httpmessage::HttpMessage;
|
pub use httpmessage::HttpMessage;
|
||||||
|
309
src/response.rs
309
src/response.rs
@ -2,7 +2,7 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::{fmt, mem, str};
|
use std::{fmt, str};
|
||||||
|
|
||||||
use bytes::{BufMut, Bytes, BytesMut};
|
use bytes::{BufMut, Bytes, BytesMut};
|
||||||
use cookie::{Cookie, CookieJar};
|
use cookie::{Cookie, CookieJar};
|
||||||
@ -12,7 +12,7 @@ use http::{Error as HttpError, HeaderMap, HttpTryFrom, StatusCode, Version};
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
use body::Body;
|
use body::{MessageBody, MessageBodyStream};
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use header::{ContentEncoding, Header, IntoHeaderValue};
|
use header::{ContentEncoding, Header, IntoHeaderValue};
|
||||||
use message::{Head, MessageFlags, ResponseHead};
|
use message::{Head, MessageFlags, ResponseHead};
|
||||||
@ -32,19 +32,9 @@ pub enum ConnectionType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An HTTP Response
|
/// An HTTP Response
|
||||||
pub struct Response(Box<InnerResponse>);
|
pub struct Response<B: MessageBody = ()>(Box<InnerResponse>, B);
|
||||||
|
|
||||||
impl Response {
|
|
||||||
#[inline]
|
|
||||||
fn get_ref(&self) -> &InnerResponse {
|
|
||||||
self.0.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_mut(&mut self) -> &mut InnerResponse {
|
|
||||||
self.0.as_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
impl Response<()> {
|
||||||
/// Create http response builder with specific status.
|
/// Create http response builder with specific status.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build(status: StatusCode) -> ResponseBuilder {
|
pub fn build(status: StatusCode) -> ResponseBuilder {
|
||||||
@ -60,13 +50,7 @@ impl Response {
|
|||||||
/// Constructs a response
|
/// Constructs a response
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(status: StatusCode) -> Response {
|
pub fn new(status: StatusCode) -> Response {
|
||||||
ResponsePool::with_body(status, Body::Empty)
|
ResponsePool::with_body(status, ())
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a response with body
|
|
||||||
#[inline]
|
|
||||||
pub fn with_body<B: Into<Body>>(status: StatusCode, body: B) -> Response {
|
|
||||||
ResponsePool::with_body(status, body.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs an error response
|
/// Constructs an error response
|
||||||
@ -98,6 +82,29 @@ impl Response {
|
|||||||
cookies: jar,
|
cookies: jar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: MessageBody> Response<B> {
|
||||||
|
#[inline]
|
||||||
|
fn get_ref(&self) -> &InnerResponse {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_mut(&mut self) -> &mut InnerResponse {
|
||||||
|
self.0.as_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn head_mut(&mut self) -> &mut ResponseHead {
|
||||||
|
&mut self.0.as_mut().head
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a response with body
|
||||||
|
#[inline]
|
||||||
|
pub fn with_body(status: StatusCode, body: B) -> Response<B> {
|
||||||
|
ResponsePool::with_body(status, body.into())
|
||||||
|
}
|
||||||
|
|
||||||
/// The source `error` for this response
|
/// The source `error` for this response
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -105,6 +112,39 @@ impl Response {
|
|||||||
self.get_ref().error.as_ref()
|
self.get_ref().error.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the response status code
|
||||||
|
#[inline]
|
||||||
|
pub fn status(&self) -> StatusCode {
|
||||||
|
self.get_ref().head.status
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the `StatusCode` for this response
|
||||||
|
#[inline]
|
||||||
|
pub fn status_mut(&mut self) -> &mut StatusCode {
|
||||||
|
&mut self.get_mut().head.status
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get custom reason for the response
|
||||||
|
#[inline]
|
||||||
|
pub fn reason(&self) -> &str {
|
||||||
|
if let Some(reason) = self.get_ref().head.reason {
|
||||||
|
reason
|
||||||
|
} else {
|
||||||
|
self.get_ref()
|
||||||
|
.head
|
||||||
|
.status
|
||||||
|
.canonical_reason()
|
||||||
|
.unwrap_or("<unknown status code>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the custom reason for the response
|
||||||
|
#[inline]
|
||||||
|
pub fn set_reason(&mut self, reason: &'static str) -> &mut Self {
|
||||||
|
self.get_mut().head.reason = Some(reason);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the headers from the response
|
/// Get the headers from the response
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn headers(&self) -> &HeaderMap {
|
pub fn headers(&self) -> &HeaderMap {
|
||||||
@ -167,39 +207,6 @@ impl Response {
|
|||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the response status code
|
|
||||||
#[inline]
|
|
||||||
pub fn status(&self) -> StatusCode {
|
|
||||||
self.get_ref().head.status
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the `StatusCode` for this response
|
|
||||||
#[inline]
|
|
||||||
pub fn status_mut(&mut self) -> &mut StatusCode {
|
|
||||||
&mut self.get_mut().head.status
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get custom reason for the response
|
|
||||||
#[inline]
|
|
||||||
pub fn reason(&self) -> &str {
|
|
||||||
if let Some(reason) = self.get_ref().head.reason {
|
|
||||||
reason
|
|
||||||
} else {
|
|
||||||
self.get_ref()
|
|
||||||
.head
|
|
||||||
.status
|
|
||||||
.canonical_reason()
|
|
||||||
.unwrap_or("<unknown status code>")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the custom reason for the response
|
|
||||||
#[inline]
|
|
||||||
pub fn set_reason(&mut self, reason: &'static str) -> &mut Self {
|
|
||||||
self.get_mut().head.reason = Some(reason);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set connection type
|
/// Set connection type
|
||||||
pub fn set_connection_type(&mut self, conn: ConnectionType) -> &mut Self {
|
pub fn set_connection_type(&mut self, conn: ConnectionType) -> &mut Self {
|
||||||
self.get_mut().connection_type = Some(conn);
|
self.get_mut().connection_type = Some(conn);
|
||||||
@ -224,38 +231,20 @@ impl Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// is chunked encoding enabled
|
|
||||||
#[inline]
|
|
||||||
pub fn chunked(&self) -> Option<bool> {
|
|
||||||
self.get_ref().chunked
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Content encoding
|
|
||||||
#[inline]
|
|
||||||
pub fn content_encoding(&self) -> Option<ContentEncoding> {
|
|
||||||
self.get_ref().encoding
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set content encoding
|
|
||||||
pub fn set_content_encoding(&mut self, enc: ContentEncoding) -> &mut Self {
|
|
||||||
self.get_mut().encoding = Some(enc);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get body os this response
|
/// Get body os this response
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn body(&self) -> &Body {
|
pub fn body(&self) -> &B {
|
||||||
&self.get_ref().body
|
&self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a body
|
/// Set a body
|
||||||
pub fn set_body<B: Into<Body>>(&mut self, body: B) {
|
pub fn set_body<B2: MessageBody>(self, body: B2) -> Response<B2> {
|
||||||
self.get_mut().body = body.into();
|
Response(self.0, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a body and return previous body value
|
/// Set a body and return previous body value
|
||||||
pub fn replace_body<B: Into<Body>>(&mut self, body: B) -> Body {
|
pub fn replace_body<B2: MessageBody>(self, body: B2) -> (Response<B2>, B) {
|
||||||
mem::replace(&mut self.get_mut().body, body.into())
|
(Response(self.0, body), self.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Size of response in bytes, excluding HTTP headers
|
/// Size of response in bytes, excluding HTTP headers
|
||||||
@ -268,16 +257,6 @@ impl Response {
|
|||||||
self.get_mut().response_size = size;
|
self.get_mut().response_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set write buffer capacity
|
|
||||||
pub fn write_buffer_capacity(&self) -> usize {
|
|
||||||
self.get_ref().write_capacity
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set write buffer capacity
|
|
||||||
pub fn set_write_buffer_capacity(&mut self, cap: usize) {
|
|
||||||
self.get_mut().write_capacity = cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn release(self) {
|
pub(crate) fn release(self) {
|
||||||
ResponsePool::release(self.0);
|
ResponsePool::release(self.0);
|
||||||
}
|
}
|
||||||
@ -287,7 +266,7 @@ impl Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_parts(parts: ResponseParts) -> Response {
|
pub(crate) fn from_parts(parts: ResponseParts) -> Response {
|
||||||
Response(Box::new(InnerResponse::from_parts(parts)))
|
Response(Box::new(InnerResponse::from_parts(parts)), ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,24 +433,6 @@ impl ResponseBuilder {
|
|||||||
self.connection_type(ConnectionType::Close)
|
self.connection_type(ConnectionType::Close)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables automatic chunked transfer encoding
|
|
||||||
#[inline]
|
|
||||||
pub fn chunked(&mut self) -> &mut Self {
|
|
||||||
if let Some(parts) = parts(&mut self.response, &self.err) {
|
|
||||||
parts.chunked = Some(true);
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Force disable chunked encoding
|
|
||||||
#[inline]
|
|
||||||
pub fn no_chunking(&mut self) -> &mut Self {
|
|
||||||
if let Some(parts) = parts(&mut self.response, &self.err) {
|
|
||||||
parts.chunked = Some(false);
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set response content type
|
/// Set response content type
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn content_type<V>(&mut self, value: V) -> &mut Self
|
pub fn content_type<V>(&mut self, value: V) -> &mut Self
|
||||||
@ -580,63 +541,73 @@ impl ResponseBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set write buffer capacity
|
// /// Set write buffer capacity
|
||||||
///
|
// ///
|
||||||
/// This parameter makes sense only for streaming response
|
// /// This parameter makes sense only for streaming response
|
||||||
/// or actor. If write buffer reaches specified capacity, stream or actor
|
// /// or actor. If write buffer reaches specified capacity, stream or actor
|
||||||
/// get paused.
|
// /// get paused.
|
||||||
///
|
// ///
|
||||||
/// Default write buffer capacity is 64kb
|
// /// Default write buffer capacity is 64kb
|
||||||
pub fn write_buffer_capacity(&mut self, cap: usize) -> &mut Self {
|
// pub fn write_buffer_capacity(&mut self, cap: usize) -> &mut Self {
|
||||||
if let Some(parts) = parts(&mut self.response, &self.err) {
|
// if let Some(parts) = parts(&mut self.response, &self.err) {
|
||||||
parts.write_capacity = cap;
|
// parts.write_capacity = cap;
|
||||||
}
|
// }
|
||||||
self
|
// self
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Set a body and generate `Response`.
|
/// Set a body and generate `Response`.
|
||||||
///
|
///
|
||||||
/// `ResponseBuilder` can not be used after this call.
|
/// `ResponseBuilder` can not be used after this call.
|
||||||
pub fn body<B: Into<Body>>(&mut self, body: B) -> Response {
|
pub fn body<B: MessageBody>(&mut self, body: B) -> Response<B> {
|
||||||
if let Some(e) = self.err.take() {
|
let mut error = if let Some(e) = self.err.take() {
|
||||||
return Error::from(e).into();
|
Some(Error::from(e))
|
||||||
}
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let mut response = self.response.take().expect("cannot reuse response builder");
|
let mut response = self.response.take().expect("cannot reuse response builder");
|
||||||
if let Some(ref jar) = self.cookies {
|
if let Some(ref jar) = self.cookies {
|
||||||
for cookie in jar.delta() {
|
for cookie in jar.delta() {
|
||||||
match HeaderValue::from_str(&cookie.to_string()) {
|
match HeaderValue::from_str(&cookie.to_string()) {
|
||||||
Ok(val) => response.head.headers.append(header::SET_COOKIE, val),
|
Ok(val) => {
|
||||||
Err(e) => return Error::from(e).into(),
|
let _ = response.head.headers.append(header::SET_COOKIE, val);
|
||||||
|
}
|
||||||
|
Err(e) => if error.is_none() {
|
||||||
|
error = Some(Error::from(e));
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response.body = body.into();
|
if let Some(error) = error {
|
||||||
Response(response)
|
response.error = Some(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Response(response, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Set a streaming body and generate `Response`.
|
/// Set a streaming body and generate `Response`.
|
||||||
///
|
///
|
||||||
/// `ResponseBuilder` can not be used after this call.
|
/// `ResponseBuilder` can not be used after this call.
|
||||||
pub fn streaming<S, E>(&mut self, stream: S) -> Response
|
pub fn streaming<S, E>(&mut self, stream: S) -> Response<impl MessageBody>
|
||||||
where
|
where
|
||||||
S: Stream<Item = Bytes, Error = E> + 'static,
|
S: Stream<Item = Bytes, Error = E> + 'static,
|
||||||
E: Into<Error>,
|
E: Into<Error>,
|
||||||
{
|
{
|
||||||
self.body(Body::Streaming(Box::new(stream.map_err(|e| e.into()))))
|
self.body(MessageBodyStream::new(stream.map_err(|e| e.into())))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a json body and generate `Response`
|
/// Set a json body and generate `Response`
|
||||||
///
|
///
|
||||||
/// `ResponseBuilder` can not be used after this call.
|
/// `ResponseBuilder` can not be used after this call.
|
||||||
pub fn json<T: Serialize>(&mut self, value: T) -> Response {
|
pub fn json<T: Serialize>(&mut self, value: T) -> Response<String> {
|
||||||
self.json2(&value)
|
self.json2(&value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a json body and generate `Response`
|
/// Set a json body and generate `Response`
|
||||||
///
|
///
|
||||||
/// `ResponseBuilder` can not be used after this call.
|
/// `ResponseBuilder` can not be used after this call.
|
||||||
pub fn json2<T: Serialize>(&mut self, value: &T) -> Response {
|
pub fn json2<T: Serialize>(&mut self, value: &T) -> Response<String> {
|
||||||
match serde_json::to_string(value) {
|
match serde_json::to_string(value) {
|
||||||
Ok(body) => {
|
Ok(body) => {
|
||||||
let contains = if let Some(parts) = parts(&mut self.response, &self.err)
|
let contains = if let Some(parts) = parts(&mut self.response, &self.err)
|
||||||
@ -651,7 +622,10 @@ impl ResponseBuilder {
|
|||||||
|
|
||||||
self.body(body)
|
self.body(body)
|
||||||
}
|
}
|
||||||
Err(e) => Error::from(e).into(),
|
Err(e) => {
|
||||||
|
let mut res: Response = Error::from(e).into();
|
||||||
|
res.replace_body(String::new()).0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,8 +633,8 @@ impl ResponseBuilder {
|
|||||||
/// Set an empty body and generate `Response`
|
/// Set an empty body and generate `Response`
|
||||||
///
|
///
|
||||||
/// `ResponseBuilder` can not be used after this call.
|
/// `ResponseBuilder` can not be used after this call.
|
||||||
pub fn finish(&mut self) -> Response {
|
pub fn finish(&mut self) -> Response<()> {
|
||||||
self.body(Body::Empty)
|
self.body(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method construct new `ResponseBuilder`
|
/// This method construct new `ResponseBuilder`
|
||||||
@ -701,7 +675,7 @@ impl From<ResponseBuilder> for Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&'static str> for Response {
|
impl From<&'static str> for Response<&'static str> {
|
||||||
fn from(val: &'static str) -> Self {
|
fn from(val: &'static str) -> Self {
|
||||||
Response::Ok()
|
Response::Ok()
|
||||||
.content_type("text/plain; charset=utf-8")
|
.content_type("text/plain; charset=utf-8")
|
||||||
@ -709,7 +683,7 @@ impl From<&'static str> for Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&'static [u8]> for Response {
|
impl From<&'static [u8]> for Response<&'static [u8]> {
|
||||||
fn from(val: &'static [u8]) -> Self {
|
fn from(val: &'static [u8]) -> Self {
|
||||||
Response::Ok()
|
Response::Ok()
|
||||||
.content_type("application/octet-stream")
|
.content_type("application/octet-stream")
|
||||||
@ -717,7 +691,7 @@ impl From<&'static [u8]> for Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Response {
|
impl From<String> for Response<String> {
|
||||||
fn from(val: String) -> Self {
|
fn from(val: String) -> Self {
|
||||||
Response::Ok()
|
Response::Ok()
|
||||||
.content_type("text/plain; charset=utf-8")
|
.content_type("text/plain; charset=utf-8")
|
||||||
@ -725,15 +699,7 @@ impl From<String> for Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a String> for Response {
|
impl From<Bytes> for Response<Bytes> {
|
||||||
fn from(val: &'a String) -> Self {
|
|
||||||
Response::build(StatusCode::OK)
|
|
||||||
.content_type("text/plain; charset=utf-8")
|
|
||||||
.body(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Bytes> for Response {
|
|
||||||
fn from(val: Bytes) -> Self {
|
fn from(val: Bytes) -> Self {
|
||||||
Response::Ok()
|
Response::Ok()
|
||||||
.content_type("application/octet-stream")
|
.content_type("application/octet-stream")
|
||||||
@ -741,7 +707,7 @@ impl From<Bytes> for Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BytesMut> for Response {
|
impl From<BytesMut> for Response<BytesMut> {
|
||||||
fn from(val: BytesMut) -> Self {
|
fn from(val: BytesMut) -> Self {
|
||||||
Response::Ok()
|
Response::Ok()
|
||||||
.content_type("application/octet-stream")
|
.content_type("application/octet-stream")
|
||||||
@ -751,8 +717,6 @@ impl From<BytesMut> for Response {
|
|||||||
|
|
||||||
struct InnerResponse {
|
struct InnerResponse {
|
||||||
head: ResponseHead,
|
head: ResponseHead,
|
||||||
body: Body,
|
|
||||||
chunked: Option<bool>,
|
|
||||||
encoding: Option<ContentEncoding>,
|
encoding: Option<ContentEncoding>,
|
||||||
connection_type: Option<ConnectionType>,
|
connection_type: Option<ConnectionType>,
|
||||||
write_capacity: usize,
|
write_capacity: usize,
|
||||||
@ -763,7 +727,6 @@ struct InnerResponse {
|
|||||||
|
|
||||||
pub(crate) struct ResponseParts {
|
pub(crate) struct ResponseParts {
|
||||||
head: ResponseHead,
|
head: ResponseHead,
|
||||||
body: Option<Bytes>,
|
|
||||||
encoding: Option<ContentEncoding>,
|
encoding: Option<ContentEncoding>,
|
||||||
connection_type: Option<ConnectionType>,
|
connection_type: Option<ConnectionType>,
|
||||||
error: Option<Error>,
|
error: Option<Error>,
|
||||||
@ -771,11 +734,7 @@ pub(crate) struct ResponseParts {
|
|||||||
|
|
||||||
impl InnerResponse {
|
impl InnerResponse {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new(
|
fn new(status: StatusCode, pool: &'static ResponsePool) -> InnerResponse {
|
||||||
status: StatusCode,
|
|
||||||
body: Body,
|
|
||||||
pool: &'static ResponsePool,
|
|
||||||
) -> InnerResponse {
|
|
||||||
InnerResponse {
|
InnerResponse {
|
||||||
head: ResponseHead {
|
head: ResponseHead {
|
||||||
status,
|
status,
|
||||||
@ -784,9 +743,7 @@ impl InnerResponse {
|
|||||||
reason: None,
|
reason: None,
|
||||||
flags: MessageFlags::empty(),
|
flags: MessageFlags::empty(),
|
||||||
},
|
},
|
||||||
body,
|
|
||||||
pool,
|
pool,
|
||||||
chunked: None,
|
|
||||||
encoding: None,
|
encoding: None,
|
||||||
connection_type: None,
|
connection_type: None,
|
||||||
response_size: 0,
|
response_size: 0,
|
||||||
@ -796,18 +753,8 @@ impl InnerResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This is for failure, we can not have Send + Sync on Streaming and Actor response
|
/// This is for failure, we can not have Send + Sync on Streaming and Actor response
|
||||||
fn into_parts(mut self) -> ResponseParts {
|
fn into_parts(self) -> ResponseParts {
|
||||||
let body = match mem::replace(&mut self.body, Body::Empty) {
|
|
||||||
Body::Empty => None,
|
|
||||||
Body::Binary(mut bin) => Some(bin.take()),
|
|
||||||
Body::Streaming(_) => {
|
|
||||||
error!("Streaming or Actor body is not support by error response");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ResponseParts {
|
ResponseParts {
|
||||||
body,
|
|
||||||
head: self.head,
|
head: self.head,
|
||||||
encoding: self.encoding,
|
encoding: self.encoding,
|
||||||
connection_type: self.connection_type,
|
connection_type: self.connection_type,
|
||||||
@ -816,16 +763,8 @@ impl InnerResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn from_parts(parts: ResponseParts) -> InnerResponse {
|
fn from_parts(parts: ResponseParts) -> InnerResponse {
|
||||||
let body = if let Some(ref body) = parts.body {
|
|
||||||
Body::Binary(body.clone().into())
|
|
||||||
} else {
|
|
||||||
Body::Empty
|
|
||||||
};
|
|
||||||
|
|
||||||
InnerResponse {
|
InnerResponse {
|
||||||
body,
|
|
||||||
head: parts.head,
|
head: parts.head,
|
||||||
chunked: None,
|
|
||||||
encoding: parts.encoding,
|
encoding: parts.encoding,
|
||||||
connection_type: parts.connection_type,
|
connection_type: parts.connection_type,
|
||||||
response_size: 0,
|
response_size: 0,
|
||||||
@ -864,7 +803,7 @@ impl ResponsePool {
|
|||||||
cookies: None,
|
cookies: None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let msg = Box::new(InnerResponse::new(status, Body::Empty, pool));
|
let msg = Box::new(InnerResponse::new(status, pool));
|
||||||
ResponseBuilder {
|
ResponseBuilder {
|
||||||
response: Some(msg),
|
response: Some(msg),
|
||||||
err: None,
|
err: None,
|
||||||
@ -874,17 +813,16 @@ impl ResponsePool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_response(
|
pub fn get_response<B: MessageBody>(
|
||||||
pool: &'static ResponsePool,
|
pool: &'static ResponsePool,
|
||||||
status: StatusCode,
|
status: StatusCode,
|
||||||
body: Body,
|
body: B,
|
||||||
) -> Response {
|
) -> Response<B> {
|
||||||
if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
|
if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
|
||||||
msg.head.status = status;
|
msg.head.status = status;
|
||||||
msg.body = body;
|
Response(msg, body)
|
||||||
Response(msg)
|
|
||||||
} else {
|
} else {
|
||||||
Response(Box::new(InnerResponse::new(status, body, pool)))
|
Response(Box::new(InnerResponse::new(status, pool)), body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -894,7 +832,7 @@ impl ResponsePool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_body(status: StatusCode, body: Body) -> Response {
|
fn with_body<B: MessageBody>(status: StatusCode, body: B) -> Response<B> {
|
||||||
POOL.with(|pool| ResponsePool::get_response(pool, status, body))
|
POOL.with(|pool| ResponsePool::get_response(pool, status, body))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -903,7 +841,6 @@ impl ResponsePool {
|
|||||||
let mut p = inner.pool.0.borrow_mut();
|
let mut p = inner.pool.0.borrow_mut();
|
||||||
if p.len() < 128 {
|
if p.len() < 128 {
|
||||||
inner.head.clear();
|
inner.head.clear();
|
||||||
inner.chunked = None;
|
|
||||||
inner.encoding = None;
|
inner.encoding = None;
|
||||||
inner.connection_type = None;
|
inner.connection_type = None;
|
||||||
inner.response_size = 0;
|
inner.response_size = 0;
|
||||||
|
132
src/service.rs
132
src/service.rs
@ -6,7 +6,7 @@ use futures::future::{ok, Either, FutureResult};
|
|||||||
use futures::{Async, AsyncSink, Future, Poll, Sink};
|
use futures::{Async, AsyncSink, Future, Poll, Sink};
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use body::Body;
|
use body::MessageBody;
|
||||||
use error::{Error, ResponseError};
|
use error::{Error, ResponseError};
|
||||||
use h1::{Codec, Message};
|
use h1::{Codec, Message};
|
||||||
use response::Response;
|
use response::Response;
|
||||||
@ -58,11 +58,11 @@ where
|
|||||||
match req {
|
match req {
|
||||||
Ok(r) => Either::A(ok(r)),
|
Ok(r) => Either::A(ok(r)),
|
||||||
Err((e, framed)) => {
|
Err((e, framed)) => {
|
||||||
let mut resp = e.error_response();
|
let mut res = e.error_response().set_body(format!("{}", e));
|
||||||
resp.set_body(format!("{}", e));
|
let (res, _body) = res.replace_body(());
|
||||||
Either::B(SendErrorFut {
|
Either::B(SendErrorFut {
|
||||||
framed: Some(framed),
|
framed: Some(framed),
|
||||||
res: Some(resp.into()),
|
res: Some(res.into()),
|
||||||
err: Some(e),
|
err: Some(e),
|
||||||
_t: PhantomData,
|
_t: PhantomData,
|
||||||
})
|
})
|
||||||
@ -109,30 +109,30 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SendResponse<T>(PhantomData<(T,)>);
|
pub struct SendResponse<T, B>(PhantomData<(T, B)>);
|
||||||
|
|
||||||
impl<T> Default for SendResponse<T>
|
impl<T, B> Default for SendResponse<T, B> {
|
||||||
where
|
|
||||||
T: AsyncRead + AsyncWrite,
|
|
||||||
{
|
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
SendResponse(PhantomData)
|
SendResponse(PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SendResponse<T>
|
impl<T, B> SendResponse<T, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
pub fn send(
|
pub fn send(
|
||||||
mut framed: Framed<T, Codec>,
|
mut framed: Framed<T, Codec>,
|
||||||
mut res: Response,
|
res: Response<B>,
|
||||||
) -> impl Future<Item = Framed<T, Codec>, Error = Error> {
|
) -> impl Future<Item = Framed<T, Codec>, Error = Error> {
|
||||||
// init codec
|
|
||||||
framed.get_codec_mut().prepare_te(&mut res);
|
|
||||||
|
|
||||||
// extract body from response
|
// extract body from response
|
||||||
let body = res.replace_body(Body::Empty);
|
let (mut res, body) = res.replace_body(());
|
||||||
|
|
||||||
|
// init codec
|
||||||
|
framed
|
||||||
|
.get_codec_mut()
|
||||||
|
.prepare_te(&mut res.head_mut(), &mut body.length());
|
||||||
|
|
||||||
// write response
|
// write response
|
||||||
SendResponseFut {
|
SendResponseFut {
|
||||||
@ -143,15 +143,16 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> NewService for SendResponse<T>
|
impl<T, B> NewService for SendResponse<T, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
type Request = (Response, Framed<T, Codec>);
|
type Request = (Response<B>, Framed<T, Codec>);
|
||||||
type Response = Framed<T, Codec>;
|
type Response = Framed<T, Codec>;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Service = SendResponse<T>;
|
type Service = SendResponse<T, B>;
|
||||||
type Future = FutureResult<Self::Service, Self::InitError>;
|
type Future = FutureResult<Self::Service, Self::InitError>;
|
||||||
|
|
||||||
fn new_service(&self) -> Self::Future {
|
fn new_service(&self) -> Self::Future {
|
||||||
@ -159,22 +160,25 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Service for SendResponse<T>
|
impl<T, B> Service for SendResponse<T, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
type Request = (Response, Framed<T, Codec>);
|
type Request = (Response<B>, Framed<T, Codec>);
|
||||||
type Response = Framed<T, Codec>;
|
type Response = Framed<T, Codec>;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = SendResponseFut<T>;
|
type Future = SendResponseFut<T, B>;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
Ok(Async::Ready(()))
|
Ok(Async::Ready(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, (mut res, mut framed): Self::Request) -> Self::Future {
|
fn call(&mut self, (res, mut framed): Self::Request) -> Self::Future {
|
||||||
framed.get_codec_mut().prepare_te(&mut res);
|
let (mut res, body) = res.replace_body(());
|
||||||
let body = res.replace_body(Body::Empty);
|
framed
|
||||||
|
.get_codec_mut()
|
||||||
|
.prepare_te(res.head_mut(), &mut body.length());
|
||||||
SendResponseFut {
|
SendResponseFut {
|
||||||
res: Some(Message::Item(res)),
|
res: Some(Message::Item(res)),
|
||||||
body: Some(body),
|
body: Some(body),
|
||||||
@ -183,73 +187,69 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SendResponseFut<T> {
|
pub struct SendResponseFut<T, B> {
|
||||||
res: Option<Message<Response>>,
|
res: Option<Message<Response>>,
|
||||||
body: Option<Body>,
|
body: Option<B>,
|
||||||
framed: Option<Framed<T, Codec>>,
|
framed: Option<Framed<T, Codec>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Future for SendResponseFut<T>
|
impl<T, B> Future for SendResponseFut<T, B>
|
||||||
where
|
where
|
||||||
T: AsyncRead + AsyncWrite,
|
T: AsyncRead + AsyncWrite,
|
||||||
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
type Item = Framed<T, Codec>;
|
type Item = Framed<T, Codec>;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
// send response
|
loop {
|
||||||
if self.res.is_some() {
|
let mut body_ready = self.body.is_some();
|
||||||
let framed = self.framed.as_mut().unwrap();
|
let framed = self.framed.as_mut().unwrap();
|
||||||
if !framed.is_write_buf_full() {
|
|
||||||
if let Some(res) = self.res.take() {
|
|
||||||
framed.force_send(res)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// send body
|
// send body
|
||||||
if self.res.is_none() && self.body.is_some() {
|
if self.res.is_none() && self.body.is_some() {
|
||||||
let framed = self.framed.as_mut().unwrap();
|
while body_ready && self.body.is_some() && !framed.is_write_buf_full() {
|
||||||
if !framed.is_write_buf_full() {
|
match self.body.as_mut().unwrap().poll_next()? {
|
||||||
let body = self.body.take().unwrap();
|
|
||||||
match body {
|
|
||||||
Body::Empty => (),
|
|
||||||
Body::Streaming(mut stream) => loop {
|
|
||||||
match stream.poll()? {
|
|
||||||
Async::Ready(item) => {
|
Async::Ready(item) => {
|
||||||
let done = item.is_none();
|
// body is done
|
||||||
framed.force_send(Message::Chunk(item.into()))?;
|
if item.is_none() {
|
||||||
if !done {
|
let _ = self.body.take();
|
||||||
if !framed.is_write_buf_full() {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
self.body = Some(Body::Streaming(stream));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
framed.force_send(Message::Chunk(item))?;
|
||||||
}
|
}
|
||||||
}
|
Async::NotReady => body_ready = false,
|
||||||
Async::NotReady => {
|
|
||||||
self.body = Some(Body::Streaming(stream));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Body::Binary(mut bin) => {
|
|
||||||
framed.force_send(Message::Chunk(Some(bin.take())))?;
|
|
||||||
framed.force_send(Message::Chunk(None))?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// flush
|
// flush write buffer
|
||||||
match self.framed.as_mut().unwrap().poll_complete()? {
|
if !framed.is_write_buf_empty() {
|
||||||
Async::Ready(_) => if self.res.is_some() || self.body.is_some() {
|
match framed.poll_complete()? {
|
||||||
return self.poll();
|
Async::Ready(_) => if body_ready {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return Ok(Async::NotReady);
|
||||||
},
|
},
|
||||||
Async::NotReady => return Ok(Async::NotReady),
|
Async::NotReady => return Ok(Async::NotReady),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Async::Ready(self.framed.take().unwrap()))
|
// send response
|
||||||
|
if let Some(res) = self.res.take() {
|
||||||
|
framed.force_send(res)?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.body.is_some() {
|
||||||
|
if body_ready {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return Ok(Async::NotReady);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(Async::Ready(self.framed.take().unwrap()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user