diff --git a/.github/workflows/check_guides.sh b/.github/workflows/check_guides.sh index 400cf78..dcfabd1 100755 --- a/.github/workflows/check_guides.sh +++ b/.github/workflows/check_guides.sh @@ -1,37 +1,50 @@ #!/bin/sh -if [ ! -e tmp/Cargo.toml ]; then - if [ ! -d tmp ]; then - cargo new tmp - else - cargo init tmp - fi - cat >> tmp/Cargo.toml <<-EOF -futures = "0.3" -hyper = { version = "0.14", features = ["full"] } -hyper-tls = "0.5" -tokio = { version = "1", features = ["full"] } +for value in legacy stable +do + if [ ! -e "$value/Cargo.toml" ]; then + if [ ! -d $value ]; then + cargo new $value + else + cargo init $value + fi + if [ $value = legacy ]; then + cat >> "$value/Cargo.toml" <<-EOF + futures = "0.3" + hyper = { version = "0.14", features = ["full"] } + hyper-tls = "0.5" + tokio = { version = "1", features = ["full"] } EOF - cargo build --manifest-path tmp/Cargo.toml -fi - -test_file() { - echo "Testing: $f" - rustdoc --edition 2018 --test $1 -L tmp/target/debug/deps -} + cargo build --manifest-path "$value/Cargo.toml" + fi + if [ $value = stable ]; then + cat >> "$value/Cargo.toml" <<-EOF + hyper = { version = "1.0.0-rc.1", features = ["full"] } + tokio = { version = "1", features = ["full"] } + http-body-util = "0.1.0-rc.1" +EOF + cargo build --manifest-path "$value/Cargo.toml" + fi + fi -if [ -n "$1" ]; then - test_file $1 - exit $? -fi + test_file() { + echo "Testing: $f" + rustdoc --edition 2018 --test $1 -L "$value/target/debug/deps" + } -status=0 -for f in `git ls-files | grep '\.md$'`; do - test_file $f - s=$? - if [ "$s" != "0" ]; then - status=$s + if [ -n "$1" ]; then + test_file $1 + exit $? fi + + status=0 + for f in `git ls-files | grep "^_$value\/.*\.md$"`; do + test_file $f + s=$? + if [ "$s" != "0" ]; then + status=$s + fi + done done exit $status diff --git a/.gitignore b/.gitignore index 7cc2d5f..102b94e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ Gemfile* _site* .sass-cache -tmp/ +/legacy +/stable diff --git a/_config.yml b/_config.yml index d37eb18..b87a627 100644 --- a/_config.yml +++ b/_config.yml @@ -6,14 +6,25 @@ url: "https://hyper.rs" # the base hostname & protocol for your site defaults: - scope: - path: "_guides" + path: "_legacy/" type: "guides" values: layout: "guide" + - + + scope: + path: "_stable/" + type: "guides" + values: + layout: "guide" + collections: - guides: - permalink: /:collection/:path/ + legacy: + permalink: /guides/0.14/:path/ + output: true + stable: + permalink: /guides/1/:path/ output: true posts: permalink: /blog/:year/:month/:day/:title/ @@ -31,7 +42,13 @@ relative_links: enabled: true collections: true -docs_url: https://docs.rs/hyper/0.14.* +plugins: + - jekyll-redirect-from + +docs_url: https://docs.rs/hyper/1.0.0-rc.1 examples_url: https://github.com/hyperium/hyper/tree/master/examples futures_url: https://docs.rs/futures/0.3.* hyper_tls_url: https://docs.rs/hyper-tls/* + +legacy_docs_url: https://docs.rs/hyper/0.14.23 +legacy_examples_url: https://github.com/hyperium/hyper/tree/0.14.x/examples diff --git a/_data/guides.yml b/_data/legacy.yml similarity index 100% rename from _data/guides.yml rename to _data/legacy.yml diff --git a/_data/stable.yml b/_data/stable.yml new file mode 100644 index 0000000..6f7e9f5 --- /dev/null +++ b/_data/stable.yml @@ -0,0 +1,19 @@ +- title: Guide + path: "" + guides: + - server + - client + +- title: Server + path: "/server" + guides: + - hello-world + - echo + - graceful-shutdown + +- title: Client + path: "/client" + guides: + - basic + - advanced + - configuration diff --git a/_includes/guide_ul.html b/_includes/guide_ul.html index bdfd151..e8533af 100644 --- a/_includes/guide_ul.html +++ b/_includes/guide_ul.html @@ -2,10 +2,18 @@

{{ topic.title }}

-
\ No newline at end of file + diff --git a/_includes/header.html b/_includes/header.html index d8cce9d..4980d34 100644 --- a/_includes/header.html +++ b/_includes/header.html @@ -5,7 +5,8 @@ - + + diff --git a/_layouts/guide.html b/_layouts/guide.html index ed8c5df..4372bcb 100644 --- a/_layouts/guide.html +++ b/_layouts/guide.html @@ -14,14 +14,27 @@

{{ page.title }}

diff --git a/_layouts/home.html b/_layouts/home.html index a6e6e06..1613cc1 100644 --- a/_layouts/home.html +++ b/_layouts/home.html @@ -9,12 +9,19 @@

hyper

Fast and safe HTTP for the Rust language.

-

Get Started

+

Get Started

-
-
+
+
+

+ Note: hyper is planning a stable 1.0 release at the end of January 2023. + These guides will be gradually transitioned to 1.0, but if you're looking for + guides for 0.14 you can find them here. If you'd like to + learn more about the move to 1.0, + this is a good place to start. +

hyper is a fast HTTP implementation written in and for Rust.

  • A Client for talking to web services.
  • diff --git a/_guides/client/advanced.md b/_legacy/client/advanced.md similarity index 93% rename from _guides/client/advanced.md rename to _legacy/client/advanced.md index c041fb3..f8cc7ae 100644 --- a/_guides/client/advanced.md +++ b/_legacy/client/advanced.md @@ -1,5 +1,8 @@ --- title: Advanced Client Usage +layout: guide +redirect_from: + - /guides/client/advanced --- Once you've done all the setup in the [simple guide][], you probably @@ -110,5 +113,5 @@ let (ip, headers) = futures::try_join!(ip_fut, headers_fut)?; ``` [simple guide]: ./basic.md -[Request]: {{ site.docs_url }}/hyper/struct.Request.html -[Method]: {{ site.docs_url }}/hyper/struct.Method.html +[Request]: {{ site.legacy_docs_url }}/hyper/struct.Request.html +[Method]: {{ site.legacy_docs_url }}/hyper/struct.Method.html diff --git a/_guides/client/basic.md b/_legacy/client/basic.md similarity index 90% rename from _guides/client/basic.md rename to _legacy/client/basic.md index bee30a9..44926f3 100644 --- a/_guides/client/basic.md +++ b/_legacy/client/basic.md @@ -1,5 +1,8 @@ --- title: Getting Started with a Client +layout: guide +redirect_from: + - /guides/client/basic --- To start with, we'll just get a simple `GET` request to a webpage working, @@ -112,9 +115,9 @@ while let Some(chunk) = resp.body_mut().data().await { And that's it! You can see the [full example here][example]. -[Client]: {{ site.docs_url }}/hyper/client/struct.Client.html +[Client]: {{ site.legacy_docs_url }}/hyper/client/struct.Client.html [Tokio]: https://tokio.rs [Tokio-Futures]: https://tokio.rs/tokio/tutorial/async -[StatusCode]: {{ site.docs_url }}/hyper/struct.StatusCode.html -[Response]: {{ site.docs_url }}/hyper/struct.Response.html -[example]: {{ site.examples_url }}/client.rs +[StatusCode]: {{ site.legacy_docs_url }}/hyper/struct.StatusCode.html +[Response]: {{ site.legacy_docs_url }}/hyper/struct.Response.html +[example]: {{ site.legacy_examples_url }}/client.rs diff --git a/_guides/client/configuration.md b/_legacy/client/configuration.md similarity index 89% rename from _guides/client/configuration.md rename to _legacy/client/configuration.md index c773454..be09c28 100644 --- a/_guides/client/configuration.md +++ b/_legacy/client/configuration.md @@ -1,5 +1,8 @@ --- title: Client Configuration +layout: guide +redirect_from: + - /guides/client/configuration --- ## Using TLS @@ -39,5 +42,5 @@ ideas of things that could be connectors: - Proxies - In-memory streams (such as for testing) -[`Client`]: {{ site.docs_url }}/hyper/client/struct.Client.html +[`Client`]: {{ site.legacy_docs_url }}/hyper/client/struct.Client.html [hyper-tls]: {{ site.hyper_tls_url }} diff --git a/_guides/client/index.md b/_legacy/client/index.md similarity index 67% rename from _guides/client/index.md rename to _legacy/client/index.md index 443558b..65a8e67 100644 --- a/_guides/client/index.md +++ b/_legacy/client/index.md @@ -1,6 +1,8 @@ --- title: Client Guides -permalink: /guides/client/ +permalink: /0.14/client +redirect_from: + - /guides/client/ --- This is just placeholder page. It should probably become a table of diff --git a/_guides/index.md b/_legacy/index.md similarity index 83% rename from _guides/index.md rename to _legacy/index.md index 3cf51c6..c6a229b 100644 --- a/_guides/index.md +++ b/_legacy/index.md @@ -1,7 +1,9 @@ --- title: Getting Started layout: guide -permalink: /guides/ +permalink: /guides/0.14/ +redirect_from: + - /guides/ --- hyper is an HTTP library for the Rust language. @@ -18,6 +20,6 @@ hyper = "0.14" You could also look at the [generated API documentaton][docs]. -[docs]: {{ site.docs_url }} +[docs]: {{ site.legacy_docs_url }} [Server guide]: server/hello-world.md [Client guide]: client/basic.md diff --git a/_guides/server/echo.md b/_legacy/server/echo.md similarity index 98% rename from _guides/server/echo.md rename to _legacy/server/echo.md index e454824..e083e96 100644 --- a/_guides/server/echo.md +++ b/_legacy/server/echo.md @@ -1,5 +1,8 @@ --- title: Echo, echo, echo +layout: guide +redirect_from: + - /guides/server/echo --- You already have a [Hello World server](hello-world.md)? Excellent! Usually, @@ -197,5 +200,5 @@ We want to concatenate the request body, and map the result into our `reverse` f You can see a compiling [example here][example]. -[example]: {{ site.examples_url }}/echo.rs +[example]: {{ site.legacy_examples_url }}/echo.rs [future-crate]: https://github.com/rust-lang-nursery/futures-rs diff --git a/_guides/server/graceful-shutdown.md b/_legacy/server/graceful-shutdown.md similarity index 97% rename from _guides/server/graceful-shutdown.md rename to _legacy/server/graceful-shutdown.md index 0f02760..1edcb90 100644 --- a/_guides/server/graceful-shutdown.md +++ b/_legacy/server/graceful-shutdown.md @@ -1,6 +1,8 @@ --- title: Gracefully Shutdown a Server layout: guide +redirect_from: + - /guides/server/graceful-shutdown --- hyper `Server`s have the ability to "gracefully" shutdown. This means stopping to accept new requests, and shutting down once all in-progress requests have completed. diff --git a/_guides/server/hello-world.md b/_legacy/server/hello-world.md similarity index 94% rename from _guides/server/hello-world.md rename to _legacy/server/hello-world.md index b64d6ce..e195caa 100644 --- a/_guides/server/hello-world.md +++ b/_legacy/server/hello-world.md @@ -1,6 +1,8 @@ --- title: Getting Started with a Server layout: guide +redirect_from: + - /guides/server/hello-world --- Let's start by making a "Hello, World!" server, and expand from there. @@ -94,5 +96,5 @@ async fn main() { To see all the snippets put together, check out the [full example][example]! -[service]: {{ site.docs_url }}/hyper/service/trait.Service.html -[example]: {{ site.examples_url }}/hello.rs +[service]: {{ site.legacy_docs_url }}/hyper/service/trait.Service.html +[example]: {{ site.legacy_examples_url }}/hello.rs diff --git a/_legacy/server/index.md b/_legacy/server/index.md new file mode 100644 index 0000000..3c0b37f --- /dev/null +++ b/_legacy/server/index.md @@ -0,0 +1,9 @@ +--- +title: Server Guides +permalink: /0.14/server +redirect_from: + - /guides/server/ +--- + +This is just placeholder page. It should probably become a table of +contents for the server guides. diff --git a/_stable/index.md b/_stable/index.md new file mode 100644 index 0000000..72ab722 --- /dev/null +++ b/_stable/index.md @@ -0,0 +1,26 @@ +--- +title: Getting Started +layout: guide +permalink: /guides/1/ +--- + +***Note:** these guides are for the upcoming version `1.0` of hyper, +click [here](/guides/0.14) to see the `0.14` guides.* + +hyper is an HTTP library for the Rust language. + +You can start using it by first adding it to your `Cargo.toml`: + +```toml +[dependencies] +hyper = { version = "1.0.0-rc.1", features = ["full"] } +``` + +- If building a web server, continue with the [Server guide][]. +- If trying to talk to a server, continue with the [Client guide][]. + +You could also look at the [generated API documentaton][docs]. + +[docs]: {{ site.docs_url }} +[Server guide]: server/hello-world +[Client guide]: client/basic diff --git a/_stable/server/echo.md b/_stable/server/echo.md new file mode 100644 index 0000000..b7e6c20 --- /dev/null +++ b/_stable/server/echo.md @@ -0,0 +1,230 @@ +--- +title: Echo, echo, echo +layout: guide +--- + +You already have a [Hello World server](../hello-world)? Excellent! Usually, +servers do more than just spit out the same body for every request. To +exercise several more parts of hyper, this guide will go through +building an echo server. + +An echo server will listen for incoming connections and send back the +request body as the response body on `POST` requests. + +## Routing + +First thing we will do, beyond renaming our service to `echo`, is setup some +routing. We want to have a route explaining instructions on how to use +our server, and another for receiving data. Oh, and we should also +handle the case when someone asks for a route we don't know! + +Before we get started we need to add some new imports: + +```rust +# extern crate hyper; +# extern crate http_body_util; +use hyper::body::Frame; +use hyper::{Method, StatusCode}; +use http_body_util::{combinators::BoxBody, BodyExt}; +# fn main() {} +``` + +Next, we need to make some changes to our `Service` function, but as you can see +it's still just an async function that takes a `Request` and returns a `Response` +future, and you can pass it to your server just like we did for the `hello` service. + +Unlike our `hello` service where we didn't care about the request body and +we always returned a single chunk of bytes containing our greeting, we're now +going to want a bit more freedom in how we shape our response `Body`. To achieve +this we will change the type of the `Body` in our `Response` to a boxed trait object. +We only care that the response body implements the [Body](https://docs.rs/http-body/1.0.0-rc1/http_body/trait.Body.html) trait, that its data is `Bytes` and its error is a `hyper::Error`. + +```rust +# extern crate hyper; +# extern crate http_body_util; +# use hyper::body::Bytes; +# use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full}; +# use hyper::{Method, Request, Response, StatusCode}; +async fn echo( + req: Request, +) -> Result>, hyper::Error> { + match (req.method(), req.uri().path()) { + (&Method::GET, "/") => Ok(Response::new(full( + "Try POSTing data to /echo", + ))), + (&Method::POST, "/echo") => { + // we'll be back +# Ok(Response::new(req.into_body().boxed())) + }, + + // Return 404 Not Found for other routes. + _ => { + let mut not_found = Response::new(empty()); + *not_found.status_mut() = StatusCode::NOT_FOUND; + Ok(not_found) + } + } +} + +// We create some utility functions to make Empty and Full bodies +// fit our broadened Response body type. +fn empty() -> BoxBody { + Empty::::new() + .map_err(|never| match never {}) + .boxed() +} +fn full>(chunk: T) -> BoxBody { + Full::new(chunk.into()) + .map_err(|never| match never {}) + .boxed() +} +# fn main() {} +``` + +We built a super simple routing table just by matching on the `method` and `path` +of an incoming `Request`. If someone requests `GET /`, our service will let them +know they should try our echo powers out. We also check for `POST /echo`, but +currently don't do anything about it. + +Our third rule catches any other method and path combination, and changes the +`StatusCode` of the `Response`. The default status of a `Response` is HTTP’s +`200 OK` (`StatusCode::OK`), which is correct for the other routes. But the third +case will instead send back `404 Not Found`. + +## Body Streams + +Now let's get that echo in place. An HTTP body is a stream of `Frames`, each +[Frame](https://docs.rs/http-body/1.0.0-rc1/http_body/struct.Frame.html) containing +parts of the `Body` data or trailers. So rather than reading the entire `Body` +into a buffer before sending our response, we can stream each frame as it arrives. +We'll start with the simplest solution, and then make alterations exercising more complex +things you can do with the `Body` streams. + +First up, plain echo. Both the `Request` and the `Response` have body streams, +and by default, you can easily pass the `Body` of the `Request` into a `Response`. + +```rust +# extern crate hyper; +# extern crate http_body_util; +# use hyper::body::Bytes; +# use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full}; +# use hyper::{Method, Request, Response, StatusCode}; +# async fn echo( +# req: Request, +# ) -> Result>, hyper::Error> { +# match (req.method(), req.uri().path()) { +// Inside the match from before +(&Method::POST, "/echo") => Ok(Response::new(req.into_body().boxed())), +# _ => unreachable!(), +# } +# } +# fn main() {} +``` + +Running our server now will echo any data we `POST` to `/echo`. That was easy. +What if we wanted to uppercase all the text? We could use a `map` on our streams. + +## Body mapping + +Every data `Frame` of our body stream is a chunk of bytes, which we can conveniently +represent using the `Bytes` type from hyper. It can be easily converted into other +typical containers of bytes. + +Next, let's add a new `/echo/uppercase` route, mapping each byte in the data `Frame`s +of our request body to uppercase, and returning the stream in our `Response`: + +```rust +# extern crate hyper; +# extern crate http_body_util; +# use hyper::body::Bytes; +# use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full}; +# use hyper::body::Frame; +# use hyper::{Method, Request, Response, StatusCode}; +# async fn echo( +# req: Request, +# ) -> Result>, hyper::Error> { +# match (req.method(), req.uri().path()) { +// Yet another route inside our match block... +(&Method::POST, "/echo/uppercase") => { + // Map this body's frame to a different type + let frame_stream = req.into_body().map_frame(|frame| { + let frame = if let Some(data) = frame.into_data() { + // Convert every byte in every Data frame to uppercase + data.iter() + .map(|byte| byte.to_ascii_uppercase()) + .collect::() + } else { + Bytes::new() + }; + + Frame::data(frame) + }); + + Ok(Response::new(frame_stream.boxed())) +}, +# _ => unreachable!(), +# } +# } +# fn full>(chunk: T) -> BoxBody { +# Full::new(chunk.into()) +# .map_err(|never| match never {}) +# .boxed() +# } +# fn main() {} +``` + +And like that, we have two echo routes: `/echo` which does no transformation, +and `/echo/uppercase` which returns all bytes after converting them to ASCII +uppercase. + +## Buffering the Request Body + +What if we want our echo service to reverse the data it received and send it +back to us? We can't really stream the data as it comes in, since we need to +find the end before we can respond. To do this, we can explore how to easily +collect the full body. + +We want to collect the entire request body and map the result into our `reverse` +function, then return the eventual result. If we import the `http_body_util::BodyExt` +extension trait, we can call the `collect` method on our body, which will drive the +stream to completion, collecting all the data and trailer frames into a `Collected` type. +We can easily turn the `Collected` body into a single `Bytes` by calling its `into_bytes` +method. + +```rust +# extern crate hyper; +# extern crate http_body_util; +# use hyper::body::Bytes; +# use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full}; +# use hyper::{Method, Request, Response, StatusCode}; +# async fn echo( +# req: Request, +# ) -> Result>, hyper::Error> { +# match (req.method(), req.uri().path()) { +// Yet another route inside our match block... +(&Method::POST, "/echo/reversed") => { + // Await the whole body to be collected into a single `Bytes`... + let whole_body = req.collect().await?.to_bytes(); + + // Iterate the whole body in reverse order and collect into a new Vec. + let reversed_body = whole_body.iter() + .rev() + .cloned() + .collect::>(); + + Ok(Response::new(full(reversed_body))) +}, +# _ => unreachable!(), +# } +# } +# fn full>(chunk: T) -> BoxBody { +# Full::new(chunk.into()) +# .map_err(|never| match never {}) +# .boxed() +# } +# fn main() {} +``` + +You can see a compiling [example here][example]. + +[example]: {{ site.examples_url }}/echo.rs diff --git a/_stable/server/hello-world.md b/_stable/server/hello-world.md new file mode 100644 index 0000000..a1c3436 --- /dev/null +++ b/_stable/server/hello-world.md @@ -0,0 +1,129 @@ +--- +title: Getting Started with a Server +layout: guide +--- + +Let's start by making a "Hello, World!" server, and expand from there. + +First we need to declare our dependencies, let's add the following to our `Cargo.toml`: + +```toml +[dependencies] +hyper = { version = "1.0.0-rc.1", features = ["full"] } +tokio = { version = "1", features = ["full"] } +http-body-util = "0.1.0-rc.1" +``` + +Next, we need to add some imports in our `main.rs` file: + +```rust +# extern crate tokio; +# extern crate hyper; +# extern crate http_body_util; +use std::convert::Infallible; +use std::net::SocketAddr; + +use http_body_util::Full; +use hyper::body::Bytes; +use hyper::server::conn::http1; +use hyper::service::service_fn; +use hyper::{Request, Response}; +use tokio::net::TcpListener; +# fn main() {} +``` + +## Creating a Service + +A [`Service`][service] lets us define how our server will respond to +incoming requests. It represents an async function that takes a +[`Request`][request] and returns a `Future`. When the processing of this +future is complete, it will resolve to a [`Response`][response] or an error. + +Hyper provides a utility for creating a `Service` from a function that should +serve most usecases: [`service_fn`][service_fn]. We will use this to create +a service from our `hello` function below when we're ready to start our +server. + +```rust +# extern crate hyper; +# extern crate http_body_util; +# use std::convert::Infallible; +# use http_body_util::Full; +# use hyper::body::Bytes; +# use hyper::{Request, Response}; +# fn main() {} +async fn hello(_: Request) -> Result>, Infallible> { + Ok(Response::new(Full::new(Bytes::from("Hello, World!")))) +} +``` + +Using this function as a service, we tell our server to respond to all requests +with a default `200 OK` status. The response `Body` will contain our friendly +greeting as a single chunk of bytes, and the `Content-Length` header will be +set automatically. + +## Starting the Server + +Lastly, we need to hook up our `hello` service into a running hyper server. + +We'll dive in to the specifics of some of these things in another guide. + +```rust +# extern crate tokio; +# extern crate hyper; +# extern crate http_body_util; +# mod no_run { +# use std::convert::Infallible; +# use std::net::SocketAddr; +# +# use http_body_util::Full; +# use hyper::body::Bytes; +# use hyper::server::conn::http1; +# use hyper::service::service_fn; +# use hyper::{Request, Response}; +# use tokio::net::TcpListener; +# async fn hello( +# _: Request, +# ) -> Result>, Infallible> { +# Ok(Response::new(Full::new(Bytes::from("Hello World!")))) +# } +#[tokio::main] +async fn main() -> Result<(), Box> { + let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); + + // We create a TcpListener and bind it to 127.0.0.1:3000 + let listener = TcpListener::bind(addr).await?; + + // We start a loop to continuously accept incoming connections + loop { + let (stream, _) = listener.accept().await?; + + // Spawn a tokio task to serve multiple connections concurrently + tokio::task::spawn(async move { + // Finally, we bind the incoming connection to our `hello` service + if let Err(err) = http1::Builder::new() + // `service_fn` converts our function in a `Service` + .serve_connection(stream, service_fn(hello)) + .await + { + println!("Error serving connection: {:?}", err); + } + }); + } +} +# } +# fn main() {} +``` + +To see all the snippets put together, check out the [full example][example]! + +Also, if `service_fn` doesn't meet your requirements and you'd like to implement +`Service` yourself, see this [example][impl service]. + +[service]: {{ site.docs_url }}/hyper/service/trait.Service.html +[service_fn]: {{ site.docs_url }}/hyper/service/fn.service_fn.html +[request]: {{ site.docs_url }}/hyper/struct.Request.html +[response]: {{ site.docs_url }}/hyper/struct.Response.html +[parts]: {{ site.docs_url }}/http/0.2.8/http/response/struct.Parts.html +[example]: {{ site.examples_url }}/hello.rs +[impl service]: {{ site.examples_url }}/service_struct_impl.rs diff --git a/_guides/server/index.md b/_stable/server/index.md similarity index 82% rename from _guides/server/index.md rename to _stable/server/index.md index 86e9f22..8c61af2 100644 --- a/_guides/server/index.md +++ b/_stable/server/index.md @@ -1,6 +1,6 @@ --- title: Server Guides -permalink: /guides/server/ +permalink: /1/server/ --- This is just placeholder page. It should probably become a table of diff --git a/index.md b/index.md index b5dedf1..bfe96df 100644 --- a/index.md +++ b/index.md @@ -3,30 +3,41 @@ layout: home --- ```rust -# extern crate hyper; # extern crate tokio; +# extern crate hyper; +# extern crate http_body_util; # mod no_run { -use std::{convert::Infallible, net::SocketAddr}; -use hyper::{Body, Request, Response, Server}; -use hyper::service::{make_service_fn, service_fn}; +use std::{convert::Infallible, net::SocketAddr, error::Error}; +use http_body_util::Full; +use hyper::{Request, Response, body::Bytes, service::service_fn}; +use hyper::server::conn::http1; +use tokio::net::TcpListener; -async fn handle(_: Request) -> Result, Infallible> { - Ok(Response::new("Hello, World!".into())) +async fn hello( + _: Request, +) -> Result>, Infallible> { + Ok(Response::new(Full::new(Bytes::from("Hello World!")))) } #[tokio::main] -async fn main() { +async fn main() -> Result<(), Box> { let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - let make_svc = make_service_fn(|_conn| async { - Ok::<_, Infallible>(service_fn(handle)) - }); + let listener = TcpListener::bind(addr).await?; - let server = Server::bind(&addr).serve(make_svc); + loop { + let (stream, _) = listener.accept().await?; - if let Err(e) = server.await { - eprintln!("server error: {}", e); + tokio::task::spawn(async move { + if let Err(err) = http1::Builder::new() + .serve_connection(stream, service_fn(hello)) + .await + { + println!("Error serving connection: {:?}", err); + } + }); } } # } +# fn main() {} ```