1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-11-26 19:41:12 +00:00

cleanup and optimize some code

This commit is contained in:
Nikolay Kim 2017-12-12 21:32:58 -08:00
parent ab6efd2421
commit 2e83c5924d
9 changed files with 148 additions and 68 deletions

View file

@ -13,9 +13,11 @@ use futures::future::{FutureResult, result};
/// simple handler
fn index(mut req: HttpRequest) -> Result<HttpResponse> {
println!("{:?}", req);
if let Ok(ch) = req.payload_mut().readany() {
if let futures::Async::Ready(Some(d)) = ch {
println!("{}", String::from_utf8_lossy(d.0.as_ref()));
if let Some(payload) = req.payload_mut() {
if let Ok(ch) = payload.readany() {
if let futures::Async::Ready(Some(d)) = ch {
println!("{}", String::from_utf8_lossy(d.0.as_ref()));
}
}
}

View file

@ -402,14 +402,14 @@ impl PayloadEncoder {
resp.headers_mut().insert(
CONTENT_LENGTH,
HeaderValue::from_str(format!("{}", b.len()).as_str()).unwrap());
HeaderValue::from_str(&b.len().to_string()).unwrap());
*bytes = Binary::from(b);
encoding = ContentEncoding::Identity;
TransferEncoding::eof()
} else {
resp.headers_mut().insert(
CONTENT_LENGTH,
HeaderValue::from_str(format!("{}", bytes.len()).as_str()).unwrap());
HeaderValue::from_str(&bytes.len().to_string()).unwrap());
resp.headers_mut().remove(TRANSFER_ENCODING);
TransferEncoding::length(bytes.len() as u64)
}
@ -478,22 +478,27 @@ impl PayloadEncoder {
impl PayloadEncoder {
#[inline]
pub fn len(&self) -> usize {
self.0.get_ref().len()
}
#[inline]
pub fn get_mut(&mut self) -> &mut BytesMut {
self.0.get_mut()
}
#[inline]
pub fn is_eof(&self) -> bool {
self.0.is_eof()
}
#[inline]
pub fn write(&mut self, payload: &[u8]) -> Result<(), io::Error> {
self.0.write(payload)
}
#[inline]
pub fn write_eof(&mut self) -> Result<(), io::Error> {
self.0.write_eof()
}
@ -508,6 +513,7 @@ enum ContentEncoder {
impl ContentEncoder {
#[inline]
pub fn is_eof(&self) -> bool {
match *self {
ContentEncoder::Br(ref encoder) =>
@ -521,6 +527,7 @@ impl ContentEncoder {
}
}
#[inline]
pub fn get_ref(&self) -> &BytesMut {
match *self {
ContentEncoder::Br(ref encoder) =>
@ -534,6 +541,7 @@ impl ContentEncoder {
}
}
#[inline]
pub fn get_mut(&mut self) -> &mut BytesMut {
match *self {
ContentEncoder::Br(ref mut encoder) =>
@ -547,6 +555,7 @@ impl ContentEncoder {
}
}
#[inline]
pub fn write_eof(&mut self) -> Result<(), io::Error> {
let encoder = mem::replace(self, ContentEncoder::Identity(TransferEncoding::eof()));
@ -555,7 +564,6 @@ impl ContentEncoder {
match encoder.finish() {
Ok(mut writer) => {
writer.encode_eof();
*self = ContentEncoder::Identity(writer);
Ok(())
},
Err(err) => Err(err),
@ -565,7 +573,6 @@ impl ContentEncoder {
match encoder.finish() {
Ok(mut writer) => {
writer.encode_eof();
*self = ContentEncoder::Identity(writer);
Ok(())
},
Err(err) => Err(err),
@ -575,7 +582,6 @@ impl ContentEncoder {
match encoder.finish() {
Ok(mut writer) => {
writer.encode_eof();
*self = ContentEncoder::Identity(writer);
Ok(())
},
Err(err) => Err(err),
@ -583,19 +589,18 @@ impl ContentEncoder {
},
ContentEncoder::Identity(mut writer) => {
writer.encode_eof();
*self = ContentEncoder::Identity(writer);
Ok(())
}
}
}
#[inline]
pub fn write(&mut self, data: &[u8]) -> Result<(), io::Error> {
match *self {
ContentEncoder::Br(ref mut encoder) => {
match encoder.write(data) {
Ok(_) => {
encoder.flush()
},
Ok(_) =>
encoder.flush(),
Err(err) => {
trace!("Error decoding br encoding: {}", err);
Err(err)
@ -604,20 +609,18 @@ impl ContentEncoder {
},
ContentEncoder::Gzip(ref mut encoder) => {
match encoder.write(data) {
Ok(_) => {
encoder.flush()
},
Ok(_) =>
encoder.flush(),
Err(err) => {
trace!("Error decoding br encoding: {}", err);
trace!("Error decoding gzip encoding: {}", err);
Err(err)
},
}
}
ContentEncoder::Deflate(ref mut encoder) => {
match encoder.write(data) {
Ok(_) => {
encoder.flush()
},
Ok(_) =>
encoder.flush(),
Err(err) => {
trace!("Error decoding deflate encoding: {}", err);
Err(err)
@ -655,6 +658,7 @@ enum TransferEncodingKind {
impl TransferEncoding {
#[inline]
pub fn eof() -> TransferEncoding {
TransferEncoding {
kind: TransferEncodingKind::Eof,
@ -662,6 +666,7 @@ impl TransferEncoding {
}
}
#[inline]
pub fn chunked() -> TransferEncoding {
TransferEncoding {
kind: TransferEncodingKind::Chunked(false),
@ -669,6 +674,7 @@ impl TransferEncoding {
}
}
#[inline]
pub fn length(len: u64) -> TransferEncoding {
TransferEncoding {
kind: TransferEncodingKind::Length(len),
@ -676,6 +682,7 @@ impl TransferEncoding {
}
}
#[inline]
pub fn is_eof(&self) -> bool {
match self.kind {
TransferEncodingKind::Eof => true,
@ -687,6 +694,7 @@ impl TransferEncoding {
}
/// Encode message. Return `EOF` state of encoder
#[inline]
pub fn encode(&mut self, msg: &[u8]) -> bool {
match self.kind {
TransferEncodingKind::Eof => {
@ -724,6 +732,7 @@ impl TransferEncoding {
}
/// Encode eof. Return `EOF` state of encoder
#[inline]
pub fn encode_eof(&mut self) {
match self.kind {
TransferEncodingKind::Eof | TransferEncodingKind::Length(_) => (),
@ -739,11 +748,13 @@ impl TransferEncoding {
impl io::Write for TransferEncoding {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.encode(buf);
Ok(buf.len())
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}

View file

@ -262,6 +262,9 @@ pub enum MultipartError {
/// Multipart boundary is not found
#[fail(display="Multipart boundary is not found")]
Boundary,
/// Request does not contain payload
#[fail(display="Request does not contain payload")]
NoPayload,
/// Error during field parsing
#[fail(display="{}", _0)]
Parse(#[cause] ParseError),
@ -329,6 +332,9 @@ pub enum WsHandshakeError {
/// Websocket key is not set or wrong
#[fail(display="Unknown websocket key")]
BadWebsocketKey,
/// Request does not contain payload
#[fail(display="Request does not contain payload")]
NoPayload,
}
impl ResponseError for WsHandshakeError {
@ -351,7 +357,9 @@ impl ResponseError for WsHandshakeError {
WsHandshakeError::UnsupportedVersion =>
HTTPBadRequest.with_reason("Unsupported version"),
WsHandshakeError::BadWebsocketKey =>
HTTPBadRequest.with_reason("Handshake error")
HTTPBadRequest.with_reason("Handshake error"),
WsHandshakeError::NoPayload =>
HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR, Body::Empty),
}
}
}
@ -371,6 +379,9 @@ pub enum UrlencodedError {
/// Content type error
#[fail(display="Content type error")]
ContentType,
/// Request does not contain payload
#[fail(display="Request does not contain payload")]
NoPayload,
}
/// Return `BadRequest` for `UrlencodedError`

View file

@ -545,28 +545,25 @@ impl Reader {
}
}
let (mut psender, payload) = Payload::new(false);
let msg = HttpRequest::new(method, uri, version, headers, payload);
let decoder = if msg.upgrade() {
let decoder = if upgrade(&method, &headers) {
Decoder::eof()
} else {
let has_len = msg.headers().contains_key(header::CONTENT_LENGTH);
let has_len = headers.contains_key(header::CONTENT_LENGTH);
// Chunked encoding
if msg.chunked()? {
if chunked(&headers)? {
if has_len {
return Err(ParseError::Header)
}
Decoder::chunked()
} else {
if !has_len {
psender.feed_eof();
let msg = HttpRequest::new(method, uri, version, headers, None);
return Ok(Message::Http1(msg, None))
}
// Content-Length
let len = msg.headers().get(header::CONTENT_LENGTH).unwrap();
let len = headers.get(header::CONTENT_LENGTH).unwrap();
if let Ok(s) = len.to_str() {
if let Ok(len) = s.parse::<u64>() {
Decoder::length(len)
@ -581,11 +578,13 @@ impl Reader {
}
};
let payload = PayloadInfo {
tx: PayloadType::new(msg.headers(), psender),
let (psender, payload) = Payload::new(false);
let info = PayloadInfo {
tx: PayloadType::new(&headers, psender),
decoder: decoder,
};
Ok(Message::Http1(msg, Some(payload)))
let msg = HttpRequest::new(method, uri, version, headers, Some(payload));
Ok(Message::Http1(msg, Some(info)))
}
}
@ -610,6 +609,32 @@ fn record_header_indices(bytes: &[u8],
}
}
/// Check if request is UPGRADE
fn upgrade(method: &Method, headers: &HeaderMap) -> bool {
if let Some(conn) = headers.get(header::CONNECTION) {
if let Ok(s) = conn.to_str() {
s.to_lowercase().contains("upgrade")
} else {
*method == Method::CONNECT
}
} else {
*method == Method::CONNECT
}
}
/// Check if request has chunked transfer encoding
fn chunked(headers: &HeaderMap) -> Result<bool, ParseError> {
if let Some(encodings) = headers.get(header::TRANSFER_ENCODING) {
if let Ok(s) = encodings.to_str() {
Ok(s.to_lowercase().contains("chunked"))
} else {
Err(ParseError::Header)
}
} else {
Ok(false)
}
}
/// Decoders to handle different Transfer-Encodings.
///
/// If a message body does not include a Transfer-Encoding, it *should*

View file

@ -237,7 +237,7 @@ impl Entry {
let (psender, payload) = Payload::new(false);
let mut req = HttpRequest::new(
parts.method, parts.uri, parts.version, parts.headers, payload);
parts.method, parts.uri, parts.version, parts.headers, Some(payload));
// set remote addr
req.set_peer_addr(addr);

View file

@ -58,6 +58,7 @@ pub(crate) enum ReplyItem {
impl Reply {
/// Create actor response
#[inline]
pub fn actor<A, S>(ctx: HttpContext<A, S>) -> Reply
where A: Actor<Context=HttpContext<A, S>>, S: 'static
{
@ -65,6 +66,7 @@ impl Reply {
}
/// Create async response
#[inline]
pub fn async<F>(fut: F) -> Reply
where F: Future<Item=HttpResponse, Error=Error> + 'static
{
@ -72,10 +74,12 @@ impl Reply {
}
/// Send response
#[inline]
pub fn response<R: Into<HttpResponse>>(response: R) -> Reply {
Reply(ReplyItem::Message(response.into()))
}
#[inline]
pub(crate) fn into(self) -> ReplyItem {
self.0
}

View file

@ -28,7 +28,7 @@ pub struct HttpMessage {
pub params: Params<'static>,
pub cookies: Option<Vec<Cookie<'static>>>,
pub addr: Option<SocketAddr>,
pub payload: Payload,
pub payload: Option<Payload>,
pub info: Option<ConnectionInfo<'static>>,
}
@ -43,7 +43,7 @@ impl Default for HttpMessage {
params: Params::default(),
cookies: None,
addr: None,
payload: Payload::empty(),
payload: None,
extensions: Extensions::new(),
info: None,
}
@ -72,13 +72,13 @@ impl HttpMessage {
}
/// An HTTP Request
pub struct HttpRequest<S=()>(Rc<HttpMessage>, Rc<S>, Option<Router<S>>);
pub struct HttpRequest<S=()>(Rc<HttpMessage>, Option<Rc<S>>, Option<Router<S>>);
impl HttpRequest<()> {
/// Construct a new Request.
#[inline]
pub fn new(method: Method, uri: Uri,
version: Version, headers: HeaderMap, payload: Payload) -> HttpRequest
version: Version, headers: HeaderMap, payload: Option<Payload>) -> HttpRequest
{
HttpRequest(
Rc::new(HttpMessage {
@ -93,7 +93,7 @@ impl HttpRequest<()> {
extensions: Extensions::new(),
info: None,
}),
Rc::new(()),
None,
None,
)
}
@ -118,14 +118,14 @@ impl HttpRequest<()> {
extensions: Extensions::new(),
info: None,
}),
Rc::new(()),
None,
None,
)
}
/// Construct new http request with state.
pub fn with_state<S>(self, state: Rc<S>, router: Router<S>) -> HttpRequest<S> {
HttpRequest(self.0, state, Some(router))
HttpRequest(self.0, Some(state), Some(router))
}
}
@ -133,7 +133,7 @@ impl<S> HttpRequest<S> {
/// Construct new http request without state.
pub fn clone_without_state(&self) -> HttpRequest {
HttpRequest(Rc::clone(&self.0), Rc::new(()), None)
HttpRequest(Rc::clone(&self.0), None, None)
}
// get mutable reference for inner message
@ -153,7 +153,7 @@ impl<S> HttpRequest<S> {
/// Shared application state
#[inline]
pub fn state(&self) -> &S {
&self.1
self.1.as_ref().unwrap()
}
/// Protocol extensions.
@ -377,20 +377,20 @@ impl<S> HttpRequest<S> {
/// Returns reference to the associated http payload.
#[inline]
pub fn payload(&self) -> &Payload {
&self.0.payload
pub fn payload(&self) -> Option<&Payload> {
self.0.payload.as_ref()
}
/// Returns mutable reference to the associated http payload.
#[inline]
pub fn payload_mut(&mut self) -> &mut Payload {
&mut self.as_mut().payload
pub fn payload_mut(&mut self) -> Option<&mut Payload> {
self.as_mut().payload.as_mut()
}
/// Return payload
#[inline]
pub fn take_payload(&mut self) -> Payload {
mem::replace(&mut self.as_mut().payload, Payload::empty())
pub fn take_payload(&mut self) -> Option<Payload> {
self.as_mut().payload.take()
}
/// Return stream to process BODY as multipart.
@ -398,7 +398,11 @@ impl<S> HttpRequest<S> {
/// Content-type: multipart/form-data;
pub fn multipart(&mut self) -> Result<Multipart, MultipartError> {
let boundary = Multipart::boundary(&self.0.headers)?;
Ok(Multipart::new(boundary, self.take_payload()))
if let Some(payload) = self.take_payload() {
Ok(Multipart::new(boundary, payload))
} else {
Err(MultipartError::NoPayload)
}
}
/// Parse `application/x-www-form-urlencoded` encoded body.
@ -441,7 +445,11 @@ impl<S> HttpRequest<S> {
};
if t {
Ok(UrlEncoded{pl: self.take_payload(), body: BytesMut::new()})
if let Some(payload) = self.take_payload() {
Ok(UrlEncoded{pl: payload, body: BytesMut::new()})
} else {
Err(UrlencodedError::NoPayload)
}
} else {
Err(UrlencodedError::ContentType)
}
@ -452,13 +460,13 @@ impl Default for HttpRequest<()> {
/// Construct default request
fn default() -> HttpRequest {
HttpRequest(Rc::new(HttpMessage::default()), Rc::new(()), None)
HttpRequest(Rc::new(HttpMessage::default()), None, None)
}
}
impl<S> Clone for HttpRequest<S> {
fn clone(&self) -> HttpRequest<S> {
HttpRequest(Rc::clone(&self.0), Rc::clone(&self.1), None)
HttpRequest(Rc::clone(&self.0), self.1.clone(), None)
}
}

View file

@ -222,20 +222,20 @@ struct Parts {
chunked: bool,
encoding: ContentEncoding,
connection_type: Option<ConnectionType>,
cookies: CookieJar,
cookies: Option<CookieJar>,
}
impl Parts {
fn new(status: StatusCode) -> Self {
Parts {
version: None,
headers: HeaderMap::new(),
headers: HeaderMap::with_capacity(8),
status: status,
reason: None,
chunked: false,
encoding: ContentEncoding::Auto,
connection_type: None,
cookies: CookieJar::new(),
cookies: None,
}
}
}
@ -359,7 +359,13 @@ impl HttpResponseBuilder {
/// Set a cookie
pub fn cookie<'c>(&mut self, cookie: Cookie<'c>) -> &mut Self {
if let Some(parts) = parts(&mut self.parts, &self.err) {
parts.cookies.add(cookie.into_owned());
if parts.cookies.is_none() {
let mut jar = CookieJar::new();
jar.add(cookie.into_owned());
parts.cookies = Some(jar)
} else {
parts.cookies.as_mut().unwrap().add(cookie.into_owned());
}
}
self
}
@ -367,9 +373,13 @@ impl HttpResponseBuilder {
/// Remote cookie, cookie has to be cookie from `HttpRequest::cookies()` method.
pub fn del_cookie<'a>(&mut self, cookie: &Cookie<'a>) -> &mut Self {
if let Some(parts) = parts(&mut self.parts, &self.err) {
if parts.cookies.is_none() {
parts.cookies = Some(CookieJar::new())
}
let mut jar = parts.cookies.as_mut().unwrap();
let cookie = cookie.clone().into_owned();
parts.cookies.add_original(cookie.clone());
parts.cookies.remove(cookie);
jar.add_original(cookie.clone());
jar.remove(cookie);
}
self
}
@ -391,10 +401,12 @@ impl HttpResponseBuilder {
if let Some(e) = self.err.take() {
return Err(e)
}
for cookie in parts.cookies.delta() {
parts.headers.append(
header::SET_COOKIE,
HeaderValue::from_str(&cookie.to_string())?);
if let Some(jar) = parts.cookies {
for cookie in jar.delta() {
parts.headers.append(
header::SET_COOKIE,
HeaderValue::from_str(&cookie.to_string())?);
}
}
Ok(HttpResponse {
version: parts.version,

View file

@ -96,11 +96,15 @@ pub fn start<A, S>(mut req: HttpRequest<S>, actor: A) -> Result<Reply, Error>
{
let resp = handshake(&req)?;
let stream = WsStream::new(&mut req);
let mut ctx = HttpContext::new(req, actor);
ctx.start(resp);
ctx.add_stream(stream);
Ok(ctx.into())
if let Some(payload) = req.take_payload() {
let stream = WsStream::new(payload);
let mut ctx = HttpContext::new(req, actor);
ctx.start(resp);
ctx.add_stream(stream);
Ok(ctx.into())
} else {
Err(WsHandshakeError::NoPayload.into())
}
}
/// Prepare `WebSocket` handshake response.
@ -178,8 +182,11 @@ pub struct WsStream {
}
impl WsStream {
pub fn new<S>(req: &mut HttpRequest<S>) -> WsStream {
WsStream { rx: req.take_payload(), buf: BytesMut::new(), closed: false, error_sent: false }
pub fn new(payload: Payload) -> WsStream {
WsStream { rx: payload,
buf: BytesMut::new(),
closed: false,
error_sent: false }
}
}