From cd3a200a5ed172949d5ca876df976e53ab9b2367 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Mon, 3 Mar 2025 16:20:29 -0500 Subject: [PATCH 1/7] refactor(app/integration): remove inert `NewService` (#3687) elsewhere in our codebase, we follow a pattern that can be called a "new service". this is a `Service` whose response `S` is itself a `Service`. new services are often useful for dealing with particular connection semantics, and provide us a way to model a connection that services many requests. our test server code makes use of a `Svc`, which wraps a reference to a map of uri's and routes. there is an associated `NewSvc` type that does not provide any material benefit. this `NewSvc` type is a `Service<()>` that never exerts backpressure, nor performs any action besides `Arc::clone`ing the map of routes. this commit golfs down `linkerd_app_integration::server::Server`, by directly cloning the routes into a `Svc(_)`, without the need for polling a future or handling an (impossible) error. Signed-off-by: katelyn martin --- linkerd/app/integration/src/server.rs | 28 +++------------------------ 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/linkerd/app/integration/src/server.rs b/linkerd/app/integration/src/server.rs index 79dd31668b..862df37ffe 100644 --- a/linkerd/app/integration/src/server.rs +++ b/linkerd/app/integration/src/server.rs @@ -193,7 +193,7 @@ impl Server { drain.clone(), async move { tracing::info!("support server running"); - let mut new_svc = NewSvc(Arc::new(self.routes)); + let svc = Svc(Arc::new(self.routes)); if let Some(delay) = delay { let _ = listening_tx.take().unwrap().send(()); delay.await; @@ -213,15 +213,10 @@ impl Server { .instrument(span.clone()) .await?; let srv_conn_count = srv_conn_count.clone(); - let svc = new_svc.call(()); + let svc = svc.clone(); let f = async move { tracing::trace!("serving..."); - let svc = svc.await; - tracing::trace!("service acquired"); srv_conn_count.fetch_add(1, Ordering::Release); - let svc = svc.map_err(|e| { - tracing::error!("support/server new_service error: {}", e) - })?; let result = match self.version { Run::Http1 => hyper::server::conn::http1::Builder::new() .serve_connection(sock, svc) @@ -290,7 +285,7 @@ impl std::fmt::Debug for Route { type BoxError = Box; -#[derive(Debug)] +#[derive(Clone, Debug)] struct Svc(Arc>); impl Svc { @@ -326,23 +321,6 @@ impl tower::Service for Svc { } } -#[derive(Debug)] -struct NewSvc(Arc>); - -impl Service<()> for NewSvc { - type Response = Svc; - type Error = ::std::io::Error; - type Future = future::Ready>; - - fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn call(&mut self, _: ()) -> Self::Future { - future::ok(Svc(Arc::clone(&self.0))) - } -} - async fn accept_connection( io: TcpStream, tls: Option>, From a10d1d7ef8240915a6e45f70a5dc3b75afe2525c Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Mon, 3 Mar 2025 16:20:45 -0500 Subject: [PATCH 2/7] refactor(app/integration): call `tcp::server()` directly (#3688) `linkerd_app_integration::tcp` provides a `TcpServer` type that is distinct from the primary `linkerd_app_integration::server::Server` type broadly used in integration tests. this commit makes a small change to reduce indirection, and clarify that this is constructing a different server implementation from a different submodule. this removes `linkerd_app_integration::server::tcp()`, and updates test code to call the `tcp::server()` function that this is masking. Signed-off-by: katelyn martin --- linkerd/app/integration/src/server.rs | 4 ---- linkerd/app/integration/src/tests/identity.rs | 2 +- linkerd/app/integration/src/tests/shutdown.rs | 2 +- .../app/integration/src/tests/telemetry.rs | 2 +- .../app/integration/src/tests/transparency.rs | 24 +++++++++---------- 5 files changed, 15 insertions(+), 19 deletions(-) diff --git a/linkerd/app/integration/src/server.rs b/linkerd/app/integration/src/server.rs index 862df37ffe..82587e09df 100644 --- a/linkerd/app/integration/src/server.rs +++ b/linkerd/app/integration/src/server.rs @@ -27,10 +27,6 @@ pub fn http2_tls(tls: Arc) -> Server { Server::http2_tls(tls) } -pub fn tcp() -> tcp::TcpServer { - tcp::server() -} - pub struct Server { routes: HashMap, version: Run, diff --git a/linkerd/app/integration/src/tests/identity.rs b/linkerd/app/integration/src/tests/identity.rs index 38048bbe79..ec6d07acbf 100644 --- a/linkerd/app/integration/src/tests/identity.rs +++ b/linkerd/app/integration/src/tests/identity.rs @@ -24,7 +24,7 @@ async fn nonblocking_identity_detection() { let msg1 = "custom tcp hello\n"; let msg2 = "custom tcp bye"; - let srv = server::tcp() + let srv = crate::tcp::server() .accept(move |read| { assert_eq!(read, msg1.as_bytes()); msg2 diff --git a/linkerd/app/integration/src/tests/shutdown.rs b/linkerd/app/integration/src/tests/shutdown.rs index e676abcef8..898fe53b57 100644 --- a/linkerd/app/integration/src/tests/shutdown.rs +++ b/linkerd/app/integration/src/tests/shutdown.rs @@ -101,7 +101,7 @@ async fn tcp_waits_for_proxies_to_close() { let msg1 = "custom tcp hello\n"; let msg2 = "custom tcp bye"; - let srv = server::tcp() + let srv = crate::tcp::server() // Trigger a shutdown while TCP stream is busy .accept_fut(move |mut sock| { async move { diff --git a/linkerd/app/integration/src/tests/telemetry.rs b/linkerd/app/integration/src/tests/telemetry.rs index 0f619d1595..b2d89e2a2e 100644 --- a/linkerd/app/integration/src/tests/telemetry.rs +++ b/linkerd/app/integration/src/tests/telemetry.rs @@ -119,7 +119,7 @@ impl TcpFixture { const BYE_MSG: &'static str = "custom tcp bye"; async fn server() -> server::Listening { - server::tcp() + crate::tcp::server() .accept(move |read| { assert_eq!(read, Self::HELLO_MSG.as_bytes()); TcpFixture::BYE_MSG diff --git a/linkerd/app/integration/src/tests/transparency.rs b/linkerd/app/integration/src/tests/transparency.rs index 9bf93b1b4a..5c4adcf4a0 100644 --- a/linkerd/app/integration/src/tests/transparency.rs +++ b/linkerd/app/integration/src/tests/transparency.rs @@ -53,7 +53,7 @@ async fn outbound_tcp() { let msg1 = "custom tcp hello\n"; let msg2 = "custom tcp bye"; - let srv = server::tcp() + let srv = crate::tcp::server() .accept(move |read| { assert_eq!(read, msg1.as_bytes()); msg2 @@ -91,7 +91,7 @@ async fn outbound_tcp_external() { let msg1 = "custom tcp hello\n"; let msg2 = "custom tcp bye"; - let srv = server::tcp() + let srv = crate::tcp::server() .accept(move |read| { assert_eq!(read, msg1.as_bytes()); msg2 @@ -130,7 +130,7 @@ async fn inbound_tcp() { let msg1 = "custom tcp hello\n"; let msg2 = "custom tcp bye"; - let srv = server::tcp() + let srv = crate::tcp::server() .accept(move |read| { assert_eq!(read, msg1.as_bytes()); msg2 @@ -201,7 +201,7 @@ async fn test_inbound_server_speaks_first(env: TestEnv) { let _trace = trace_init(); let (tx, rx) = mpsc::channel(1); - let srv = server::tcp() + let srv = crate::tcp::server() .accept_fut(move |sock| serve_server_first(sock, tx)) .run() .await; @@ -231,7 +231,7 @@ async fn inbound_tcp_server_first_no_discovery() { let _trace = trace_init(); let (tx, rx) = mpsc::channel(1); - let srv = server::tcp() + let srv = crate::tcp::server() .accept_fut(move |sock| serve_server_first(sock, tx)) .run() .await; @@ -303,7 +303,7 @@ async fn outbound_opaque_tcp_server_first() { let _trace = trace_init(); let (tx, rx) = mpsc::channel(1); - let srv = server::tcp() + let srv = crate::tcp::server() .accept_fut(move |sock| serve_server_first(sock, tx)) .run() .await; @@ -383,7 +383,7 @@ async fn tcp_connections_close_if_client_closes() { let (tx, mut rx) = mpsc::channel::<()>(1); - let srv = server::tcp() + let srv = crate::tcp::server() .accept_fut(move |mut sock| { async move { let _tx = tx; @@ -582,7 +582,7 @@ macro_rules! http1_tests { let chatproto_req = "[chatproto-c]{send}: hi all\n"; let chatproto_res = "[chatproto-s]{recv}: welcome!\n"; - let srv = server::tcp() + let srv = crate::tcp::server() .accept_fut(move |mut sock| { async move { // Read upgrade_req... @@ -731,7 +731,7 @@ macro_rules! http1_tests { let tunneled_req = b"{send}: hi all\n"; let tunneled_res = b"{recv}: welcome!\n"; - let srv = server::tcp() + let srv = crate::tcp::server() .accept_fut(move |mut sock| { async move { // Read connect_req... @@ -823,7 +823,7 @@ macro_rules! http1_tests { let tunneled_req = b"{send}: hi all\n"; let tunneled_res = b"{recv}: welcome!\n"; - let srv = server::tcp() + let srv = crate::tcp::server() .accept_fut(move |mut sock| { async move { // Read connect_req... @@ -887,7 +887,7 @@ macro_rules! http1_tests { async fn http11_connect_bad_requests() { let _trace = trace_init(); - let srv = server::tcp() + let srv = crate::tcp::server() .accept(move |_sock| -> Vec { unreachable!("shouldn't get through the proxy"); }) @@ -1210,7 +1210,7 @@ macro_rules! http1_tests { let _trace = trace_init(); // test both http/1.0 and 1.1 - let srv = server::tcp() + let srv = crate::tcp::server() .accept(move |_read| { "\ HTTP/1.0 200 OK\r\n\ From f4eac760f0668f12e76087f311d8cb29fd1fff20 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Mon, 3 Mar 2025 18:38:48 -0500 Subject: [PATCH 3/7] refactor(app/integration): use `linker_app_core::Error` (#3690) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the test server implementation in `linkerd_app_integration` defines an `BoxError` alias. we have a boxed error type in `linkerd_app_core::Error` that achieves the same purpose, that we can use instead. this commit replaces this type alias with a reƫxport of `linkerd_app_core::Error`. see also, #3685, which removed another similar alias. Signed-off-by: katelyn martin --- linkerd/app/integration/src/server.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/linkerd/app/integration/src/server.rs b/linkerd/app/integration/src/server.rs index 82587e09df..1b857b39f9 100644 --- a/linkerd/app/integration/src/server.rs +++ b/linkerd/app/integration/src/server.rs @@ -43,7 +43,7 @@ pub struct Listening { type Request = http::Request; type Response = http::Response; -type RspFuture = Pin> + Send + Sync + 'static>>; +type RspFuture = Pin> + Send + Sync + 'static>>; impl Listening { pub fn connections(&self) -> usize { @@ -126,7 +126,7 @@ impl Server { { self.route_async(path, move |req| { let res = cb(req); - async move { Ok::<_, BoxError>(res) } + async move { Ok::<_, Error>(res) } }) } @@ -136,7 +136,7 @@ impl Server { where F: Fn(Request) -> U + Send + Sync + 'static, U: TryFuture + Send + Sync + 'static, - U::Error: Into + Send + 'static, + U::Error: Into + Send + 'static, { let func = move |req| Box::pin(cb(req).map_err(Into::into)) as RspFuture; self.routes.insert(path.into(), Route(Box::new(func))); @@ -149,7 +149,7 @@ impl Server { let resp = resp.clone(); async move { tokio::time::sleep(latency).await; - Ok::<_, BoxError>( + Ok::<_, Error>( http::Response::builder() .status(200) .body(hyper::Body::from(resp.clone())) @@ -279,8 +279,6 @@ impl std::fmt::Debug for Route { } } -type BoxError = Box; - #[derive(Clone, Debug)] struct Svc(Arc>); @@ -305,7 +303,7 @@ impl Svc { impl tower::Service for Svc { type Response = Response; - type Error = BoxError; + type Error = Error; type Future = RspFuture; fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { From abc8364f392f929b0796c64aa9aea5d858367a47 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Mon, 3 Mar 2025 18:39:03 -0500 Subject: [PATCH 4/7] nit(app/integration): use `OK`, `NOT_FOUND` constants (#3691) these constants exist, and are generally considered a best practice for these situations. this commit replaces numeric literals with named constants. Signed-off-by: katelyn martin --- linkerd/app/integration/src/server.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linkerd/app/integration/src/server.rs b/linkerd/app/integration/src/server.rs index 1b857b39f9..a40e074ac4 100644 --- a/linkerd/app/integration/src/server.rs +++ b/linkerd/app/integration/src/server.rs @@ -151,7 +151,7 @@ impl Server { tokio::time::sleep(latency).await; Ok::<_, Error>( http::Response::builder() - .status(200) + .status(StatusCode::OK) .body(hyper::Body::from(resp.clone())) .unwrap(), ) @@ -265,7 +265,7 @@ impl Route { Route(Box::new(move |_| { Box::pin(future::ok( http::Response::builder() - .status(200) + .status(StatusCode::OK) .body(hyper::Body::from(body.clone())) .unwrap(), )) @@ -292,7 +292,7 @@ impl Svc { None => { tracing::warn!("server 404: {:?}", req.uri().path()); let res = http::Response::builder() - .status(404) + .status(StatusCode::NOT_FOUND) .body(Default::default()) .unwrap(); Box::pin(async move { Ok(res) }) From 84c3b8491e45c58e5937d67a74af43b45f02b82a Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Mon, 3 Mar 2025 18:39:55 -0500 Subject: [PATCH 5/7] nit(app/integration): add/remove whitespace for consistency (#3689) * nit(app/integration): add whitespace for consistency we follow a convention of an empty line between functions. this commit adds an empty line. Signed-off-by: katelyn martin * nit(app/integration): remove whitespace for consistency Signed-off-by: katelyn martin * nit(app/integration): add whitespace for consistency Signed-off-by: katelyn martin --------- Signed-off-by: katelyn martin --- linkerd/app/integration/src/client.rs | 1 + linkerd/app/integration/src/server.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/linkerd/app/integration/src/client.rs b/linkerd/app/integration/src/client.rs index 71f58c61f7..023869d4e3 100644 --- a/linkerd/app/integration/src/client.rs +++ b/linkerd/app/integration/src/client.rs @@ -77,6 +77,7 @@ pub fn http2_tls>(addr: SocketAddr, auth: T, tls: TlsConfig) -> pub fn tcp(addr: SocketAddr) -> tcp::TcpClient { tcp::client(addr) } + pub struct Client { addr: SocketAddr, run: Run, diff --git a/linkerd/app/integration/src/server.rs b/linkerd/app/integration/src/server.rs index a40e074ac4..1b9de085f5 100644 --- a/linkerd/app/integration/src/server.rs +++ b/linkerd/app/integration/src/server.rs @@ -95,6 +95,7 @@ impl Server { tls, } } + fn http1() -> Self { Server::new(Run::Http1, None) } @@ -329,7 +330,6 @@ async fn accept_connection( _running: None, }) } - None => Ok(RunningIo { io: Box::pin(io), abs_form: false, From ce7e6645e32ce353f4fdc5c37d6492a0ac007cc8 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Mon, 3 Mar 2025 18:46:09 -0500 Subject: [PATCH 6/7] refactor(app/integration): remove `Request`, `Response` aliases (#3692) * refactor(app/integration): remove `Request`, `Response` aliases see https://github.com/linkerd/linkerd2/issues/8733. this commit removes two type aliases from our test server implementation. these are each tied to the defunct `hyper::Body` type. since much of this code was originally written (between 2017 and 2020) we've since developed some patterns / idioms elsewhere for dealing with request and response bodies. to help set the stage for tweaks to which interfaces need `hyper::body::Incoming`, which types work with our general default of `BoxBody`, and which can be generic across arbitrary `B`-typed bodies, we remove these aliases and provide the body parameter to `Request` and `Response`. Signed-off-by: katelyn martin * refactor(app/integration): remove `Request`, `Response` aliases see https://github.com/linkerd/linkerd2/issues/8733. this commit removes two type aliases from our test client implementation. these are each tied to the defunct `hyper::Body` type. since much of this code was originally written (between 2017 and 2020) we've since developed some patterns / idioms elsewhere for dealing with request and response bodies. to help set the stage for tweaks to which interfaces need `hyper::body::Incoming`, which types work with our general default of `BoxBody`, and which can be generic across arbitrary `B`-typed bodies, we remove these aliases and provide the body parameter to `Request` and `Response`. Signed-off-by: katelyn martin --------- Signed-off-by: katelyn martin --- linkerd/app/integration/src/client.rs | 24 +++++++++++++++--------- linkerd/app/integration/src/server.rs | 22 +++++++++++----------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/linkerd/app/integration/src/client.rs b/linkerd/app/integration/src/client.rs index 023869d4e3..fbb4370ad3 100644 --- a/linkerd/app/integration/src/client.rs +++ b/linkerd/app/integration/src/client.rs @@ -1,4 +1,5 @@ use super::*; +use http::{Request, Response}; use linkerd_app_core::proxy::http::TracingExecutor; use parking_lot::Mutex; use std::io; @@ -7,9 +8,10 @@ use tokio_rustls::rustls::{self, ClientConfig}; use tracing::info_span; type ClientError = hyper::Error; -type Request = http::Request; -type Response = http::Response; -type Sender = mpsc::UnboundedSender<(Request, oneshot::Sender>)>; +type Sender = mpsc::UnboundedSender<( + Request, + oneshot::Sender, ClientError>>, +)>; #[derive(Clone)] pub struct TlsConfig { @@ -133,11 +135,12 @@ impl Client { pub fn request( &self, builder: http::request::Builder, - ) -> impl Future> + Send + Sync + 'static { + ) -> impl Future, ClientError>> + Send + Sync + 'static + { self.send_req(builder.body(Bytes::new().into()).unwrap()) } - pub async fn request_body(&self, req: Request) -> Response { + pub async fn request_body(&self, req: Request) -> Response { self.send_req(req).await.expect("response") } @@ -156,8 +159,9 @@ impl Client { #[tracing::instrument(skip(self))] pub(crate) fn send_req( &self, - mut req: Request, - ) -> impl Future> + Send + Sync + 'static { + mut req: Request, + ) -> impl Future, ClientError>> + Send + Sync + 'static + { if req.uri().scheme().is_none() { if self.tls.is_some() { *req.uri_mut() = format!("https://{}{}", self.authority, req.uri().path()) @@ -228,8 +232,10 @@ fn run( version: Run, tls: Option, ) -> (Sender, JoinHandle<()>, Running) { - let (tx, rx) = - mpsc::unbounded_channel::<(Request, oneshot::Sender>)>(); + let (tx, rx) = mpsc::unbounded_channel::<( + Request, + oneshot::Sender, ClientError>>, + )>(); let test_name = thread_name(); let absolute_uris = if let Run::Http1 { absolute_uris } = version { diff --git a/linkerd/app/integration/src/server.rs b/linkerd/app/integration/src/server.rs index 1b9de085f5..9b50bdd9e6 100644 --- a/linkerd/app/integration/src/server.rs +++ b/linkerd/app/integration/src/server.rs @@ -1,5 +1,6 @@ use super::app_core::svc::http::TracingExecutor; use super::*; +use http::{Request, Response}; use std::{ io, sync::atomic::{AtomicUsize, Ordering}, @@ -41,9 +42,8 @@ pub struct Listening { pub(super) http_version: Option, } -type Request = http::Request; -type Response = http::Response; -type RspFuture = Pin> + Send + Sync + 'static>>; +type RspFuture = + Pin, Error>> + Send + Sync + 'static>>; impl Listening { pub fn connections(&self) -> usize { @@ -123,7 +123,7 @@ impl Server { /// to send back. pub fn route_fn(self, path: &str, cb: F) -> Self where - F: Fn(Request) -> Response + Send + Sync + 'static, + F: Fn(Request) -> Response + Send + Sync + 'static, { self.route_async(path, move |req| { let res = cb(req); @@ -135,8 +135,8 @@ impl Server { /// a response to send back. pub fn route_async(mut self, path: &str, cb: F) -> Self where - F: Fn(Request) -> U + Send + Sync + 'static, - U: TryFuture + Send + Sync + 'static, + F: Fn(Request) -> U + Send + Sync + 'static, + U: TryFuture> + Send + Sync + 'static, U::Error: Into + Send + 'static, { let func = move |req| Box::pin(cb(req).map_err(Into::into)) as RspFuture; @@ -258,7 +258,7 @@ pub(super) enum Run { Http2, } -struct Route(Box RspFuture + Send + Sync>); +struct Route(Box) -> RspFuture + Send + Sync>); impl Route { fn string(body: &str) -> Route { @@ -284,7 +284,7 @@ impl std::fmt::Debug for Route { struct Svc(Arc>); impl Svc { - fn route(&mut self, req: Request) -> RspFuture { + fn route(&mut self, req: Request) -> RspFuture { match self.0.get(req.uri().path()) { Some(Route(ref func)) => { tracing::trace!(path = %req.uri().path(), "found route for path"); @@ -302,8 +302,8 @@ impl Svc { } } -impl tower::Service for Svc { - type Response = Response; +impl tower::Service> for Svc { + type Response = Response; type Error = Error; type Future = RspFuture; @@ -311,7 +311,7 @@ impl tower::Service for Svc { Poll::Ready(Ok(())) } - fn call(&mut self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { self.route(req) } } From 4e3119cd455d0ac4785cebae1f04b4a32940c9cd Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Mon, 3 Mar 2025 19:42:01 -0500 Subject: [PATCH 7/7] refactor(app/integration): clean up `Server` constructors (#3693) this commit removes some misdirection from the various constructors for our test server. currently, we expose a family of constructor functions `server::new()`, `server::http1()`, ..., and so forth. each of these invoke a private `server::Server::http1()`, `server::Server::http2()`, `server::Server::http2_tls()`, ..., counterpart, which then delegates down once more to another private constructor `server::Server::new()`. this is all a bit roundabout, particularly because these private constructors are not used by any other internal code in the `server` submodule. this commit removes these inherent `Server` constructors, since they are private and not used by any test code. each free-standing constructor function is altered to instead directly construct a `Server`. Signed-off-by: katelyn martin --- linkerd/app/integration/src/server.rs | 48 +++++++++++---------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/linkerd/app/integration/src/server.rs b/linkerd/app/integration/src/server.rs index 9b50bdd9e6..ef5e331fc0 100644 --- a/linkerd/app/integration/src/server.rs +++ b/linkerd/app/integration/src/server.rs @@ -13,19 +13,35 @@ pub fn new() -> Server { } pub fn http1() -> Server { - Server::http1() + Server { + routes: Default::default(), + version: Run::Http1, + tls: None, + } } pub fn http1_tls(tls: Arc) -> Server { - Server::http1_tls(tls) + Server { + routes: Default::default(), + version: Run::Http1, + tls: Some(tls), + } } pub fn http2() -> Server { - Server::http2() + Server { + routes: Default::default(), + version: Run::Http2, + tls: None, + } } pub fn http2_tls(tls: Arc) -> Server { - Server::http2_tls(tls) + Server { + routes: Default::default(), + version: Run::Http2, + tls: Some(tls), + } } pub struct Server { @@ -88,30 +104,6 @@ impl Listening { } impl Server { - fn new(run: Run, tls: Option>) -> Self { - Server { - routes: HashMap::new(), - version: run, - tls, - } - } - - fn http1() -> Self { - Server::new(Run::Http1, None) - } - - fn http1_tls(tls: Arc) -> Self { - Server::new(Run::Http1, Some(tls)) - } - - fn http2() -> Self { - Server::new(Run::Http2, None) - } - - fn http2_tls(tls: Arc) -> Self { - Server::new(Run::Http2, Some(tls)) - } - /// Return a string body as a 200 OK response, with the string as /// the response body. pub fn route(mut self, path: &str, resp: &str) -> Self {