summaryrefslogtreecommitdiff
path: root/vendor/hyper-util/examples/server.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/hyper-util/examples/server.rs')
-rw-r--r--vendor/hyper-util/examples/server.rs75
1 files changed, 75 insertions, 0 deletions
diff --git a/vendor/hyper-util/examples/server.rs b/vendor/hyper-util/examples/server.rs
new file mode 100644
index 00000000..48806d80
--- /dev/null
+++ b/vendor/hyper-util/examples/server.rs
@@ -0,0 +1,75 @@
+//! This example runs a server that responds to any request with "Hello, world!"
+
+use std::{convert::Infallible, error::Error};
+
+use bytes::Bytes;
+use http::{header::CONTENT_TYPE, Request, Response};
+use http_body_util::{combinators::BoxBody, BodyExt, Full};
+use hyper::{body::Incoming, service::service_fn};
+use hyper_util::{
+ rt::{TokioExecutor, TokioIo},
+ server::conn::auto::Builder,
+};
+use tokio::{net::TcpListener, task::JoinSet};
+
+/// Function from an incoming request to an outgoing response
+///
+/// This function gets turned into a [`hyper::service::Service`] later via
+/// [`service_fn`]. Instead of doing this, you could also write a type that
+/// implements [`hyper::service::Service`] directly and pass that in place of
+/// writing a function like this and calling [`service_fn`].
+///
+/// This function could use [`Full`] as the body type directly since that's
+/// the only type that can be returned in this case, but this uses [`BoxBody`]
+/// anyway for demonstration purposes, since this is what's usually used when
+/// writing a more complex webserver library.
+async fn handle_request(
+ _request: Request<Incoming>,
+) -> Result<Response<BoxBody<Bytes, Infallible>>, Infallible> {
+ let response = Response::builder()
+ .header(CONTENT_TYPE, "text/plain")
+ .body(Full::new(Bytes::from("Hello, world!\n")).boxed())
+ .expect("values provided to the builder should be valid");
+
+ Ok(response)
+}
+
+#[tokio::main(flavor = "current_thread")]
+async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
+ let listen_addr = "127.0.0.1:8000";
+ let tcp_listener = TcpListener::bind(listen_addr).await?;
+ println!("listening on http://{listen_addr}");
+
+ let mut join_set = JoinSet::new();
+ loop {
+ let (stream, addr) = match tcp_listener.accept().await {
+ Ok(x) => x,
+ Err(e) => {
+ eprintln!("failed to accept connection: {e}");
+ continue;
+ }
+ };
+
+ let serve_connection = async move {
+ println!("handling a request from {addr}");
+
+ let result = Builder::new(TokioExecutor::new())
+ .serve_connection(TokioIo::new(stream), service_fn(handle_request))
+ .await;
+
+ if let Err(e) = result {
+ eprintln!("error serving {addr}: {e}");
+ }
+
+ println!("handled a request from {addr}");
+ };
+
+ join_set.spawn(serve_connection);
+ }
+
+ // If you add a method for breaking the above loop (i.e. graceful shutdown),
+ // then you may also want to wait for all existing connections to finish
+ // being served before terminating the program, which can be done like this:
+ //
+ // while let Some(_) = join_set.join_next().await {}
+}