1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 07:53:00 +01:00

allow to set default content encoding on application level

This commit is contained in:
Nikolay Kim 2018-02-18 22:23:17 -08:00
parent 816c6fb0e0
commit edd114f6e4
11 changed files with 73 additions and 21 deletions

View File

@ -1,15 +1,25 @@
# Changes # Changes
## 0.3.4 (2018-..-..) ## 0.4.0 (2018-02-..)
* Actix 0.5 compatibility
* Fix request json loader * Fix request json loader
* Simplify HttpServer type definition
* Added HttpRequest::mime_type() method * Added HttpRequest::mime_type() method
* Added HttpRequest::uri_mut(), allows to modify request uri
* Added StaticFiles::index_file() * Added StaticFiles::index_file()
* Added basic websocket client * Added basic websocket client
* Added TestServer::ws(), test websockets client
* Allow to override content encoding on application level
## 0.3.3 (2018-01-25) ## 0.3.3 (2018-01-25)

View File

@ -17,7 +17,7 @@ If you already have rustup installed, run this command to ensure you have the la
rustup update rustup update
``` ```
Actix web framework requires rust version 1.20 and up. Actix web framework requires rust version 1.21 and up.
## Running Examples ## Running Examples

View File

@ -6,6 +6,7 @@ use std::collections::HashMap;
use handler::Reply; use handler::Reply;
use router::{Router, Pattern}; use router::{Router, Pattern};
use resource::Resource; use resource::Resource;
use headers::ContentEncoding;
use handler::{Handler, RouteHandler, WrapHandler}; use handler::{Handler, RouteHandler, WrapHandler};
use httprequest::HttpRequest; use httprequest::HttpRequest;
use pipeline::{Pipeline, PipelineHandler}; use pipeline::{Pipeline, PipelineHandler};
@ -24,6 +25,7 @@ pub struct HttpApplication<S=()> {
pub(crate) struct Inner<S> { pub(crate) struct Inner<S> {
prefix: usize, prefix: usize,
default: Resource<S>, default: Resource<S>,
encoding: ContentEncoding,
router: Router, router: Router,
resources: Vec<Resource<S>>, resources: Vec<Resource<S>>,
handlers: Vec<(String, Box<RouteHandler<S>>)>, handlers: Vec<(String, Box<RouteHandler<S>>)>,
@ -31,6 +33,10 @@ pub(crate) struct Inner<S> {
impl<S: 'static> PipelineHandler<S> for Inner<S> { impl<S: 'static> PipelineHandler<S> for Inner<S> {
fn encoding(&self) -> ContentEncoding {
self.encoding
}
fn handle(&mut self, mut req: HttpRequest<S>) -> Reply { fn handle(&mut self, mut req: HttpRequest<S>) -> Reply {
if let Some(idx) = self.router.recognize(&mut req) { if let Some(idx) = self.router.recognize(&mut req) {
self.resources[idx].handle(req.clone(), Some(&mut self.default)) self.resources[idx].handle(req.clone(), Some(&mut self.default))
@ -97,6 +103,7 @@ struct ApplicationParts<S> {
resources: HashMap<Pattern, Option<Resource<S>>>, resources: HashMap<Pattern, Option<Resource<S>>>,
handlers: Vec<(String, Box<RouteHandler<S>>)>, handlers: Vec<(String, Box<RouteHandler<S>>)>,
external: HashMap<String, Pattern>, external: HashMap<String, Pattern>,
encoding: ContentEncoding,
middlewares: Vec<Box<Middleware<S>>>, middlewares: Vec<Box<Middleware<S>>>,
} }
@ -119,6 +126,7 @@ impl Application<()> {
resources: HashMap::new(), resources: HashMap::new(),
handlers: Vec::new(), handlers: Vec::new(),
external: HashMap::new(), external: HashMap::new(),
encoding: ContentEncoding::Auto,
middlewares: Vec::new(), middlewares: Vec::new(),
}) })
} }
@ -149,6 +157,7 @@ impl<S> Application<S> where S: 'static {
handlers: Vec::new(), handlers: Vec::new(),
external: HashMap::new(), external: HashMap::new(),
middlewares: Vec::new(), middlewares: Vec::new(),
encoding: ContentEncoding::Auto,
}) })
} }
} }
@ -253,6 +262,16 @@ impl<S> Application<S> where S: 'static {
self self
} }
/// Set default content encoding. `ContentEncoding::Auto` is set by default.
pub fn default_encoding<F>(mut self, encoding: ContentEncoding) -> Application<S>
{
{
let parts = self.parts.as_mut().expect("Use after finish");
parts.encoding = encoding;
}
self
}
/// Register external resource. /// Register external resource.
/// ///
/// External resources are useful for URL generation purposes only and /// External resources are useful for URL generation purposes only and
@ -344,6 +363,7 @@ impl<S> Application<S> where S: 'static {
Inner { Inner {
prefix: prefix.len(), prefix: prefix.len(),
default: parts.default, default: parts.default,
encoding: parts.encoding,
router: router.clone(), router: router.clone(),
resources: resources, resources: resources,
handlers: parts.handlers, handlers: parts.handlers,

View File

@ -162,13 +162,13 @@ impl HttpResponse {
/// Content encoding /// Content encoding
#[inline] #[inline]
pub fn content_encoding(&self) -> ContentEncoding { pub fn content_encoding(&self) -> Option<ContentEncoding> {
self.get_ref().encoding self.get_ref().encoding
} }
/// Set content encoding /// Set content encoding
pub fn set_content_encoding(&mut self, enc: ContentEncoding) -> &mut Self { pub fn set_content_encoding(&mut self, enc: ContentEncoding) -> &mut Self {
self.get_mut().encoding = enc; self.get_mut().encoding = Some(enc);
self self
} }
@ -294,7 +294,7 @@ impl HttpResponseBuilder {
#[inline] #[inline]
pub fn content_encoding(&mut self, enc: ContentEncoding) -> &mut Self { pub fn content_encoding(&mut self, enc: ContentEncoding) -> &mut Self {
if let Some(parts) = parts(&mut self.response, &self.err) { if let Some(parts) = parts(&mut self.response, &self.err) {
parts.encoding = enc; parts.encoding = Some(enc);
} }
self self
} }
@ -648,7 +648,7 @@ struct InnerHttpResponse {
reason: Option<&'static str>, reason: Option<&'static str>,
body: Body, body: Body,
chunked: Option<bool>, chunked: Option<bool>,
encoding: ContentEncoding, encoding: Option<ContentEncoding>,
connection_type: Option<ConnectionType>, connection_type: Option<ConnectionType>,
response_size: u64, response_size: u64,
error: Option<Error>, error: Option<Error>,
@ -665,7 +665,7 @@ impl InnerHttpResponse {
reason: None, reason: None,
body: body, body: body,
chunked: None, chunked: None,
encoding: ContentEncoding::Auto, encoding: None,
connection_type: None, connection_type: None,
response_size: 0, response_size: 0,
error: None, error: None,
@ -717,7 +717,7 @@ impl Pool {
inner.version = None; inner.version = None;
inner.chunked = None; inner.chunked = None;
inner.reason = None; inner.reason = None;
inner.encoding = ContentEncoding::Auto; inner.encoding = None;
inner.connection_type = None; inner.connection_type = None;
inner.response_size = 0; inner.response_size = 0;
inner.error = None; inner.error = None;
@ -809,11 +809,11 @@ mod tests {
#[test] #[test]
fn test_content_encoding() { fn test_content_encoding() {
let resp = HttpResponse::build(StatusCode::OK).finish().unwrap(); let resp = HttpResponse::build(StatusCode::OK).finish().unwrap();
assert_eq!(resp.content_encoding(), ContentEncoding::Auto); assert_eq!(resp.content_encoding(), None);
let resp = HttpResponse::build(StatusCode::OK) let resp = HttpResponse::build(StatusCode::OK)
.content_encoding(ContentEncoding::Br).finish().unwrap(); .content_encoding(ContentEncoding::Br).finish().unwrap();
assert_eq!(resp.content_encoding(), ContentEncoding::Br); assert_eq!(resp.content_encoding(), Some(ContentEncoding::Br));
} }
#[test] #[test]

View File

@ -24,8 +24,8 @@
//! * [User Guide](http://actix.github.io/actix-web/guide/) //! * [User Guide](http://actix.github.io/actix-web/guide/)
//! * [Chat on gitter](https://gitter.im/actix/actix) //! * [Chat on gitter](https://gitter.im/actix/actix)
//! * [GitHub repository](https://github.com/actix/actix-web) //! * [GitHub repository](https://github.com/actix/actix-web)
//! * Cargo package: [actix-web](https://crates.io/crates/actix-web) //! * [Cargo package](https://crates.io/crates/actix-web)
//! * Supported Rust version: 1.20 or later //! * Supported Rust version: 1.21 or later
//! //!
//! ## Features //! ## Features
//! //!

View File

@ -441,7 +441,6 @@ impl CorsBuilder {
/// [Resource Processing Model](https://www.w3.org/TR/cors/#resource-processing-model). /// [Resource Processing Model](https://www.w3.org/TR/cors/#resource-processing-model).
/// ///
/// Defaults to `All`. /// Defaults to `All`.
/// ```
pub fn allowed_origin(&mut self, origin: &str) -> &mut CorsBuilder { pub fn allowed_origin(&mut self, origin: &str) -> &mut CorsBuilder {
if let Some(cors) = cors(&mut self.cors, &self.error) { if let Some(cors) = cors(&mut self.cors, &self.error) {
match Uri::try_from(origin) { match Uri::try_from(origin) {

View File

@ -10,6 +10,7 @@ use futures::unsync::oneshot;
use body::{Body, BodyStream}; use body::{Body, BodyStream};
use context::{Frame, ActorHttpContext}; use context::{Frame, ActorHttpContext};
use error::Error; use error::Error;
use headers::ContentEncoding;
use handler::{Reply, ReplyItem}; use handler::{Reply, ReplyItem};
use httprequest::HttpRequest; use httprequest::HttpRequest;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
@ -18,6 +19,9 @@ use application::Inner;
use server::{Writer, WriterState, HttpHandlerTask}; use server::{Writer, WriterState, HttpHandlerTask};
pub(crate) trait PipelineHandler<S> { pub(crate) trait PipelineHandler<S> {
fn encoding(&self) -> ContentEncoding;
fn handle(&mut self, req: HttpRequest<S>) -> Reply; fn handle(&mut self, req: HttpRequest<S>) -> Reply;
} }
@ -62,6 +66,7 @@ struct PipelineInfo<S> {
context: Option<Box<ActorHttpContext>>, context: Option<Box<ActorHttpContext>>,
error: Option<Error>, error: Option<Error>,
disconnected: Option<bool>, disconnected: Option<bool>,
encoding: ContentEncoding,
} }
impl<S> PipelineInfo<S> { impl<S> PipelineInfo<S> {
@ -73,6 +78,7 @@ impl<S> PipelineInfo<S> {
error: None, error: None,
context: None, context: None,
disconnected: None, disconnected: None,
encoding: ContentEncoding::Auto,
} }
} }
@ -108,6 +114,7 @@ impl<S: 'static, H: PipelineHandler<S>> Pipeline<S, H> {
error: None, error: None,
context: None, context: None,
disconnected: None, disconnected: None,
encoding: handler.borrow().encoding(),
}; };
let state = StartMiddlewares::init(&mut info, handler); let state = StartMiddlewares::init(&mut info, handler);
@ -451,7 +458,11 @@ impl<S: 'static, H> ProcessResponse<S, H> {
'outter: loop { 'outter: loop {
let result = match mem::replace(&mut self.iostate, IOState::Done) { let result = match mem::replace(&mut self.iostate, IOState::Done) {
IOState::Response => { IOState::Response => {
let result = match io.start(info.req_mut().get_inner(), &mut self.resp) { let encoding = self.resp.content_encoding().unwrap_or(info.encoding);
let result = match io.start(info.req_mut().get_inner(),
&mut self.resp, encoding)
{
Ok(res) => res, Ok(res) => res,
Err(err) => { Err(err) => {
info.error = Some(err.into()); info.error = Some(err.into());

View File

@ -347,10 +347,13 @@ impl PayloadEncoder {
PayloadEncoder(ContentEncoder::Identity(TransferEncoding::eof(bytes))) PayloadEncoder(ContentEncoder::Identity(TransferEncoding::eof(bytes)))
} }
pub fn new(buf: SharedBytes, req: &HttpMessage, resp: &mut HttpResponse) -> PayloadEncoder { pub fn new(buf: SharedBytes,
req: &HttpMessage,
resp: &mut HttpResponse,
response_encoding: ContentEncoding) -> PayloadEncoder
{
let version = resp.version().unwrap_or_else(|| req.version); let version = resp.version().unwrap_or_else(|| req.version);
let mut body = resp.replace_body(Body::Empty); let mut body = resp.replace_body(Body::Empty);
let response_encoding = resp.content_encoding();
let has_body = match body { let has_body = match body {
Body::Empty => false, Body::Empty => false,
Body::Binary(ref bin) => Body::Binary(ref bin) =>

View File

@ -7,6 +7,7 @@ use http::header::{HeaderValue, CONNECTION, DATE};
use helpers; use helpers;
use body::{Body, Binary}; use body::{Body, Binary};
use headers::ContentEncoding;
use httprequest::HttpMessage; use httprequest::HttpMessage;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE}; use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
@ -94,9 +95,13 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
self.written self.written
} }
fn start(&mut self, req: &mut HttpMessage, msg: &mut HttpResponse) -> io::Result<WriterState> { fn start(&mut self,
req: &mut HttpMessage,
msg: &mut HttpResponse,
encoding: ContentEncoding) -> io::Result<WriterState>
{
// prepare task // prepare task
self.encoder = PayloadEncoder::new(self.buffer.clone(), req, msg); self.encoder = PayloadEncoder::new(self.buffer.clone(), req, msg, encoding);
if msg.keep_alive().unwrap_or_else(|| req.keep_alive()) { if msg.keep_alive().unwrap_or_else(|| req.keep_alive()) {
self.flags.insert(Flags::STARTED | Flags::KEEPALIVE); self.flags.insert(Flags::STARTED | Flags::KEEPALIVE);
} else { } else {

View File

@ -8,6 +8,7 @@ use http::header::{HeaderValue, CONNECTION, TRANSFER_ENCODING, DATE, CONTENT_LEN
use helpers; use helpers;
use body::{Body, Binary}; use body::{Body, Binary};
use headers::ContentEncoding;
use httprequest::HttpMessage; use httprequest::HttpMessage;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
use super::encoding::PayloadEncoder; use super::encoding::PayloadEncoder;
@ -108,10 +109,11 @@ impl Writer for H2Writer {
self.written self.written
} }
fn start(&mut self, req: &mut HttpMessage, msg: &mut HttpResponse) -> io::Result<WriterState> { fn start(&mut self, req: &mut HttpMessage, msg: &mut HttpResponse, encoding: ContentEncoding)
-> io::Result<WriterState> {
// prepare response // prepare response
self.flags.insert(Flags::STARTED); self.flags.insert(Flags::STARTED);
self.encoder = PayloadEncoder::new(self.buffer.clone(), req, msg); self.encoder = PayloadEncoder::new(self.buffer.clone(), req, msg, encoding);
if let Body::Empty = *msg.body() { if let Body::Empty = *msg.body() {
self.flags.insert(Flags::EOF); self.flags.insert(Flags::EOF);
} }

View File

@ -24,6 +24,7 @@ pub use self::settings::ServerSettings;
use body::Binary; use body::Binary;
use error::Error; use error::Error;
use headers::ContentEncoding;
use httprequest::{HttpMessage, HttpRequest}; use httprequest::{HttpMessage, HttpRequest};
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
@ -102,7 +103,8 @@ pub enum WriterState {
pub trait Writer { pub trait Writer {
fn written(&self) -> u64; fn written(&self) -> u64;
fn start(&mut self, req: &mut HttpMessage, resp: &mut HttpResponse) -> io::Result<WriterState>; fn start(&mut self, req: &mut HttpMessage, resp: &mut HttpResponse, encoding: ContentEncoding)
-> io::Result<WriterState>;
fn write(&mut self, payload: Binary) -> io::Result<WriterState>; fn write(&mut self, payload: Binary) -> io::Result<WriterState>;