diff --git a/src/client/connector.rs b/src/client/connector.rs index 694e03bc9..239a00c5e 100644 --- a/src/client/connector.rs +++ b/src/client/connector.rs @@ -292,7 +292,6 @@ impl ClientConnector { /// # extern crate futures; /// # use futures::{future, Future}; /// # use std::io::Write; - /// # use std::process; /// # use actix_web::actix::Actor; /// extern crate openssl; /// use actix_web::{actix, client::ClientConnector, client::Connect}; @@ -337,10 +336,8 @@ impl ClientConnector { /// # #![cfg(feature = "rust-tls")] /// # extern crate actix_web; /// # extern crate futures; - /// # extern crate tokio; /// # use futures::{future, Future}; /// # use std::io::Write; - /// # use std::process; /// # use actix_web::actix::Actor; /// extern crate rustls; /// extern crate webpki_roots; @@ -380,6 +377,42 @@ impl ClientConnector { feature = "tls", not(any(feature = "alpn", feature = "rust-tls")) ))] + /// Create `ClientConnector` actor with custom `SslConnector` instance. + /// + /// By default `ClientConnector` uses very a simple SSL configuration. + /// With `with_connector` method it is possible to use a custom + /// `SslConnector` object. + /// + /// ```rust + /// # #![cfg(feature = "tls")] + /// # extern crate actix_web; + /// # extern crate futures; + /// # use futures::{future, Future}; + /// # use std::io::Write; + /// # use actix_web::actix::Actor; + /// extern crate native_tls; + /// extern crate webpki_roots; + /// use native_tls::TlsConnector; + /// use actix_web::{actix, client::ClientConnector, client::Connect}; + /// + /// fn main() { + /// actix::run(|| { + /// let connector = TlsConnector::new().unwrap(); + /// let conn = ClientConnector::with_connector(connector.into()).start(); + /// + /// conn.send( + /// Connect::new("https://www.rust-lang.org").unwrap()) // <- connect to host + /// .map_err(|_| ()) + /// .and_then(|res| { + /// if let Ok(mut stream) = res { + /// stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); + /// } + /// # actix::System::current().stop(); + /// Ok(()) + /// }) + /// }); + /// } + /// ``` pub fn with_connector(connector: SslConnector) -> ClientConnector { // keep level of indirection for docstrings matching featureflags Self::with_connector_impl(connector) diff --git a/src/server/error.rs b/src/server/error.rs index 5bd0bf83b..d08ccf87f 100644 --- a/src/server/error.rs +++ b/src/server/error.rs @@ -21,7 +21,12 @@ impl HttpHandlerTask for ServerError { bytes.reserve(helpers::STATUS_LINE_BUF_SIZE + 1); helpers::write_status_line(self.0, self.1.as_u16(), bytes); } + // Convert Status Code to Reason. + let reason = self.1.canonical_reason().unwrap_or(""); + io.buffer().extend_from_slice(reason.as_bytes()); + // No response body. io.buffer().extend_from_slice(b"\r\ncontent-length: 0\r\n"); + // date header io.set_date(); Ok(Async::Ready(true)) } diff --git a/tests/test_server.rs b/tests/test_server.rs index c573c4e12..8235be6b6 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -932,6 +932,29 @@ fn test_application() { assert!(response.status().is_success()); } +#[test] +fn test_default_404_handler_response() { + let mut srv = test::TestServer::with_factory(|| { + App::new() + .prefix("/app") + .resource("", |r| r.f(|_| HttpResponse::Ok())) + .resource("/", |r| r.f(|_| HttpResponse::Ok())) + }); + let addr = srv.addr(); + + let mut buf = [0; 24]; + let request = TcpStream::connect(&addr) + .and_then(|sock| { + tokio::io::write_all(sock, "HEAD / HTTP/1.1\r\nHost: localhost\r\n\r\n") + .and_then(|(sock, _)| tokio::io::read_exact(sock, &mut buf)) + .and_then(|(_, buf)| Ok(buf)) + }) + .map_err(|e| panic!("{:?}", e)); + let response = srv.execute(request).unwrap(); + let rep = String::from_utf8_lossy(&response[..]); + assert!(rep.contains("HTTP/1.1 404 Not Found")); +} + #[test] fn test_server_cookies() { use actix_web::http;