From f58065082e69f023a73faeed1d646a8ef067e02e Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 25 Jul 2018 10:30:55 -0700 Subject: [PATCH] fix missing content-encoding header for h2 connections #421 --- CHANGES.md | 15 ++++--- src/server/h2writer.rs | 94 ++++++++++++++++++++++++------------------ 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 494ad7a65..2b13657a0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,19 +4,24 @@ ### Added - * Add implementation of `FromRequest` for `Option` and `Result` +* Add implementation of `FromRequest` for `Option` and `Result` - * Allow to handle application prefix, i.e. allow to handle `/app` path +* Allow to handle application prefix, i.e. allow to handle `/app` path for application with `/app` prefix. Check [`App::prefix()`](https://actix.rs/actix-web/actix_web/struct.App.html#method.prefix) api doc. +* Add `CookieSessionBackend::http_only` method to set `HttpOnly` directive of cookies + +### Changed + +* Upgrade to cookie 0.11 + +* Removed the timestamp from the default logger middleware ### Fixed -* removed the timestamp from the default logger middleware - -* Add `CookieSessionBackend::http_only` method to set `HttpOnly` directive of cookies +* Missing response header "content-encoding" #421 ## [0.7.1] - 2018-07-21 diff --git a/src/server/h2writer.rs b/src/server/h2writer.rs index c4fc59972..c877250dd 100644 --- a/src/server/h2writer.rs +++ b/src/server/h2writer.rs @@ -8,16 +8,18 @@ use modhttp::Response; use std::rc::Rc; use std::{cmp, io}; -use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING}; use http::{HttpTryFrom, Method, Version}; use super::helpers; use super::message::Request; -use super::output::{Output, ResponseInfo}; +use super::output::{Output, ResponseInfo, ResponseLength}; use super::settings::WorkerSettings; use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE}; use body::{Binary, Body}; use header::ContentEncoding; +use http::header::{ + HeaderValue, CONNECTION, CONTENT_ENCODING, CONTENT_LENGTH, DATE, TRANSFER_ENCODING, +}; use httpresponse::HttpResponse; const CHUNK_SIZE: usize = 16_384; @@ -92,50 +94,63 @@ impl Writer for H2Writer { let mut info = ResponseInfo::new(req.inner.method == Method::HEAD); self.buffer.for_server(&mut info, &req.inner, msg, encoding); - // http2 specific - msg.headers_mut().remove(CONNECTION); - msg.headers_mut().remove(TRANSFER_ENCODING); - - // using helpers::date is quite a lot faster - if !msg.headers().contains_key(DATE) { - let mut bytes = BytesMut::with_capacity(29); - self.settings.set_date(&mut bytes, false); - msg.headers_mut() - .insert(DATE, HeaderValue::try_from(bytes.freeze()).unwrap()); - } - - let body = msg.replace_body(Body::Empty); - match body { - Body::Binary(ref bytes) => { - if bytes.is_empty() { - msg.headers_mut() - .insert(CONTENT_LENGTH, HeaderValue::from_static("0")); - self.flags.insert(Flags::EOF); - } else { - let mut val = BytesMut::new(); - helpers::convert_usize(bytes.len(), &mut val); - let l = val.len(); - msg.headers_mut().insert( - CONTENT_LENGTH, - HeaderValue::try_from(val.split_to(l - 2).freeze()).unwrap(), - ); - } - } - Body::Empty => { - self.flags.insert(Flags::EOF); - msg.headers_mut() - .insert(CONTENT_LENGTH, HeaderValue::from_static("0")); - } - _ => (), - } - + let mut has_date = false; let mut resp = Response::new(()); *resp.status_mut() = msg.status(); *resp.version_mut() = Version::HTTP_2; for (key, value) in msg.headers().iter() { + match *key { + // http2 specific + CONNECTION | TRANSFER_ENCODING => continue, + CONTENT_ENCODING => if encoding != ContentEncoding::Identity { + continue; + }, + CONTENT_LENGTH => match info.length { + ResponseLength::None => (), + _ => continue, + }, + DATE => has_date = true, + _ => (), + } resp.headers_mut().insert(key, value.clone()); } + // set date header + if !has_date { + let mut bytes = BytesMut::with_capacity(29); + self.settings.set_date(&mut bytes, false); + resp.headers_mut() + .insert(DATE, HeaderValue::try_from(bytes.freeze()).unwrap()); + } + + // content length + match info.length { + ResponseLength::Zero => { + resp.headers_mut() + .insert(CONTENT_LENGTH, HeaderValue::from_static("0")); + self.flags.insert(Flags::EOF); + } + ResponseLength::Length(len) => { + let mut val = BytesMut::new(); + helpers::convert_usize(len, &mut val); + let l = val.len(); + resp.headers_mut().insert( + CONTENT_LENGTH, + HeaderValue::try_from(val.split_to(l - 2).freeze()).unwrap(), + ); + } + ResponseLength::Length64(len) => { + let l = format!("{}", len); + resp.headers_mut() + .insert(CONTENT_LENGTH, HeaderValue::try_from(l.as_str()).unwrap()); + } + _ => (), + } + if let Some(ce) = info.content_encoding { + resp.headers_mut() + .insert(CONTENT_ENCODING, HeaderValue::try_from(ce).unwrap()); + } + match self .respond .send_response(resp, self.flags.contains(Flags::EOF)) @@ -146,6 +161,7 @@ impl Writer for H2Writer { trace!("Response: {:?}", msg); + let body = msg.replace_body(Body::Empty); if let Body::Binary(bytes) = body { if bytes.is_empty() { Ok(WriterState::Done)