mirror of
https://github.com/actix/actix-web.git
synced 2024-11-19 16:11:07 +00:00
allow to set default content encoding on application level
This commit is contained in:
parent
816c6fb0e0
commit
edd114f6e4
11 changed files with 73 additions and 21 deletions
12
CHANGES.md
12
CHANGES.md
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
|
||||||
//!
|
//!
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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) =>
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue