Skip to content

Commit 38320eb

Browse files
committed
create HTTPS server
1 parent 73360f7 commit 38320eb

File tree

6 files changed

+215
-64
lines changed

6 files changed

+215
-64
lines changed

Cargo.lock

Lines changed: 4 additions & 56 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
[package]
2-
name = "hyper-rustls-prac"
2+
name = "hyper-rustls-example"
33
version = "0.1.0"
44
authors = ["Ryo Ota <nwtgck@nwtgck.org>"]
55
edition = "2018"
66

77
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
88

99
[dependencies]
10-
hyper = { version = "0.13.0", default-features = false }
11-
tokio = { version = "0.2", features = ["full"] }
10+
hyper = "0.13.0"
11+
tokio = { version = "0.2", features = ["rt-threaded", "macros"] }
1212
rustls = "0.18"
1313
hyper-rustls = "0.21.0"
14+
futures-util = "0.3.1"
15+
tokio-rustls = "0.14.0"

README.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,25 @@
1-
# hyper-rustls-prac
1+
# hyper-rustls-example
2+
Simple example of [hyper-rustls](https://github.com/ctz/hyper-rustls)
3+
4+
## Run
5+
6+
Run as follows.
7+
8+
```bash
9+
cargo run
10+
```
11+
12+
Access to the server as follows.
13+
14+
```bash
15+
curl -k https://localhost:3000/
16+
```
17+
18+
## Make self-signed certificates by yourself
19+
20+
You can make certificates as follows.
21+
22+
```bash
23+
mkdir ssl_certs && cd ssl_certs && openssl req -x509 -newkey rsa:4096 -keyout _server.key -out server.crt -days 365 -sha256 -nodes --subj '/CN=localhost/' && openssl rsa -in _server.key -out server.key && rm _server.key && cd -
24+
```
25+
(ref: [Can't run example with system certificate · Issue #26 · ctz/rustls](https://github.com/ctz/rustls/issues/26#issuecomment-565515486))

src/main.rs

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,125 @@
1+
use futures_util::{
2+
future::TryFutureExt,
3+
stream::{Stream, StreamExt, TryStreamExt},
4+
};
5+
use hyper::service::{make_service_fn, service_fn};
6+
use hyper::{Body, Request, Response, Server};
7+
use rustls::internal::pemfile;
18
use std::convert::Infallible;
9+
use std::io;
210
use std::net::SocketAddr;
3-
use hyper::{Body, Request, Response, Server};
4-
use hyper::service::{make_service_fn, service_fn};
11+
use tokio::net::{TcpListener, TcpStream};
12+
use tokio_rustls::server::TlsStream;
13+
use tokio_rustls::TlsAcceptor;
514

615
async fn hello_world(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
716
Ok(Response::new("Hello, World".into()))
817
}
918

19+
fn error(err: String) -> std::io::Error {
20+
std::io::Error::new(std::io::ErrorKind::Other, err)
21+
}
22+
1023
#[tokio::main]
11-
async fn main() {
24+
async fn main() -> io::Result<()> {
1225
// We'll bind to 127.0.0.1:3000
1326
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
1427

28+
// Build TLS configuration.
29+
let tls_cfg = {
30+
// Load public certificate.
31+
let certs = load_certs("./ssl_certs/server.crt")?;
32+
// Load private key.
33+
let key = load_private_key("./ssl_certs/server.key")?;
34+
// Do not use client certificate authentication.
35+
let mut cfg = rustls::ServerConfig::new(rustls::NoClientAuth::new());
36+
// Select a certificate to use.
37+
cfg.set_single_cert(certs, key)
38+
.map_err(|e| {
39+
println!("{}", e);
40+
error(format!("{}", e))
41+
})?;
42+
// Configure ALPN to accept HTTP/2, HTTP/1.1 in that order.
43+
cfg.set_protocols(&[b"h2".to_vec(), b"http/1.1".to_vec()]);
44+
std::sync::Arc::new(cfg)
45+
};
46+
47+
// Create a TCP listener via tokio.
48+
let mut tcp = TcpListener::bind(&addr).await?;
49+
let tls_acceptor = TlsAcceptor::from(tls_cfg);
50+
// Prepare a long-running future stream to accept and serve cients.
51+
let incoming_tls_stream = tcp
52+
.incoming()
53+
.map_err(|e| error(format!("Incoming failed: {:?}", e)))
54+
.and_then(move |s| {
55+
tls_acceptor.accept(s).map_err(|e| {
56+
println!("[!] Voluntary server halt due to client-connection error...");
57+
// Errors could be handled here, instead of server aborting.
58+
// Ok(None)
59+
error(format!("TLS Error: {:?}", e))
60+
})
61+
})
62+
.boxed();
63+
1564
// A `Service` is needed for every connection, so this
1665
// creates one from our `hello_world` function.
1766
let make_svc = make_service_fn(|_conn| async {
1867
// service_fn converts our function into a `Service`
1968
Ok::<_, Infallible>(service_fn(hello_world))
2069
});
2170

22-
let server = Server::bind(&addr).serve(make_svc);
71+
// let server = Server::bind(&addr).serve(make_svc);
72+
let server = Server::builder(HyperAcceptor {
73+
acceptor: incoming_tls_stream,
74+
})
75+
.serve(make_svc);
2376

2477
// Run this server for... forever!
2578
if let Err(e) = server.await {
2679
eprintln!("server error: {}", e);
2780
}
81+
Ok(())
82+
}
83+
84+
struct HyperAcceptor<'a> {
85+
acceptor: core::pin::Pin<Box<dyn Stream<Item = Result<TlsStream<TcpStream>, io::Error>> + 'a>>,
86+
}
87+
88+
impl hyper::server::accept::Accept for HyperAcceptor<'_> {
89+
type Conn = TlsStream<TcpStream>;
90+
type Error = io::Error;
91+
92+
fn poll_accept(
93+
mut self: core::pin::Pin<&mut Self>,
94+
cx: &mut core::task::Context,
95+
) -> core::task::Poll<Option<Result<Self::Conn, Self::Error>>> {
96+
core::pin::Pin::new(&mut self.acceptor).poll_next(cx)
97+
}
98+
}
99+
100+
// Load public certificate from file.
101+
fn load_certs(filename: &str) -> io::Result<Vec<rustls::Certificate>> {
102+
// Open certificate file.
103+
let certfile = std::fs::File::open(filename)
104+
.map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
105+
let mut reader = io::BufReader::new(certfile);
106+
107+
// Load and return certificate.
108+
pemfile::certs(&mut reader).map_err(|_| error("failed to load certificate".into()))
109+
}
110+
111+
// Load private key from file.
112+
fn load_private_key(filename: &str) -> io::Result<rustls::PrivateKey> {
113+
// Open keyfile.
114+
let keyfile = std::fs::File::open(filename)
115+
.map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
116+
let mut reader = io::BufReader::new(keyfile);
117+
118+
// Load and return a single private key.
119+
let keys = pemfile::rsa_private_keys(&mut reader)
120+
.map_err(|_| error("failed to load private key".into()))?;
121+
if keys.len() != 1 {
122+
return Err(error("expected a single private key".into()));
123+
}
124+
Ok(keys[0].clone())
28125
}

ssl_certs/server.crt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIFCTCCAvGgAwIBAgIUcZwW2HAgmPaohXXCHbS+TywRu7QwDQYJKoZIhvcNAQEL
3+
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMDgyNDExMjY1OVoXDTIxMDgy
4+
NDExMjY1OVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
5+
AAOCAg8AMIICCgKCAgEAt2K/Z9FObJB8UL0BlF1yn29On1Nf8uMiyNzmwbLE9gQG
6+
ZkCjFybjcEU5Cdud+EsvP+VT+1cIgZo9RLNA/+Ts0VAiji//+EZVGNZTBSV26Vnu
7+
GdRr26AzA43KkebelD98SkaOtmzLmNkHZZDkaBp33eRIpfIZL590GoYvNV+ZahcS
8+
OHt6vwVuToX2obFDkWVSZIea/XnB2ObYyUzJIR/HHA6pbqoztETO27/5DPKCW9on
9+
DGGRUAa+yWrTsHaDFPiwja88nWMWCDStnuVXVOTSOljpMcDuAoR7k3xzQBvLb2KC
10+
4sNpHeMveGiukUHvNJboBW+h6EwakFVWvFKXR+bbSaWfMBxPNTvMuH6RR1doA7D1
11+
XLQoOi3bKtHKjHP/ysLhv4J+TDnOC6BGoPpj6HnMEd3fQZvx6ogkjJHSm2lHJNm0
12+
3l4DczK1Dcy5eH1KMOwD2Jyu7mjZO0ZHQ+rVwMIt7JlXbrZJqKVHr/F9PidljiJq
13+
vMJqW6Ih1VAyWKxQbFgq8LdcjRvcYiKTONt2q/hzHhrF1x68irgogC282GWeHkS/
14+
QMgWF704LM2zCMfyZEOMUvUfNrfvUckwXMDdTXDCW3ZYuH91uV7q3N6LHonPD/xX
15+
7DGMMNwXgDQZnPzaYMdhB+CwQJpneambE6LZ1me883MYUJaJFoUmExej38leDHEC
16+
AwEAAaNTMFEwHQYDVR0OBBYEFDn2jffC2WRaJCKG2CgT5YJZTZuKMB8GA1UdIwQY
17+
MBaAFDn2jffC2WRaJCKG2CgT5YJZTZuKMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
18+
hvcNAQELBQADggIBAKq+q7BMxIi/FET8lJEmS6JFCa6cy/Ig4y5Vz6KYvPA4W1Pe
19+
hyXqqpruLk620paYzAFteZINX4agZAPgeY/Vp69iq79zy4qf+n/8ftCeY6ByXpOq
20+
zY5ofxZOh5F7ZAKJNcgj9bZMiUXyF6inPwx2MFJ7jrnmiKjvhq0k/UKlctr5oRiX
21+
Vq3PdiiosRxMXe5tQ9YqfJzjgqA6PAjKacxX1szsBldLirIHmEsOGAFAoLHCxaVT
22+
f/Za/1f3v42w9AtPKO2sdH5DvRYPexYxnxTSBq3nXcgyGulHOdU5RtTgI5qBW81S
23+
jZEy7FWLkf+STSZOKUxvd/dcsXLsWV9Gn19iiY27KvrO/m/zFsFLO7I49HIM9WBp
24+
mPGJkkFDyxzzHS9wOUxYMvuWuxOjogTSxLFoIpMPVQte0hT5oJkKTXrHS0RJBrHY
25+
qteHU2t7+xWp577rfaUBAhBPDrCnf05iEUSJokCe7ZUiPEEw5oxvbU+tRhwgnkPS
26+
bZc+q+NysFcd1TrC5fr1RbGlFfy//S6h+F1VDegLQgvztbRhKxk7bqSq2eog0C8n
27+
Cv7Am4MotCM5amexcYlxur4fUyoJSLftj3UgXD6lP9pZmDChAr5pj/rBKBhWGLMC
28+
p2FGNeUaiPNpMqAnlOUwyC9ghzP1BMWR7wPiL/ITcHMWlO72mIfrutRY7oVr
29+
-----END CERTIFICATE-----

ssl_certs/server.key

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
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
51+
-----END RSA PRIVATE KEY-----

0 commit comments

Comments
 (0)