From fbdda8acb191dcaaa02f582ed8fce0b9bb96a51e Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 18 Jul 2019 17:24:12 +0600 Subject: [PATCH] Unix domain sockets (HttpServer::bind_uds) #92 --- CHANGES.md | 5 +++- Cargo.toml | 9 ++++--- actix-multipart/src/server.rs | 11 +++++--- examples/uds.rs | 49 +++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/server.rs | 32 +++++++++++++++++++++++ test-server/CHANGES.md | 4 +++ test-server/Cargo.toml | 4 +-- test-server/src/lib.rs | 3 ++- 9 files changed, 108 insertions(+), 10 deletions(-) create mode 100644 examples/uds.rs diff --git a/CHANGES.md b/CHANGES.md index d64a2239..80abfc59 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,9 +1,11 @@ # Changes -## [1.0.5] - ? +## [1.0.5] - 2019-07-xx ### Added +* Unix domain sockets (HttpServer::bind_uds) #92 + * Actix now logs errors resulting in "internal server error" responses always, with the `error` logging level @@ -11,6 +13,7 @@ * Restored logging of errors through the `Logger` middleware + ## [1.0.4] - 2019-07-17 ### Added diff --git a/Cargo.toml b/Cargo.toml index 866a7628..40817a1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"] edition = "2018" [package.metadata.docs.rs] -features = ["ssl", "brotli", "flate2-zlib", "secure-cookies", "client", "rust-tls"] +features = ["ssl", "brotli", "flate2-zlib", "secure-cookies", "client", "rust-tls", "uds"] [badges] travis-ci = { repository = "actix/actix-web", branch = "master" } @@ -68,6 +68,9 @@ ssl = ["openssl", "actix-server/ssl", "awc/ssl"] # rustls rust-tls = ["rustls", "actix-server/rust-tls"] +# unix domain sockets support +uds = ["actix-server/uds"] + [dependencies] actix-codec = "0.1.2" actix-service = "0.4.1" @@ -76,8 +79,8 @@ actix-router = "0.1.5" actix-rt = "0.2.4" actix-web-codegen = "0.1.2" actix-http = "0.2.6" -actix-server = "0.5.1" -actix-server-config = "0.1.1" +actix-server = "0.6.0" +actix-server-config = "0.1.2" actix-threadpool = "0.1.1" awc = { version = "0.2.1", optional = true } diff --git a/actix-multipart/src/server.rs b/actix-multipart/src/server.rs index 70eb61cb..e2111bb7 100644 --- a/actix-multipart/src/server.rs +++ b/actix-multipart/src/server.rs @@ -286,7 +286,10 @@ impl InnerMultipart { } // read boundary InnerState::Boundary => { - match InnerMultipart::read_boundary(&mut *payload, &self.boundary)? { + match InnerMultipart::read_boundary( + &mut *payload, + &self.boundary, + )? { None => return Ok(Async::NotReady), Some(eof) => { if eof { @@ -411,7 +414,8 @@ impl Stream for Field { fn poll(&mut self) -> Poll, Self::Error> { if self.safety.current() { let mut inner = self.inner.borrow_mut(); - if let Some(mut payload) = inner.payload.as_ref().unwrap().get_mut(&self.safety) + if let Some(mut payload) = + inner.payload.as_ref().unwrap().get_mut(&self.safety) { payload.poll_stream()?; } @@ -582,7 +586,8 @@ impl InnerField { return Ok(Async::Ready(None)); } - let result = if let Some(mut payload) = self.payload.as_ref().unwrap().get_mut(s) { + let result = if let Some(mut payload) = self.payload.as_ref().unwrap().get_mut(s) + { if !self.eof { let res = if let Some(ref mut len) = self.length { InnerField::read_len(&mut *payload, len)? diff --git a/examples/uds.rs b/examples/uds.rs new file mode 100644 index 00000000..4d6eca40 --- /dev/null +++ b/examples/uds.rs @@ -0,0 +1,49 @@ +use futures::IntoFuture; + +use actix_web::{ + get, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, +}; + +#[get("/resource1/{name}/index.html")] +fn index(req: HttpRequest, name: web::Path) -> String { + println!("REQ: {:?}", req); + format!("Hello: {}!\r\n", name) +} + +fn index_async(req: HttpRequest) -> impl IntoFuture { + println!("REQ: {:?}", req); + Ok("Hello world!\r\n") +} + +#[get("/")] +fn no_params() -> &'static str { + "Hello world!\r\n" +} + +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info"); + env_logger::init(); + + HttpServer::new(|| { + App::new() + .wrap(middleware::DefaultHeaders::new().header("X-Version", "0.2")) + .wrap(middleware::Compress::default()) + .wrap(middleware::Logger::default()) + .service(index) + .service(no_params) + .service( + web::resource("/resource2/index.html") + .wrap( + middleware::DefaultHeaders::new().header("X-Version-R2", "0.3"), + ) + .default_service( + web::route().to(|| HttpResponse::MethodNotAllowed()), + ) + .route(web::get().to_async(index_async)), + ) + .service(web::resource("/test1.html").to(|| "Test\r\n")) + }) + .bind_uds("/Users/fafhrd91/uds-test")? + .workers(1) + .run() +} diff --git a/src/lib.rs b/src/lib.rs index 857bc294..c7cdf147 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,6 +78,7 @@ //! `c` compiler (default enabled) //! * `flate2-rust` - experimental rust based implementation for //! `gzip`, `deflate` compression. +//! * `uds` - Unix domain support, enables `HttpServer::bind_uds()` method. //! #![allow(clippy::type_complexity, clippy::new_without_default)] diff --git a/src/server.rs b/src/server.rs index 43236fa3..aa654e57 100644 --- a/src/server.rs +++ b/src/server.rs @@ -434,6 +434,38 @@ where } Ok(self) } + + #[cfg(feature = "uds")] + /// Start listening for incoming unix domain connections. + /// + /// This method is available with `uds` feature. + pub fn bind_uds(mut self, addr: A) -> io::Result + where + A: AsRef, + { + let cfg = self.config.clone(); + let factory = self.factory.clone(); + self.sockets.push(Socket { + scheme: "http", + addr: net::SocketAddr::new( + net::IpAddr::V4(net::Ipv4Addr::new(127, 0, 0, 1)), + 8080, + ), + }); + + self.builder = self.builder.bind_uds( + format!("actix-web-service-{:?}", addr.as_ref()), + addr, + move || { + let c = cfg.lock(); + HttpService::build() + .keep_alive(c.keep_alive) + .client_timeout(c.client_timeout) + .finish(factory()) + }, + )?; + Ok(self) + } } impl HttpServer diff --git a/test-server/CHANGES.md b/test-server/CHANGES.md index f3e98010..33314421 100644 --- a/test-server/CHANGES.md +++ b/test-server/CHANGES.md @@ -1,5 +1,9 @@ # Changes +## [0.2.4] - 2019-07-18 + +* Update actix-server to 0.6 + ## [0.2.3] - 2019-07-16 * Add `delete`, `options`, `patch` methods to `TestServerRunner` diff --git a/test-server/Cargo.toml b/test-server/Cargo.toml index 445ed33e..512f65e1 100644 --- a/test-server/Cargo.toml +++ b/test-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-http-test" -version = "0.2.3" +version = "0.2.4" authors = ["Nikolay Kim "] description = "Actix http test server" readme = "README.md" @@ -33,7 +33,7 @@ ssl = ["openssl", "actix-server/ssl", "awc/ssl"] actix-codec = "0.1.2" actix-rt = "0.2.2" actix-service = "0.4.1" -actix-server = "0.5.1" +actix-server = "0.6.0" actix-utils = "0.4.1" awc = "0.2.2" diff --git a/test-server/src/lib.rs b/test-server/src/lib.rs index 38405cd5..ce73e181 100644 --- a/test-server/src/lib.rs +++ b/test-server/src/lib.rs @@ -12,6 +12,7 @@ use futures::future::lazy; use futures::{Future, IntoFuture, Stream}; use http::Method; use net2::TcpBuilder; +use tokio_tcp::TcpStream; thread_local! { static RT: RefCell = { @@ -109,7 +110,7 @@ pub struct TestServerRuntime { impl TestServer { #[allow(clippy::new_ret_no_self)] /// Start new test server with application factory - pub fn new(factory: F) -> TestServerRuntime { + pub fn new>(factory: F) -> TestServerRuntime { let (tx, rx) = mpsc::channel(); // run server in separate thread