From 129361909642cadc9e88537ba4615a7570ec4041 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Fri, 8 Dec 2017 09:24:05 -0800 Subject: [PATCH] set server settings to HttpHandler --- src/channel.rs | 19 ++++--- src/h1.rs | 22 +++----- src/h2.rs | 17 +++--- src/httprequest.rs | 3 +- src/server.rs | 132 ++++++++++++++++++++++----------------------- 5 files changed, 92 insertions(+), 101 deletions(-) diff --git a/src/channel.rs b/src/channel.rs index e266d4d48..c649d8c46 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -1,3 +1,4 @@ +use std::rc::Rc; use std::net::SocketAddr; use actix::dev::*; @@ -12,9 +13,13 @@ use httprequest::HttpRequest; use server::ServerSettings; /// Low level http request handler +#[allow(unused_variables)] pub trait HttpHandler: 'static { /// Handle request fn handle(&self, req: HttpRequest) -> Result; + + /// Set server settings + fn server_settings(&mut self, settings: ServerSettings) {} } /// Conversion helper trait @@ -51,17 +56,16 @@ pub struct HttpChannel impl HttpChannel where T: AsyncRead + AsyncWrite + 'static, H: HttpHandler + 'static { - pub fn new(settings: ServerSettings, - stream: T, peer: Option, http2: bool) -> HttpChannel + pub fn new(h: Rc>, io: T, peer: Option, http2: bool) -> HttpChannel { if http2 { HttpChannel { proto: Some(HttpProtocol::H2( - h2::Http2::new(settings, stream, peer, Bytes::new()))) } + h2::Http2::new(h, io, peer, Bytes::new()))) } } else { HttpChannel { proto: Some(HttpProtocol::H1( - h1::Http1::new(settings, stream, peer))) } + h1::Http1::new(h, io, peer))) } } } } @@ -97,8 +101,7 @@ impl Future for HttpChannel return Err(()), } } - Some(HttpProtocol::H2(ref mut h2)) => - return h2.poll(), + Some(HttpProtocol::H2(ref mut h2)) => return h2.poll(), None => unreachable!(), } @@ -106,9 +109,9 @@ impl Future for HttpChannel let proto = self.proto.take().unwrap(); match proto { HttpProtocol::H1(h1) => { - let (settings, stream, addr, buf) = h1.into_inner(); + let (h, io, addr, buf) = h1.into_inner(); self.proto = Some( - HttpProtocol::H2(h2::Http2::new(settings, stream, addr, buf))); + HttpProtocol::H2(h2::Http2::new(h, io, addr, buf))); self.poll() } _ => unreachable!() diff --git a/src/h1.rs b/src/h1.rs index cebdfa190..9b4587d87 100644 --- a/src/h1.rs +++ b/src/h1.rs @@ -1,4 +1,5 @@ use std::{self, io, ptr}; +use std::rc::Rc; use std::net::SocketAddr; use std::time::Duration; use std::collections::VecDeque; @@ -20,7 +21,6 @@ use httpcodes::HTTPNotFound; use httprequest::HttpRequest; use error::{ParseError, PayloadError, ResponseError}; use payload::{Payload, PayloadWriter, DEFAULT_BUFFER_SIZE}; -use server::ServerSettings; const KEEPALIVE_PERIOD: u64 = 15; // seconds const INIT_BUFFER_SIZE: usize = 8192; @@ -31,7 +31,6 @@ const HTTP2_PREFACE: [u8; 14] = *b"PRI * HTTP/2.0"; bitflags! { struct Flags: u8 { - const SECURE = 0b0000_0001; const ERROR = 0b0000_0010; const KEEPALIVE = 0b0000_0100; const H2 = 0b0000_1000; @@ -60,7 +59,7 @@ enum Item { pub(crate) struct Http1 { flags: Flags, - settings: ServerSettings, + handlers: Rc>, addr: Option, stream: H1Writer, reader: Reader, @@ -78,14 +77,9 @@ impl Http1 where T: AsyncRead + AsyncWrite + 'static, H: HttpHandler + 'static { - pub fn new(settings: ServerSettings, stream: T, addr: Option) -> Self { - let flags = if settings.secure() { - Flags::SECURE | Flags::KEEPALIVE - } else { - Flags::KEEPALIVE - }; - Http1{ flags: flags, - settings: settings, + pub fn new(h: Rc>, stream: T, addr: Option) -> Self { + Http1{ flags: Flags::KEEPALIVE, + handlers: h, addr: addr, stream: H1Writer::new(stream), reader: Reader::new(), @@ -94,8 +88,8 @@ impl Http1 keepalive_timer: None } } - pub fn into_inner(mut self) -> (ServerSettings, T, Option, Bytes) { - (self.settings, self.stream.unwrap(), self.addr, self.read_buf.freeze()) + pub fn into_inner(mut self) -> (Rc>, T, Option, Bytes) { + (self.handlers, self.stream.unwrap(), self.addr, self.read_buf.freeze()) } pub fn poll(&mut self) -> Poll { @@ -204,7 +198,7 @@ impl Http1 // start request processing let mut pipe = None; - for h in self.settings.handlers() { + for h in self.handlers.iter() { req = match h.handle(req) { Ok(t) => { pipe = Some(t); diff --git a/src/h2.rs b/src/h2.rs index 5a77e1943..264fb4629 100644 --- a/src/h2.rs +++ b/src/h2.rs @@ -1,4 +1,5 @@ use std::{io, cmp, mem}; +use std::rc::Rc; use std::io::{Read, Write}; use std::time::Duration; use std::net::SocketAddr; @@ -21,13 +22,11 @@ use encoding::PayloadType; use httpcodes::HTTPNotFound; use httprequest::HttpRequest; use payload::{Payload, PayloadWriter}; -use server::ServerSettings; const KEEPALIVE_PERIOD: u64 = 15; // seconds bitflags! { struct Flags: u8 { - const SECURE = 0b0000_0001; const DISCONNECTED = 0b0000_0010; } } @@ -37,7 +36,7 @@ pub(crate) struct Http2 where T: AsyncRead + AsyncWrite + 'static, H: 'static { flags: Flags, - settings: ServerSettings, + handlers: Rc>, addr: Option, state: State>, tasks: VecDeque, @@ -54,10 +53,10 @@ impl Http2 where T: AsyncRead + AsyncWrite + 'static, H: HttpHandler + 'static { - pub fn new(settings: ServerSettings, stream: T, addr: Option, buf: Bytes) -> Self + pub fn new(h: Rc>, stream: T, addr: Option, buf: Bytes) -> Self { - Http2{ flags: if settings.secure() { Flags::SECURE } else { Flags::empty() }, - settings: settings, + Http2{ flags: Flags::empty(), + handlers: h, addr: addr, tasks: VecDeque::new(), state: State::Handshake( @@ -152,7 +151,7 @@ impl Http2 self.keepalive_timer.take(); self.tasks.push_back( - Entry::new(parts, body, resp, self.addr, &self.settings)); + Entry::new(parts, body, resp, self.addr, &self.handlers)); } Ok(Async::NotReady) => { // start keep-alive timer @@ -231,7 +230,7 @@ impl Entry { recv: RecvStream, resp: Respond, addr: Option, - settings: &ServerSettings) -> Entry + handlers: &Rc>) -> Entry where H: HttpHandler + 'static { // Payload and Content-Encoding @@ -248,7 +247,7 @@ impl Entry { // start request processing let mut task = None; - for h in settings.handlers() { + for h in handlers.iter() { req = match h.handle(req) { Ok(t) => { task = Some(t); diff --git a/src/httprequest.rs b/src/httprequest.rs index 44e13f875..d6d0f43e4 100644 --- a/src/httprequest.rs +++ b/src/httprequest.rs @@ -142,7 +142,8 @@ impl HttpRequest { &self.0.headers } - #[cfg(test)] + #[doc(hidden)] + #[inline] pub fn headers_mut(&mut self) -> &mut HeaderMap { &mut self.as_mut().headers } diff --git a/src/server.rs b/src/server.rs index 674aca697..8b8656182 100644 --- a/src/server.rs +++ b/src/server.rs @@ -5,6 +5,8 @@ use std::marker::PhantomData; use actix::dev::*; use futures::Stream; +use http::HttpTryFrom; +use http::header::HeaderValue; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_core::net::{TcpListener, TcpStream}; @@ -27,49 +29,41 @@ use tokio_openssl::{SslStream, SslAcceptorExt}; use channel::{HttpChannel, HttpHandler, IntoHttpHandler}; /// Various server settings -pub struct ServerSettings (Rc>); - -struct InnerServerSettings { - h: Vec, +#[derive(Debug, Clone)] +pub struct ServerSettings { addr: Option, secure: bool, - sethost: bool, + host: Option, } -impl Clone for ServerSettings { - fn clone(&self) -> Self { - ServerSettings(Rc::clone(&self.0)) - } -} - -impl ServerSettings { +impl ServerSettings { /// Crate server settings instance - fn new(h: Vec, addr: Option, secure: bool, sethost: bool) -> Self { - ServerSettings( - Rc::new(InnerServerSettings { - h: h, - addr: addr, - secure: secure, - sethost: sethost })) + fn new(addr: Option, secure: bool) -> Self { + let host = if let Some(ref addr) = addr { + HeaderValue::try_from(format!("{}", addr).as_str()).ok() + } else { + None + }; + ServerSettings { + addr: addr, + secure: secure, + host: host, + } } - /// Returns list of http handlers - pub fn handlers(&self) -> &Vec { - &self.0.h - } /// Returns the socket address of the local half of this TCP connection pub fn local_addr(&self) -> Option { - self.0.addr + self.addr } /// Returns true if connection is secure(https) pub fn secure(&self) -> bool { - self.0.secure + self.secure } - /// Should http channel set *HOST* header - pub fn set_host_header(&self) -> bool { - self.0.sethost + /// Returns host header value + pub fn host(&self) -> Option<&HeaderValue> { + self.host.as_ref() } } @@ -81,10 +75,9 @@ impl ServerSettings { /// /// `H` - request handler pub struct HttpServer { - h: Option>, + h: Rc>, io: PhantomData, addr: PhantomData, - sethost: bool, } impl Actor for HttpServer { @@ -99,16 +92,9 @@ impl HttpServer where H: HttpHandler { let apps: Vec<_> = handler.into_iter().map(|h| h.into_handler()).collect(); - HttpServer {h: Some(apps), + HttpServer{ h: Rc::new(apps), io: PhantomData, - addr: PhantomData, - sethost: false} - } - - /// Set *HOST* header if not set - pub fn set_host_header(mut self) -> Self { - self.sethost = true; - self + addr: PhantomData } } } @@ -122,14 +108,17 @@ impl HttpServer where Self: ActorAddress, S: Stream + 'static { + // set server settings let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap(); - let settings = ServerSettings::new( - self.h.take().unwrap(), Some(addr), secure, self.sethost); + let settings = ServerSettings::new(Some(addr), secure); + for h in Rc::get_mut(&mut self.h).unwrap().iter_mut() { + h.server_settings(settings.clone()); + } + // start server Ok(HttpServer::create(move |ctx| { ctx.add_stream(stream.map( - move |(t, _)| IoStream{settings: settings.clone(), - io: t, peer: None, http2: false})); + move |(t, _)| IoStream{io: t, peer: None, http2: false})); self })) } @@ -170,16 +159,20 @@ impl HttpServer { S: net::ToSocketAddrs, { let addrs = self.bind(addr)?; - let settings = ServerSettings::new( - self.h.take().unwrap(), Some(addrs[0].0), false, self.sethost); + // set server settings + let settings = ServerSettings::new(Some(addrs[0].0), false); + for h in Rc::get_mut(&mut self.h).unwrap().iter_mut() { + h.server_settings(settings.clone()); + } + + // start server Ok(HttpServer::create(move |ctx| { for (addr, tcp) in addrs { info!("Starting http server on {}", addr); - let s = settings.clone(); + ctx.add_stream(tcp.incoming().map( - move |(t, a)| IoStream{settings: s.clone(), - io: t, peer: Some(a), http2: false})); + move |(t, a)| IoStream{io: t, peer: Some(a), http2: false})); } self })) @@ -198,8 +191,12 @@ impl HttpServer, net::SocketAddr, H> { S: net::ToSocketAddrs, { let addrs = self.bind(addr)?; - let settings = ServerSettings::new( - self.h.take().unwrap(), Some(addrs[0].0.clone()), true, self.sethost); + + // set server settings + let settings = ServerSettings::new(Some(addrs[0].0), true); + for h in Rc::get_mut(&mut self.h).unwrap().iter_mut() { + h.server_settings(settings.clone()); + } let acceptor = match TlsAcceptor::builder(pkcs12) { Ok(builder) => { @@ -211,18 +208,15 @@ impl HttpServer, net::SocketAddr, H> { Err(err) => return Err(io::Error::new(io::ErrorKind::Other, err)) }; + // start server Ok(HttpServer::create(move |ctx| { for (srv, tcp) in addrs { info!("Starting tls http server on {}", srv); - let st = settings.clone(); let acc = acceptor.clone(); ctx.add_stream(tcp.incoming().and_then(move |(stream, addr)| { - let st2 = st.clone(); TlsAcceptorExt::accept_async(acc.as_ref(), stream) - .map(move |t| - IoStream{settings: st2.clone(), - io: t, peer: Some(addr), http2: false}) + .map(move |t| IoStream{io: t, peer: Some(addr), http2: false}) .map_err(|err| { trace!("Error during handling tls connection: {}", err); io::Error::new(io::ErrorKind::Other, err) @@ -246,8 +240,12 @@ impl HttpServer, net::SocketAddr, H> { S: net::ToSocketAddrs, { let addrs = self.bind(addr)?; - let settings = ServerSettings::new( - self.h.take().unwrap(), Some(addrs[0].0.clone()), true, self.sethost); + + // set server settings + let settings = ServerSettings::new(Some(addrs[0].0), true); + for h in Rc::get_mut(&mut self.h).unwrap().iter_mut() { + h.server_settings(settings.clone()); + } let acceptor = match SslAcceptorBuilder::mozilla_intermediate( SslMethod::tls(), &identity.pkey, &identity.cert, &identity.chain) @@ -265,10 +263,8 @@ impl HttpServer, net::SocketAddr, H> { for (srv, tcp) in addrs { info!("Starting tls http server on {}", srv); - let st = settings.clone(); let acc = acceptor.clone(); ctx.add_stream(tcp.incoming().and_then(move |(stream, addr)| { - let st2 = st.clone(); SslAcceptorExt::accept_async(&acc, stream) .map(move |stream| { let http2 = if let Some(p) = @@ -278,8 +274,7 @@ impl HttpServer, net::SocketAddr, H> { } else { false }; - IoStream{settings: st2.clone(), - io: stream, peer: Some(addr), http2: http2} + IoStream{io: stream, peer: Some(addr), http2: http2} }) .map_err(|err| { trace!("Error during handling tls connection: {}", err); @@ -292,26 +287,25 @@ impl HttpServer, net::SocketAddr, H> { } } -struct IoStream { +struct IoStream { io: T, peer: Option, http2: bool, - settings: ServerSettings, } -impl ResponseType for IoStream +impl ResponseType for IoStream where T: AsyncRead + AsyncWrite + 'static { type Item = (); type Error = (); } -impl StreamHandler, io::Error> for HttpServer +impl StreamHandler, io::Error> for HttpServer where T: AsyncRead + AsyncWrite + 'static, H: HttpHandler + 'static, A: 'static {} -impl Handler, io::Error> for HttpServer +impl Handler, io::Error> for HttpServer where T: AsyncRead + AsyncWrite + 'static, H: HttpHandler + 'static, A: 'static, @@ -320,11 +314,11 @@ impl Handler, io::Error> for HttpServer debug!("Error handling request: {}", err) } - fn handle(&mut self, msg: IoStream, _: &mut Context) - -> Response> + fn handle(&mut self, msg: IoStream, _: &mut Context) + -> Response> { Arbiter::handle().spawn( - HttpChannel::new(msg.settings, msg.io, msg.peer, msg.http2)); + HttpChannel::new(Rc::clone(&self.h), msg.io, msg.peer, msg.http2)); Self::empty() } }