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 }}
- {% for guide in topic.guides %}
- {% assign guide_url = guide | prepend:"/" | prepend: topic.path | prepend:"/guides" | append:"/" %}
- {% assign p = site.guides | where:"url", guide_url | first %}
- - {{ p.title }}
- {% endfor %}
+ {% if page.collection == "legacy" %}
+ {% for guide in topic.guides %}
+ {% assign guide_url = guide | prepend:"/" | prepend: topic.path | prepend:"/guides/0.14" | append:"/" %}
+ {% assign p = site.legacy | where:"url", guide_url | first %}
+ - {{ p.title }}
+ {% endfor %}
+ {% elsif page.collection == "stable" %}
+ {% for guide in topic.guides %}
+ {% assign guide_url = guide | prepend:"/" | prepend: topic.path | prepend:"/guides/1" | append:"/" %}
+ {% assign p = site.stable | where:"url", guide_url | first %}
+ - {{ p.title }}
+ {% endfor %}
+ {% endif %}
-
\ 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 @@
hyper.rs
- Guides
+ 1.0 Guides
+ 0.14 Guides
Source
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 @@
-
-
+
+
+
+ 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() {}
```