diff --git a/.travis.yml b/.travis.yml
index 5dac530c..0419ed11 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -69,7 +69,7 @@ script:
# Upload docs
after_success:
- |
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" && "$TRAVIS_RUST_VERSION" == "nightly-2018-01-03" ]]; then
+ if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" && "$TRAVIS_RUST_VERSION" == "1.20.0" ]]; then
cargo doc --features alpn --no-deps &&
echo "" > target/doc/index.html &&
cargo install mdbook &&
diff --git a/CHANGES.md b/CHANGES.md
index 22b42266..df1308f8 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,7 +1,7 @@
# Changes
-## 0.3.0 (2017-xx-xx)
+## 0.3.0 (2018-01-12)
* HTTP/2 Support
diff --git a/Cargo.toml b/Cargo.toml
index 80a53a9c..cc87f724 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -36,10 +36,11 @@ alpn = ["openssl", "openssl/v102", "openssl/v110", "tokio-openssl"]
log = "0.4"
failure = "0.1"
failure_derive = "0.1"
-time = "0.1"
+h2 = "0.1"
http = "^0.1.2"
httparse = "1.2"
http-range = "0.1"
+time = "0.1"
mime = "0.3"
mime_guess = "1.8"
regex = "0.2"
@@ -54,8 +55,7 @@ smallvec = "0.6"
bitflags = "1.0"
num_cpus = "1.0"
-#flate2 = "1.0"
-flate2 = { git="https://github.com/fafhrd91/flate2-rs.git" }
+flate2 = "1.0"
# temp solution
# cookie = { version="0.10", features=["percent-encode", "secure"] }
@@ -69,8 +69,6 @@ futures = "0.1"
tokio-io = "0.1"
tokio-core = "0.1"
-h2 = { git = 'https://github.com/carllerche/h2' }
-
# native-tls
native-tls = { version="0.1", optional = true }
tokio-tls = { version="0.1", optional = true }
diff --git a/src/server/encoding.rs b/src/server/encoding.rs
index f9dbd64c..deb4a543 100644
--- a/src/server/encoding.rs
+++ b/src/server/encoding.rs
@@ -1,5 +1,5 @@
use std::{io, cmp, mem};
-use std::io::Write;
+use std::io::{Read, Write};
use std::fmt::Write as FmtWrite;
use std::str::FromStr;
@@ -8,7 +8,8 @@ use http::header::{HeaderMap, HeaderValue,
ACCEPT_ENCODING, CONNECTION,
CONTENT_ENCODING, CONTENT_LENGTH, TRANSFER_ENCODING};
use flate2::Compression;
-use flate2::write::{GzDecoder, GzEncoder, DeflateDecoder, DeflateEncoder};
+use flate2::read::GzDecoder;
+use flate2::write::{GzEncoder, DeflateDecoder, DeflateEncoder};
use brotli2::write::{BrotliDecoder, BrotliEncoder};
use bytes::{Bytes, BytesMut, BufMut, Writer};
@@ -122,15 +123,50 @@ impl PayloadWriter for PayloadType {
enum Decoder {
Deflate(Box>>),
- Gzip(Box>>),
+ Gzip(Option>>),
Br(Box>>),
Identity,
}
+// should go after write::GzDecoder get implemented
+#[derive(Debug)]
+struct Wrapper {
+ buf: BytesMut,
+ eof: bool,
+}
+
+impl io::Read for Wrapper {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result {
+ let len = cmp::min(buf.len(), self.buf.len());
+ buf[..len].copy_from_slice(&self.buf[..len]);
+ self.buf.split_to(len);
+ if len == 0 {
+ if self.eof {
+ Ok(0)
+ } else {
+ Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
+ }
+ } else {
+ Ok(len)
+ }
+ }
+}
+
+impl io::Write for Wrapper {
+ fn write(&mut self, buf: &[u8]) -> io::Result {
+ self.buf.extend_from_slice(buf);
+ Ok(buf.len())
+ }
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
/// Payload wrapper with content decompression support
pub(crate) struct EncodedPayload {
inner: PayloadSender,
decoder: Decoder,
+ dst: BytesMut,
error: bool,
}
@@ -141,11 +177,10 @@ impl EncodedPayload {
Box::new(BrotliDecoder::new(BytesMut::with_capacity(8192).writer()))),
ContentEncoding::Deflate => Decoder::Deflate(
Box::new(DeflateDecoder::new(BytesMut::with_capacity(8192).writer()))),
- ContentEncoding::Gzip => Decoder::Gzip(
- Box::new(GzDecoder::new(BytesMut::with_capacity(8192).writer()))),
+ ContentEncoding::Gzip => Decoder::Gzip(None),
_ => Decoder::Identity,
};
- EncodedPayload{ inner: inner, decoder: dec, error: false }
+ EncodedPayload{ inner: inner, decoder: dec, error: false, dst: BytesMut::new() }
}
}
@@ -174,16 +209,28 @@ impl PayloadWriter for EncodedPayload {
}
},
Decoder::Gzip(ref mut decoder) => {
- match decoder.try_finish() {
- Ok(_) => {
- let b = decoder.get_mut().get_mut().take().freeze();
- if !b.is_empty() {
- self.inner.feed_data(b);
+ if let Some(ref mut decoder) = *decoder {
+ decoder.as_mut().get_mut().eof = true;
+
+ loop {
+ self.dst.reserve(8192);
+ match decoder.read(unsafe{self.dst.bytes_mut()}) {
+ Ok(n) => {
+ if n == 0 {
+ self.inner.feed_eof();
+ return
+ } else {
+ unsafe{self.dst.set_len(n)};
+ self.inner.feed_data(self.dst.split_to(n).freeze());
+ }
+ }
+ Err(err) => {
+ break Some(err);
+ }
}
- self.inner.feed_eof();
- return
- },
- Err(err) => Some(err),
+ }
+ } else {
+ return
}
},
Decoder::Deflate(ref mut decoder) => {
@@ -231,14 +278,33 @@ impl PayloadWriter for EncodedPayload {
}
Decoder::Gzip(ref mut decoder) => {
- if decoder.write(&data).is_ok() && decoder.flush().is_ok() {
- let b = decoder.get_mut().get_mut().take().freeze();
- if !b.is_empty() {
- self.inner.feed_data(b);
- }
- return
+ if decoder.is_none() {
+ *decoder = Some(
+ Box::new(GzDecoder::new(
+ Wrapper{buf: BytesMut::from(data), eof: false})));
+ } else {
+ let _ = decoder.as_mut().unwrap().write(&data);
+ }
+
+ loop {
+ self.dst.reserve(8192);
+ match decoder.as_mut().as_mut().unwrap().read(unsafe{self.dst.bytes_mut()}) {
+ Ok(n) => {
+ if n == 0 {
+ return
+ } else {
+ unsafe{self.dst.set_len(n)};
+ self.inner.feed_data(self.dst.split_to(n).freeze());
+ }
+ }
+ Err(e) => {
+ if e.kind() == io::ErrorKind::WouldBlock {
+ return
+ }
+ break
+ }
+ }
}
- trace!("Error decoding gzip encoding");
}
Decoder::Deflate(ref mut decoder) => {