Skip to content

Commit 4e71a77

Browse files
committed
chore: improve rust http-server
1 parent 8242189 commit 4e71a77

File tree

5 files changed

+174
-52
lines changed

5 files changed

+174
-52
lines changed

bench/algorithm/http-server/1-http2.rs

Lines changed: 76 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
2-
31
use axum::routing::post;
4-
use axum_server::tls_rustls::RustlsConfig;
2+
use axum_server::{tls_rustls::RustlsConfig, AddrIncomingConfig, HttpConfig};
3+
use hyper::{client::HttpConnector, StatusCode};
4+
use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder};
55
use rand::prelude::*;
6+
use rustls::client::ServerCertVerifier;
67
use serde::{Deserialize, Serialize};
8+
use std::{
9+
net::{IpAddr, Ipv4Addr, SocketAddr},
10+
sync::Arc,
11+
time::Duration,
12+
};
713
use tokio::sync::mpsc::{self, Sender};
814

915
static CERT: &[u8] = include_bytes!("../self_signed_certs/cert.pem");
1016
static KEY: &[u8] = include_bytes!("../self_signed_certs/key.pem");
1117
lazy_static::lazy_static! {
12-
static ref HTTP_CLIENT: reqwest::Client = reqwest::Client::builder()
13-
.danger_accept_invalid_certs(true)
14-
.use_rustls_tls()
15-
.build()
16-
.unwrap();
18+
static ref H2_CLIENT: hyper::Client<HttpsConnector<HttpConnector>> = h2_client();
1719
}
1820

1921
fn main() -> anyhow::Result<()> {
@@ -51,35 +53,89 @@ async fn run_server(port: usize) -> anyhow::Result<()> {
5153
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port as u16);
5254
let rustls_config = RustlsConfig::from_pem(CERT.into(), KEY.into()).await?;
5355
axum_server::bind_rustls(addr, rustls_config)
56+
.http_config(
57+
HttpConfig::default()
58+
.http2_keep_alive_interval(Some(Duration::from_secs(10)))
59+
.http2_only(true)
60+
.build(),
61+
)
62+
.addr_incoming_config(AddrIncomingConfig::default().tcp_nodelay(true).build())
5463
.serve(app.into_make_service())
5564
.await?;
5665
Ok(())
5766
}
5867

5968
async fn send_with_retry(api: String, value: usize, sender: Sender<usize>) -> anyhow::Result<()> {
6069
loop {
61-
if let Ok(r) = send_once(&api, value).await {
62-
sender.send(r).await?;
63-
break;
70+
match send_once(&api, value).await {
71+
Ok(r) => {
72+
sender.send(r).await?;
73+
break;
74+
}
75+
Err(_e) => {
76+
// eprintln!("{_e}");
77+
}
6478
}
6579
}
6680
Ok(())
6781
}
6882

6983
async fn send_once(api: &str, value: usize) -> anyhow::Result<usize> {
7084
let payload = Payload { value };
71-
let resp = HTTP_CLIENT
72-
.post(api)
73-
.json(&payload)
74-
.version(reqwest::Version::HTTP_2)
75-
.send()
85+
let resp = H2_CLIENT
86+
.request(hyper::Request::post(api).body(serde_json::to_string(&payload)?.into())?)
7687
.await?;
77-
let resp_text = resp.text().await?;
78-
Ok(resp_text.parse::<usize>()?)
88+
if resp.status().is_success() {
89+
let bytes = hyper::body::to_bytes(resp.into_body()).await?;
90+
let text = String::from_utf8_lossy(&bytes[..]);
91+
Ok(text.parse::<usize>()?)
92+
} else {
93+
anyhow::bail!("{}", resp.status())
94+
}
95+
}
96+
97+
async fn handler(body: axum::extract::RawBody) -> (StatusCode, String) {
98+
match handler_inner(body).await {
99+
Ok(b) => (StatusCode::OK, b),
100+
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
101+
}
102+
}
103+
104+
async fn handler_inner(body: axum::extract::RawBody) -> anyhow::Result<String> {
105+
let bytes = hyper::body::to_bytes(body.0).await?;
106+
let json: Payload = serde_json::from_slice(&bytes[..])?;
107+
Ok(format!("{}", json.value))
108+
}
109+
110+
struct CustomTlsVerifier;
111+
112+
impl ServerCertVerifier for CustomTlsVerifier {
113+
fn verify_server_cert(
114+
&self,
115+
_end_entity: &rustls::Certificate,
116+
_intermediates: &[rustls::Certificate],
117+
_server_name: &rustls::ServerName,
118+
_scts: &mut dyn Iterator<Item = &[u8]>,
119+
_ocsp_response: &[u8],
120+
_now: std::time::SystemTime,
121+
) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
122+
Ok(rustls::client::ServerCertVerified::assertion())
123+
}
79124
}
80125

81-
async fn handler(payload: axum::Json<Payload>) -> String {
82-
format!("{}", payload.value)
126+
fn h2_client() -> hyper::Client<HttpsConnector<HttpConnector>> {
127+
hyper::Client::builder().build(
128+
HttpsConnectorBuilder::new()
129+
.with_tls_config(
130+
rustls::ClientConfig::builder()
131+
.with_safe_defaults()
132+
.with_custom_certificate_verifier(Arc::new(CustomTlsVerifier))
133+
.with_no_client_auth(),
134+
)
135+
.https_only()
136+
.enable_http2()
137+
.build(),
138+
)
83139
}
84140

85141
#[derive(Debug, Clone, Serialize, Deserialize)]

bench/algorithm/http-server/1.rs

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use axum::routing::post;
2+
use hyper::{client::HttpConnector, StatusCode};
23
use rand::prelude::*;
34
use serde::{Deserialize, Serialize};
45
use tokio::sync::mpsc::{self, Sender};
56

67
static HOST: &str = "127.0.0.1";
78
lazy_static::lazy_static! {
8-
static ref HTTP_CLIENT: reqwest::Client = reqwest::Client::new();
9+
static ref H1_CLIENT: hyper::Client<HttpConnector> = h1_client();
910
}
1011

1112
fn main() -> anyhow::Result<()> {
@@ -46,11 +47,7 @@ async fn run_server(port: usize) -> anyhow::Result<()> {
4647
Ok(())
4748
}
4849

49-
async fn send_with_retry(
50-
api: String,
51-
value: usize,
52-
sender: Sender<usize>,
53-
) -> anyhow::Result<()> {
50+
async fn send_with_retry(api: String, value: usize, sender: Sender<usize>) -> anyhow::Result<()> {
5451
loop {
5552
if let Ok(r) = send_once(&api, value).await {
5653
sender.send(r).await?;
@@ -62,13 +59,33 @@ async fn send_with_retry(
6259

6360
async fn send_once(api: &str, value: usize) -> anyhow::Result<usize> {
6461
let payload = Payload { value };
65-
let resp = HTTP_CLIENT.post(api).json(&payload).send().await?;
66-
let resp_text = resp.text().await?;
67-
Ok(resp_text.parse::<usize>()?)
62+
let resp = H1_CLIENT
63+
.request(hyper::Request::post(api).body(serde_json::to_string(&payload)?.into())?)
64+
.await?;
65+
if resp.status().is_success() {
66+
let bytes = hyper::body::to_bytes(resp.into_body()).await?;
67+
let text = String::from_utf8_lossy(&bytes[..]);
68+
Ok(text.parse::<usize>()?)
69+
} else {
70+
anyhow::bail!("{}", resp.status())
71+
}
72+
}
73+
74+
async fn handler(body: axum::extract::RawBody) -> (StatusCode, String) {
75+
match handler_inner(body).await {
76+
Ok(b) => (StatusCode::OK, b),
77+
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
78+
}
79+
}
80+
81+
async fn handler_inner(body: axum::extract::RawBody) -> anyhow::Result<String> {
82+
let bytes = hyper::body::to_bytes(body.0).await?;
83+
let json: Payload = serde_json::from_slice(&bytes[..])?;
84+
Ok(format!("{}", json.value))
6885
}
6986

70-
async fn handler(payload: axum::Json<Payload>) -> String {
71-
format!("{}", payload.value)
87+
fn h1_client() -> hyper::Client<HttpConnector> {
88+
hyper::Client::builder().build_http()
7289
}
7390

7491
#[derive(Debug, Clone, Serialize, Deserialize)]

bench/algorithm/http-server/2-http2.rs

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1+
use hyper::client::HttpConnector;
2+
use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder};
13
use rand::prelude::*;
4+
use rustls::client::ServerCertVerifier;
25
use serde::{Deserialize, Serialize};
6+
use std::sync::Arc;
37
use tokio::sync::mpsc::{self, Sender};
48
use warp::Filter;
59

610
static CERT: &[u8] = include_bytes!("../self_signed_certs/cert.pem");
711
static KEY: &[u8] = include_bytes!("../self_signed_certs/key.pem");
812
lazy_static::lazy_static! {
9-
static ref HTTP_CLIENT: reqwest::Client = reqwest::Client::builder()
10-
.danger_accept_invalid_certs(true)
11-
.use_rustls_tls()
12-
.build()
13-
.unwrap();
13+
static ref H2_CLIENT: hyper::Client<HttpsConnector<HttpConnector>> = h2_client();
1414
}
1515

1616
fn main() -> anyhow::Result<()> {
@@ -63,22 +63,57 @@ async fn send_with_retry(api: String, value: usize, sender: Sender<usize>) -> an
6363
sender.send(r).await?;
6464
break;
6565
}
66-
Err(err) => eprintln!("{err}"),
66+
Err(_e) => {
67+
// eprintln!("{_e}");
68+
}
6769
}
6870
}
6971
Ok(())
7072
}
7173

7274
async fn send_once(api: &str, value: usize) -> anyhow::Result<usize> {
7375
let payload = Payload { value };
74-
let resp = HTTP_CLIENT
75-
.post(api)
76-
.json(&payload)
77-
.version(reqwest::Version::HTTP_2)
78-
.send()
76+
let resp = H2_CLIENT
77+
.request(hyper::Request::post(api).body(serde_json::to_string(&payload)?.into())?)
7978
.await?;
80-
let resp_text = resp.text().await?;
81-
Ok(resp_text.parse::<usize>()?)
79+
if resp.status().is_success() {
80+
let bytes = hyper::body::to_bytes(resp.into_body()).await?;
81+
let text = String::from_utf8_lossy(&bytes[..]);
82+
Ok(text.parse::<usize>()?)
83+
} else {
84+
anyhow::bail!("{}", resp.status())
85+
}
86+
}
87+
88+
struct CustomTlsVerifier;
89+
90+
impl ServerCertVerifier for CustomTlsVerifier {
91+
fn verify_server_cert(
92+
&self,
93+
_end_entity: &rustls::Certificate,
94+
_intermediates: &[rustls::Certificate],
95+
_server_name: &rustls::ServerName,
96+
_scts: &mut dyn Iterator<Item = &[u8]>,
97+
_ocsp_response: &[u8],
98+
_now: std::time::SystemTime,
99+
) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
100+
Ok(rustls::client::ServerCertVerified::assertion())
101+
}
102+
}
103+
104+
fn h2_client() -> hyper::Client<HttpsConnector<HttpConnector>> {
105+
hyper::Client::builder().build(
106+
HttpsConnectorBuilder::new()
107+
.with_tls_config(
108+
rustls::ClientConfig::builder()
109+
.with_safe_defaults()
110+
.with_custom_certificate_verifier(Arc::new(CustomTlsVerifier))
111+
.with_no_client_auth(),
112+
)
113+
.https_only()
114+
.enable_http2()
115+
.build(),
116+
)
82117
}
83118

84119
#[derive(Debug, Clone, Serialize, Deserialize)]

bench/algorithm/http-server/2.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1+
use hyper::client::HttpConnector;
12
use rand::prelude::*;
23
use serde::{Deserialize, Serialize};
34
use tokio::sync::mpsc::{self, Sender};
45
use warp::Filter;
56

67
lazy_static::lazy_static! {
7-
static ref HTTP_CLIENT: reqwest::Client = reqwest::Client::builder()
8-
.build()
9-
.unwrap();
8+
static ref H1_CLIENT: hyper::Client<HttpConnector> = h1_client();
109
}
1110

1211
fn main() -> anyhow::Result<()> {
@@ -62,9 +61,20 @@ async fn send_with_retry(api: String, value: usize, sender: Sender<usize>) -> an
6261

6362
async fn send_once(api: &str, value: usize) -> anyhow::Result<usize> {
6463
let payload = Payload { value };
65-
let resp = HTTP_CLIENT.post(api).json(&payload).send().await?;
66-
let resp_text = resp.text().await?;
67-
Ok(resp_text.parse::<usize>()?)
64+
let resp = H1_CLIENT
65+
.request(hyper::Request::post(api).body(serde_json::to_string(&payload)?.into())?)
66+
.await?;
67+
if resp.status().is_success() {
68+
let bytes = hyper::body::to_bytes(resp.into_body()).await?;
69+
let text = String::from_utf8_lossy(&bytes[..]);
70+
Ok(text.parse::<usize>()?)
71+
} else {
72+
anyhow::bail!("{}", resp.status())
73+
}
74+
}
75+
76+
fn h1_client() -> hyper::Client<HttpConnector> {
77+
hyper::Client::builder().build_http()
6878
}
6979

7080
#[derive(Debug, Clone, Serialize, Deserialize)]

bench/include/rust/Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ default = [
1313
"futures-lite",
1414
"axum",
1515
"axum-server",
16-
"reqwest",
16+
"hyper",
17+
"hyper-rustls",
18+
"rustls",
1719
"warp",
1820
]
1921

@@ -49,7 +51,9 @@ axum = {version = "0.6", optional = true, features = ["http1", "http2"]}
4951
axum-server = {version = "0.4", optional = true, features = ["tls-rustls"]}
5052
flume = {version = "0", optional = true}
5153
futures-lite = {version = "1", optional = true}
52-
reqwest = {version = "0.11", optional = true, default-features = false, features = ["json", "rustls-tls"]}
54+
hyper = {version = "0.14", optional = true, default-features = false, features = ["client", "http1", "http2"]}
55+
hyper-rustls = {version = "0.23", optional = true, default-features = false, features = ["native-tokio", "http2"]}
56+
rustls = {version = "0.20", optional = true}
5357
tokio = {version = "1.22", optional = true}
5458
warp = {version = "0.3", optional = true, features = ["tls"]}
5559

0 commit comments

Comments
 (0)