1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-07-03 09:36:36 +02:00

Compare commits

...

4 Commits

Author SHA1 Message Date
ed9971b212 Fix segfault in ServerSettings::get_response_builder() 2018-05-11 21:43:13 -07:00
75861a21ae backport #215 2018-05-09 05:29:49 -07:00
40b01df846 prep release 2018-04-24 12:25:31 -07:00
8495e92660 make flate crate optional 2018-04-24 12:24:24 -07:00
11 changed files with 103 additions and 35 deletions

View File

@ -8,7 +8,6 @@ cache:
matrix:
include:
- rust: 1.21.0
- rust: stable
- rust: beta
- rust: nightly

View File

@ -1,5 +1,20 @@
# Changes
## 0.5.8 (2018-05-11)
* Fix segfault in ServerSettings::get_response_builder()
## 0.5.7 (2018-05-09)
* Fix http/2 payload streaming #215
## 0.5.6 (2018-04-24)
* Make flate2 crate optional #200
## 0.5.5 (2018-04-24)
* Fix panic when Websocket is closed with no error code #191

View File

@ -1,6 +1,6 @@
[package]
name = "actix-web"
version = "0.5.5"
version = "0.5.8"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust."
readme = "README.md"
@ -76,7 +76,7 @@ lazy_static = "1.0"
url = { version="1.7", features=["query_encoding"] }
cookie = { version="0.10", features=["percent-encode"] }
brotli2 = { version="^0.3.2", optional = true }
flate2 = { version="1.0", default-features = false }
flate2 = { version="1.0", optional = true, default-features = false }
# io
mio = "^0.6.13"

View File

@ -7,8 +7,10 @@ use std::io::{self, Write};
#[cfg(feature = "brotli")]
use brotli2::write::BrotliEncoder;
use bytes::{BufMut, BytesMut};
use flate2::Compression;
#[cfg(feature = "flate2")]
use flate2::write::{DeflateEncoder, GzEncoder};
#[cfg(feature = "flate2")]
use flate2::Compression;
use futures::{Async, Poll};
use http::header::{HeaderValue, CONNECTION, CONTENT_ENCODING, CONTENT_LENGTH, DATE,
TRANSFER_ENCODING};
@ -18,9 +20,9 @@ use tokio_io::AsyncWrite;
use body::{Binary, Body};
use header::ContentEncoding;
use server::WriterState;
use server::encoding::{ContentEncoder, TransferEncoding};
use server::shared::SharedBytes;
use server::WriterState;
use client::ClientRequest;
@ -70,7 +72,7 @@ impl HttpClientWriter {
// !self.flags.contains(Flags::UPGRADE) }
fn write_to_stream<T: AsyncWrite>(
&mut self, stream: &mut T
&mut self, stream: &mut T,
) -> io::Result<WriterState> {
while !self.buffer.is_empty() {
match stream.write(self.buffer.as_ref()) {
@ -191,7 +193,7 @@ impl HttpClientWriter {
#[inline]
pub fn poll_completed<T: AsyncWrite>(
&mut self, stream: &mut T, shutdown: bool
&mut self, stream: &mut T, shutdown: bool,
) -> Poll<(), io::Error> {
match self.write_to_stream(stream) {
Ok(WriterState::Done) => {
@ -222,9 +224,11 @@ fn content_encoder(buf: SharedBytes, req: &mut ClientRequest) -> ContentEncoder
let tmp = SharedBytes::default();
let transfer = TransferEncoding::eof(tmp.clone());
let mut enc = match encoding {
#[cfg(feature = "flate2")]
ContentEncoding::Deflate => ContentEncoder::Deflate(
DeflateEncoder::new(transfer, Compression::default()),
),
#[cfg(feature = "flate2")]
ContentEncoding::Gzip => ContentEncoder::Gzip(GzEncoder::new(
transfer,
Compression::default(),
@ -283,10 +287,12 @@ fn content_encoder(buf: SharedBytes, req: &mut ClientRequest) -> ContentEncoder
req.replace_body(body);
match encoding {
#[cfg(feature = "flate2")]
ContentEncoding::Deflate => ContentEncoder::Deflate(DeflateEncoder::new(
transfer,
Compression::default(),
)),
#[cfg(feature = "flate2")]
ContentEncoding::Gzip => {
ContentEncoder::Gzip(GzEncoder::new(transfer, Compression::default()))
}
@ -299,7 +305,7 @@ fn content_encoder(buf: SharedBytes, req: &mut ClientRequest) -> ContentEncoder
}
fn streaming_encoding(
buf: SharedBytes, version: Version, req: &mut ClientRequest
buf: SharedBytes, version: Version, req: &mut ClientRequest,
) -> TransferEncoding {
if req.chunked() {
// Enable transfer encoding

View File

@ -6,8 +6,8 @@ use std::str::FromStr;
use bytes::{Bytes, BytesMut};
use mime::Mime;
use modhttp::Error as HttpError;
use modhttp::header::GetAll;
use modhttp::Error as HttpError;
pub use modhttp::header::*;
@ -116,8 +116,10 @@ pub enum ContentEncoding {
#[cfg(feature = "brotli")]
Br,
/// A format using the zlib structure with deflate algorithm
#[cfg(feature = "flate2")]
Deflate,
/// Gzip algorithm
#[cfg(feature = "flate2")]
Gzip,
/// Indicates the identity function (i.e. no compression, nor modification)
Identity,
@ -137,7 +139,9 @@ impl ContentEncoding {
match *self {
#[cfg(feature = "brotli")]
ContentEncoding::Br => "br",
#[cfg(feature = "flate2")]
ContentEncoding::Gzip => "gzip",
#[cfg(feature = "flate2")]
ContentEncoding::Deflate => "deflate",
ContentEncoding::Identity | ContentEncoding::Auto => "identity",
}
@ -149,7 +153,9 @@ impl ContentEncoding {
match *self {
#[cfg(feature = "brotli")]
ContentEncoding::Br => 1.1,
#[cfg(feature = "flate2")]
ContentEncoding::Gzip => 1.0,
#[cfg(feature = "flate2")]
ContentEncoding::Deflate => 0.9,
ContentEncoding::Identity | ContentEncoding::Auto => 0.1,
}
@ -159,10 +165,12 @@ impl ContentEncoding {
// TODO: remove memory allocation
impl<'a> From<&'a str> for ContentEncoding {
fn from(s: &'a str) -> ContentEncoding {
match s.trim().to_lowercase().as_ref() {
match AsRef::<str>::as_ref(&s.trim().to_lowercase()) {
#[cfg(feature = "brotli")]
"br" => ContentEncoding::Br,
#[cfg(feature = "flate2")]
"gzip" => ContentEncoding::Gzip,
#[cfg(feature = "flate2")]
"deflate" => ContentEncoding::Deflate,
_ => ContentEncoding::Identity,
}
@ -202,7 +210,7 @@ impl fmt::Write for Writer {
#[doc(hidden)]
/// Reads a comma-delimited raw header into a Vec.
pub fn from_comma_delimited<T: FromStr>(
all: GetAll<HeaderValue>
all: GetAll<HeaderValue>,
) -> Result<Vec<T>, ParseError> {
let mut result = Vec::new();
for h in all {

View File

@ -64,8 +64,10 @@
#![cfg_attr(actix_nightly, feature(
specialization, // for impl ErrorResponse for std::error::Error
))]
#![cfg_attr(feature = "cargo-clippy",
allow(decimal_literal_representation, suspicious_arithmetic_impl))]
#![cfg_attr(
feature = "cargo-clippy",
allow(decimal_literal_representation, suspicious_arithmetic_impl)
)]
#[macro_use]
extern crate log;
@ -103,6 +105,7 @@ extern crate serde;
#[cfg(feature = "brotli")]
extern crate brotli2;
extern crate encoding;
#[cfg(feature = "flate2")]
extern crate flate2;
extern crate h2 as http2;
extern crate num_cpus;

View File

@ -491,8 +491,8 @@ impl<S: 'static, H> ProcessResponse<S, H> {
if let Some(err) = self.resp.error() {
if self.resp.status().is_server_error() {
error!(
"Error occured during request handling: {}",
err
"Error occured during request handling, status: {} {}",
self.resp.status(), err
);
} else {
warn!(

View File

@ -6,11 +6,14 @@ use std::{cmp, io, mem};
#[cfg(feature = "brotli")]
use brotli2::write::{BrotliDecoder, BrotliEncoder};
use bytes::{BufMut, Bytes, BytesMut};
use flate2::Compression;
#[cfg(feature = "flate2")]
use flate2::read::GzDecoder;
#[cfg(feature = "flate2")]
use flate2::write::{DeflateDecoder, DeflateEncoder, GzEncoder};
use http::header::{HeaderMap, HeaderValue, ACCEPT_ENCODING,
CONTENT_ENCODING, CONTENT_LENGTH, TRANSFER_ENCODING};
#[cfg(feature = "flate2")]
use flate2::Compression;
use http::header::{HeaderMap, HeaderValue, ACCEPT_ENCODING, CONTENT_ENCODING,
CONTENT_LENGTH, TRANSFER_ENCODING};
use http::{HttpTryFrom, Method, Version};
use body::{Binary, Body};
@ -144,7 +147,9 @@ impl PayloadWriter for EncodedPayload {
}
pub(crate) enum Decoder {
#[cfg(feature = "flate2")]
Deflate(Box<DeflateDecoder<Writer>>),
#[cfg(feature = "flate2")]
Gzip(Option<Box<GzDecoder<Wrapper>>>),
#[cfg(feature = "brotli")]
Br(Box<BrotliDecoder<Writer>>),
@ -223,9 +228,11 @@ impl PayloadStream {
ContentEncoding::Br => {
Decoder::Br(Box::new(BrotliDecoder::new(Writer::new())))
}
#[cfg(feature = "flate2")]
ContentEncoding::Deflate => {
Decoder::Deflate(Box::new(DeflateDecoder::new(Writer::new())))
}
#[cfg(feature = "flate2")]
ContentEncoding::Gzip => Decoder::Gzip(None),
_ => Decoder::Identity,
};
@ -251,6 +258,7 @@ impl PayloadStream {
}
Err(e) => Err(e),
},
#[cfg(feature = "flate2")]
Decoder::Gzip(ref mut decoder) => {
if let Some(ref mut decoder) = *decoder {
decoder.as_mut().get_mut().eof = true;
@ -267,6 +275,7 @@ impl PayloadStream {
Ok(None)
}
}
#[cfg(feature = "flate2")]
Decoder::Deflate(ref mut decoder) => match decoder.try_finish() {
Ok(_) => {
let b = decoder.get_mut().take();
@ -297,6 +306,7 @@ impl PayloadStream {
}
Err(e) => Err(e),
},
#[cfg(feature = "flate2")]
Decoder::Gzip(ref mut decoder) => {
if decoder.is_none() {
*decoder = Some(Box::new(GzDecoder::new(Wrapper {
@ -334,6 +344,7 @@ impl PayloadStream {
}
}
}
#[cfg(feature = "flate2")]
Decoder::Deflate(ref mut decoder) => match decoder.write_all(&data) {
Ok(_) => {
decoder.flush()?;
@ -352,7 +363,9 @@ impl PayloadStream {
}
pub(crate) enum ContentEncoder {
#[cfg(feature = "flate2")]
Deflate(DeflateEncoder<TransferEncoding>),
#[cfg(feature = "flate2")]
Gzip(GzEncoder<TransferEncoding>),
#[cfg(feature = "brotli")]
Br(BrotliEncoder<TransferEncoding>),
@ -422,9 +435,11 @@ impl ContentEncoder {
let tmp = SharedBytes::default();
let transfer = TransferEncoding::eof(tmp.clone());
let mut enc = match encoding {
#[cfg(feature = "flate2")]
ContentEncoding::Deflate => ContentEncoder::Deflate(
DeflateEncoder::new(transfer, Compression::fast()),
),
#[cfg(feature = "flate2")]
ContentEncoding::Gzip => ContentEncoder::Gzip(GzEncoder::new(
transfer,
Compression::fast(),
@ -478,10 +493,12 @@ impl ContentEncoder {
}
match encoding {
#[cfg(feature = "flate2")]
ContentEncoding::Deflate => ContentEncoder::Deflate(DeflateEncoder::new(
transfer,
Compression::fast(),
)),
#[cfg(feature = "flate2")]
ContentEncoding::Gzip => {
ContentEncoder::Gzip(GzEncoder::new(transfer, Compression::fast()))
}
@ -494,7 +511,7 @@ impl ContentEncoder {
}
fn streaming_encoding(
buf: SharedBytes, version: Version, resp: &mut HttpResponse
buf: SharedBytes, version: Version, resp: &mut HttpResponse,
) -> TransferEncoding {
match resp.chunked() {
Some(true) => {
@ -563,7 +580,9 @@ impl ContentEncoder {
match *self {
#[cfg(feature = "brotli")]
ContentEncoder::Br(ref encoder) => encoder.get_ref().is_eof(),
#[cfg(feature = "flate2")]
ContentEncoder::Deflate(ref encoder) => encoder.get_ref().is_eof(),
#[cfg(feature = "flate2")]
ContentEncoder::Gzip(ref encoder) => encoder.get_ref().is_eof(),
ContentEncoder::Identity(ref encoder) => encoder.is_eof(),
}
@ -587,6 +606,7 @@ impl ContentEncoder {
}
Err(err) => Err(err),
},
#[cfg(feature = "flate2")]
ContentEncoder::Gzip(encoder) => match encoder.finish() {
Ok(mut writer) => {
writer.encode_eof();
@ -595,6 +615,7 @@ impl ContentEncoder {
}
Err(err) => Err(err),
},
#[cfg(feature = "flate2")]
ContentEncoder::Deflate(encoder) => match encoder.finish() {
Ok(mut writer) => {
writer.encode_eof();
@ -625,6 +646,7 @@ impl ContentEncoder {
}
}
}
#[cfg(feature = "flate2")]
ContentEncoder::Gzip(ref mut encoder) => {
match encoder.write_all(data.as_ref()) {
Ok(_) => Ok(()),
@ -634,6 +656,7 @@ impl ContentEncoder {
}
}
}
#[cfg(feature = "flate2")]
ContentEncoder::Deflate(ref mut encoder) => {
match encoder.write_all(data.as_ref()) {
Ok(_) => Ok(()),

View File

@ -343,24 +343,27 @@ impl<H: 'static> Entry<H> {
}
fn poll_payload(&mut self) {
if !self.flags.contains(EntryFlags::REOF) {
if self.payload.need_read() == PayloadStatus::Read {
if let Err(err) = self.recv.release_capacity().release_capacity(32_768) {
self.payload.set_error(PayloadError::Http2(err))
}
} else if let Err(err) = self.recv.release_capacity().release_capacity(0) {
self.payload.set_error(PayloadError::Http2(err))
}
while !self.flags.contains(EntryFlags::REOF)
&& self.payload.need_read() == PayloadStatus::Read
{
match self.recv.poll() {
Ok(Async::Ready(Some(chunk))) => {
let l = chunk.len();
self.payload.feed_data(chunk);
if let Err(err) = self.recv.release_capacity().release_capacity(l) {
self.payload.set_error(PayloadError::Http2(err));
break;
}
}
Ok(Async::Ready(None)) => {
self.flags.insert(EntryFlags::REOF);
self.payload.feed_eof();
}
Ok(Async::NotReady) => break,
Err(err) => {
self.payload.set_error(PayloadError::Http2(err));
break;
}
Ok(Async::NotReady) => (),
Err(err) => self.payload.set_error(PayloadError::Http2(err)),
}
}
}

View File

@ -8,15 +8,14 @@ use std::sync::Arc;
use std::{fmt, mem, net};
use time;
use super::KeepAlive;
use super::channel::Node;
use super::helpers;
use super::shared::{SharedBytes, SharedBytesPool};
use super::KeepAlive;
use body::Body;
use httpresponse::{HttpResponse, HttpResponseBuilder, HttpResponsePool};
/// Various server settings
#[derive(Clone)]
pub struct ServerSettings {
addr: Option<net::SocketAddr>,
secure: bool,
@ -28,6 +27,18 @@ pub struct ServerSettings {
unsafe impl Sync for ServerSettings {}
unsafe impl Send for ServerSettings {}
impl Clone for ServerSettings {
fn clone(&self) -> Self {
ServerSettings {
addr: self.addr,
secure: self.secure,
host: self.host.clone(),
cpu_pool: self.cpu_pool.clone(),
responses: HttpResponsePool::pool(),
}
}
}
struct InnerCpuPool {
cpu_pool: UnsafeCell<Option<CpuPool>>,
}
@ -72,7 +83,7 @@ impl Default for ServerSettings {
impl ServerSettings {
/// Crate server settings instance
pub(crate) fn new(
addr: Option<net::SocketAddr>, host: &Option<String>, secure: bool
addr: Option<net::SocketAddr>, host: &Option<String>, secure: bool,
) -> ServerSettings {
let host = if let Some(ref host) = *host {
host.clone()
@ -119,7 +130,7 @@ impl ServerSettings {
#[inline]
pub(crate) fn get_response_builder(
&self, status: StatusCode
&self, status: StatusCode,
) -> HttpResponseBuilder {
HttpResponsePool::get_builder(&self.responses, status)
}

View File

@ -814,7 +814,7 @@ fn test_h2() {
})
});
let _res = core.run(tcp);
// assert_eq!(res.unwrap(), Bytes::from_static(STR.as_ref()));
// assert_eq!(_res.unwrap(), Bytes::from_static(STR.as_ref()));
}
#[test]