### HTTP Upgrades Example (WebSockets)
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
Demonstrates how to perform HTTP upgrades, such as establishing WebSocket connections. Includes both server and client code for the upgrade process.
```rust
use futures_util::{SinkExt, StreamExt};
use hyper::server::conn::AddrStream;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode};
use hyper_util::rt::TokioIo;
use std::convert::Infallible;
use std::net::SocketAddr;
use tokio_tungstenite::tungstenite::Message;
use tokio_tungstenite::WebSocketStream;
async fn handle_request(req: Request
, src: SocketAddr) -> Result, Box> {
if req.method() == hyper::Method::GET && req.uri().path() == "/websocket" {
let (ws, _) = hyper_upgrade::upgrade(req)?;
tokio::spawn(async move {
let websocket = WebSocketStream::from_tokio(TokioIo::new(ws));
handle_websocket(websocket, src).await;
});
Ok(Response::new(Body::empty()))
} else {
let mut resp = Response::new(Body::from("Hello World!"));
*resp.status_mut() = StatusCode::OK;
Ok(resp)
}
}
async fn handle_websocket(mut websocket: WebSocketStream>, src: SocketAddr) {
while let Some(msg) = websocket.next().await {
match msg {
Ok(Message::Text(text)) => {
println!("Received message from {{}}: {{}}", src, text);
let response = format!("Echo: {}", text);
if websocket.send(Message::Text(response)).await.is_err() {
eprintln!("Failed to send message to {}", src);
break;
}
}
Ok(Message::Binary(bin)) => {
println!("Received binary from {{}}: {{:?}}", src, bin);
if websocket.send(Message::Binary(bin)).await.is_err() {
eprintln!("Failed to send binary message to {}", src);
break;
}
}
Ok(Message::Close(_)) => {
println!("Connection closed by {}", src);
break;
}
Err(e) => {
eprintln!("WebSocket error from {{}}: {}", src, e);
break;
}
_ => {},
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let addr = ([127, 0, 0, 1], 3000).into();
let make_svc = make_service_fn(|conn: AddrStream| {
let src = conn.remote_addr();
async move {
Ok::<_, Infallible>(service_fn(move |req| handle_request(req, src)))
}
});
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{{}}", addr);
server.await?;
Ok(())
}
```
--------------------------------
### Simple HTTP Client Example
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
A basic CLI client that fetches content from a given URL and prints it chunk by chunk. Requires the URL as a command-line parameter.
```rust
use hyper::client::HttpConnector;
use hyper::Body;
use hyper::Client;
use hyper_util::rt::TokioIo;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box> {
let url = std::env::args().nth(1).ok_or("Please provide a URL")?;
let url = url.parse::()?;
let client = Client::builder().build::<_, Body>(HttpConnector::new());
let resp = client.get(url).await?;
let mut stream = "";
let mut body_bytes = Vec::new();
let mut stream = hyper::body::BodyStream::new(resp.into_body());
while let Some(chunk) = stream.next().await {
let chunk = chunk?;
body_bytes.extend_from_slice(&chunk);
}
let body_str = String::from_utf8(body_bytes)?;
println!("{}", body_str);
Ok(())
}
```
--------------------------------
### Simple "Hello World" Server
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
A minimal HTTP server that responds with "Hello World!". Demonstrates basic server setup.
```rust
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode};
use std::convert::Infallible;
async fn hello(_req: Request) -> Result, Infallible> {
Ok(Response::new(Body::from("Hello World!")))
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let addr = ([127, 0, 0, 1], 3000).into();
let make_svc = make_service_fn(|_| async {
Ok::<_, Infallible>(service_fn(hello))
});
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{{}}", addr);
server.await?;
Ok(())
}
```
--------------------------------
### TOML Dependencies for Hyper Examples
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
This TOML block lists the dependencies required to run the hyper examples. Ensure these are included in your Cargo.toml file.
```toml
[dependencies]
hyper = { version = "1", features = ["full"] }
tokio = { version = "1", features = ["full"] }
pretty_env_logger = "0.5"
http-body-util = "0.1"
bytes = "1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
form_urlencoded = "1"
http = "1"utures-util = { version = "0.3", default-features = false }
```
--------------------------------
### Build and install shared library with cargo-c
Source: https://github.com/hyperium/hyper/blob/master/capi/README.md
If you are using `cargo-c`, this command builds and installs a shared library with the unstable C API. It also enables client, HTTP/1, HTTP/2, and FFI features.
```bash
RUSTFLAGS="--cfg hyper_unstable_ffi" cargo cbuild --features client,http1,http2,ffi --release
```
--------------------------------
### JSON Client Example
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
Fetches JSON data from a URL, reads the body asynchronously, and parses it using serde. Useful for interacting with JSON APIs.
```rust
use hyper::client::HttpConnector;
use hyper::Body;
use hyper::Client;
use hyper_util::rt::TokioIo;
use serde::Deserialize;
use std::error::Error;
#[derive(Deserialize, Debug)]
struct User {
name: String,
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let url = std::env::args().nth(1).ok_or("Please provide a URL")?;
let url = url.parse::()?;
let client = Client::builder().build::<_, Body>(HttpConnector::new());
let resp = client.get(url).await?;
let body_bytes = hyper::body::to_bytes(resp.into_body()).await?;
let user: User = serde_json::from_slice(&body_bytes)?;
println!("{:?}", user);
Ok(())
}
```
--------------------------------
### Send File Server Example
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
A server that asynchronously reads files using tokio-util and sends their content back to the client. Demonstrates efficient file serving.
```rust
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode};
use tokio::fs::File;
use tokio_util::codec::{BytesCodec, FramedRead};
use std::convert::Infallible;
use std::path::PathBuf;
async fn send_file(req: Request) -> Result, Box> {
let mut path = PathBuf::from("./files");
path.push(req.uri().path().trim_start_matches('/'));
match File::open(&path).await {
Ok(file) => {
let stream = FramedRead::new(file, BytesCodec);
let body = Body::wrap_stream(stream);
Ok(Response::new(body))
}
Err(_) => {
let mut resp = Response::new(Body::from("File not found"));
*resp.status_mut() = StatusCode::NOT_FOUND;
Ok(resp)
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let addr = ([127, 0, 0, 1], 3000).into();
let make_svc = make_service_fn(|_| async {
Ok::<_, Infallible>(service_fn(send_file))
});
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{{}}", addr);
server.await?;
Ok(())
}
```
--------------------------------
### Echo Server Example
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
An echo server that reflects the POST request's body back in the response. Useful for testing request body handling.
```rust
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode};
use hyper_util::rt::TokioIo;
use std::convert::Infallible;
async fn echo(req: Request) -> Result, Infallible> {
let whole_body = hyper::body::to_bytes(req.into_body()).await?;
Ok(Response::new(Body::from(whole_body)))
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let addr = ([127, 0, 0, 1], 3000).into();
let make_svc = make_service_fn(|_| async {
Ok::<_, Infallible>(service_fn(echo))
});
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{{}}", addr);
server.await?;
Ok(())
}
```
--------------------------------
### Graceful Shutdown Server Example
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
A server configured with a connection timeout and graceful shutdown capabilities. Ensures active connections are completed before the server stops.
```rust
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode};
use std::convert::Infallible;
use std::time::Duration;
async fn hello(_req: Request) -> Result, Infallible> {
tokio::time::sleep(Duration::from_secs(5)).await;
Ok(Response::new(Body::from("Hello World!")))
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let addr = ([127, 0, 0, 1], 3000).into();
let make_svc = make_service_fn(|_| async {
Ok::<_, Infallible>(service_fn(hello))
});
let server = Server::builder(tokio::net::TcpListener::bind(addr))
.tcp_nodelay(true)
.serve(make_svc);
let server = server.with_graceful_shutdown(async {
tokio::signal::ctrl_c().await.unwrap();
});
println!("Listening on http://{{}}", addr);
server.await?;
Ok(())
}
```
--------------------------------
### Web API Server Example
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
A server composed of two services: one that uppercases POST request content, and another that calls the first service and includes its response in its own. Demonstrates service composition.
```rust
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode};
use std::convert::Infallible;
async fn uppercase_service(req: Request) -> Result, Infallible> {
let whole_body = hyper::body::to_bytes(req.into_body()).await?;
let uppercased = String::from_utf8(whole_body.to_vec()).unwrap().to_uppercase();
Ok(Response::new(Body::from(uppercased)))
}
async fn composed_service(req: Request) -> Result, Infallible> {
let resp1 = uppercase_service(req).await?;
let body1_bytes = hyper::body::to_bytes(resp1.into_body()).await?;
let body1_str = String::from_utf8(body1_bytes.to_vec()).unwrap();
Ok(Response::new(Body::from(format!("Service 1 response: {}", body1_str))))
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let addr = ([127, 0, 0, 1], 3000).into();
let make_svc = make_service_fn(|_| async {
Ok::<_, Infallible>(service_fn(composed_service))
});
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{{}}", addr);
server.await?;
Ok(())
}
```
--------------------------------
### Reverse Proxy Gateway Example
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
A server acting as a gateway (reverse proxy) that forwards requests to another service, like the 'hello' service. Demonstrates request forwarding.
```rust
use hyper::client::HttpConnector;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, Uri};
use hyper_util::client::http1;
use hyper_util::rt::TokioIo;
use std::convert::Infallible;
async fn handle_request(mut req: Request) -> Result, Box> {
let uri = req.uri().clone();
let host = uri.host().ok_or("Invalid URI")?.to_string();
let port = uri.port_u16().unwrap_or(80);
let path = uri.path();
let new_uri = format!("http://{}:{}{}", host, port, path);
*req.uri_mut() = new_uri.parse::()?;
let client = Client::new();
let resp = client.request(req).await?;
Ok(resp)
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let addr = ([127, 0, 0, 1], 3000).into();
let make_svc = make_service_fn(|_| async {
Ok::<_, Infallible>(service_fn(handle_request))
});
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{{}}", addr);
server.await?;
Ok(())
}
```
--------------------------------
### Multi-Port Server Example
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
A server that listens on two different network ports, each with its own distinct service handler. Useful for routing different types of requests to different logic.
```rust
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode};
use std::convert::Infallible;
async fn handle_port1(_req: Request) -> Result, Infallible> {
Ok(Response::new(Body::from("Hello from Port 1!")))
}
async fn handle_port2(_req: Request) -> Result, Infallible> {
Ok(Response::new(Body::from("Hello from Port 2!")))
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let addr1 = ([127, 0, 0, 1], 3000).into();
let addr2 = ([127, 0, 0, 1], 3001).into();
let make_svc1 = make_service_fn(|_| async {
Ok::<_, Infallible>(service_fn(handle_port1))
});
let make_svc2 = make_service_fn(|_| async {
Ok::<_, Infallible>(service_fn(handle_port2))
});
let server1 = Server::bind(&addr1).serve(make_svc1);
let server2 = Server::bind(&addr2).serve(make_svc2);
println!("Listening on http://{{}} and http://{{}}", addr1, addr2);
tokio::join!(server1, server2);
Ok(())
}
```
--------------------------------
### Compile hyper with unstable C API
Source: https://github.com/hyperium/hyper/blob/master/capi/README.md
Use this command to compile the hyper library with the unstable C API enabled. Ensure you have Rust 1.64.0 or later. The `--features` flag includes necessary components for client functionality and HTTP versions.
```bash
RUSTFLAGS="--cfg hyper_unstable_ffi" cargo rustc --features client,http1,http2,ffi --crate-type cdylib
```
--------------------------------
### Check Rust Code Style (Mac/Linux)
Source: https://github.com/hyperium/hyper/blob/master/docs/CODE_STYLE.md
Use this command on Mac or Linux to check the formatting of all Rust files in the project using rustfmt.
```bash
# Mac or Linux
rustfmt --check --edition 2021 $(git ls-files '*.rs')
```
--------------------------------
### Check Rust Code Style (Powershell)
Source: https://github.com/hyperium/hyper/blob/master/docs/CODE_STYLE.md
Use this Powershell command to check the formatting of all Rust files in the project using rustfmt.
```powershell
# Powershell
Get-ChildItem . -Filter "*.rs" -Recurse | foreach { rustfmt --check --edition 2021 $_.FullName }
```
--------------------------------
### Configure Rust-Analyzer for Feature Checking
Source: https://github.com/hyperium/hyper/blob/master/docs/CODE_STYLE.md
Add these settings to your VS Code `settings.json` to ensure rust-analyzer considers all project features when checking code style.
```json
{
"rust-analyzer.cargo.features": ["full"],
"rust-analyzer.check.features": ["full"]
}
```
--------------------------------
### Single-Threaded Server with !Send State
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
A server configured to run on a single thread, enabling the use of `!Send` application state like `Rc`. Useful when thread-safety is not required for state.
```rust
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode};
use std::cell::RefCell;
use std::convert::Infallible;
use std::rc::Rc;
struct AppState {
counter: RefCell,
}
struct App {
state: Rc,
}
impl Service> for App {
type Response = Response;
type Error = Infallible;
type Future = futures_util::future::Ready>;
fn call(&self, _req: Request) -> Self::Future {
let mut counter = self.state.counter.borrow_mut();
*counter += 1;
let response = Response::new(Body::from(format!("Request count: {}", *counter)));
futures_util::future::ready(Ok(response))
}
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let state = Rc::new(AppState {
counter: RefCell::new(0),
});
let make_svc = make_service_fn(move |_| {
let state = Rc::clone(&state);
async move {
Ok::<_, Infallible>(App { state })
}
});
let addr = ([127, 0 0 1], 3000).into();
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{{}}", addr);
server.await?;
Ok(())
}
```
--------------------------------
### Form Parameter Validation Server
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
A web server that accepts form data, specifically 'name' and 'number' parameters. It validates their presence and data types. Useful for handling user input.
```rust
use bytes::Bytes;
use futures_util::StreamExt;
use http::StatusCode;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
use std::collections::HashMap;
use std::convert::Infallible;
async fn handle_request(req: Request) -> Result, Infallible> {
let mut response = Response::new(Body::empty());
if req.method() == hyper::Method::POST {
let mut body = BytesMut::new();
let mut stream = req.into_body();
while let Some(chunk) = stream.next().await {
body.extend_from_slice(&chunk?);
}
let body_str = String::from_utf8(body.to_vec()).unwrap();
let params = form_urlencoded::parse(&body_str)
.into_owned()
.collect::>();
let name = params.get("name");
let number = params.get("number");
match (name, number) {
(Some(n), Some(num_str)) => {
if let Ok(num) = num_str.parse::() {
*response.status_mut() = StatusCode::OK;
*response.body_mut() = Body::from(format!("Hello, {{}}! Your number is {{}}.", n, num));
} else {
*response.status_mut() = StatusCode::BAD_REQUEST;
*response.body_mut() = Body::from("Invalid number format.");
}
}
_ => {
*response.status_mut() = StatusCode::BAD_REQUEST;
*response.body_mut() = Body::from("Missing name or number parameter.");
}
}
} else {
*response.status_mut() = StatusCode::METHOD_NOT_ALLOWED;
}
Ok(response)
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let addr = ([127, 0, 0, 1], 3000).into();
let make_svc = make_service_fn(|_| async {
Ok::<_, Infallible>(service_fn(handle_request))
});
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{{}}", addr);
server.await?;
Ok(())
}
```
--------------------------------
### HTTP/S Proxy with CONNECT Tunneling
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
A proxy server that handles HTTP and HTTPS traffic, including CONNECT requests for tunneling. It forwards data between clients and remote servers.
```rust
use hyper::client::HttpConnector;
use hyper::server::conn::AddrStream;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode, Uri};
use hyper_util::client::http1;
use hyper_util::rt::TokioIo;
use std::convert::Infallible;
use std::net::SocketAddr;
async fn handle_request(req: Request, src: SocketAddr) -> Result, Box> {
if req.method() == hyper::Method::CONNECT {
let uri = req.uri().clone();
let host_port = uri.to_string();
tokio::spawn(async move {
if let Err(e) = tunnel(host_port).await {
eprintln!("Tunnel error: {}", e);
}
});
let mut resp = Response::new(Body::empty());
*resp.status_mut() = StatusCode::OK;
return Ok(resp);
}
let url = req.uri().to_string();
let client = Client::new();
let resp = client.request(req).await?;
Ok(resp)
}
async fn tunnel(host_port: String) -> Result<(), Box> {
let mut parts = host_port.split(':');
let host = parts.next().ok_or("Invalid host")?;
let port = parts.next().ok_or("Invalid port")?.parse::()?;
let mut stream = TcpStream::connect((host, port)).await?;
let io = TokioIo::new(stream);
let (sender, conn) = hyper::server::conn::Http::new()
.serve_connection(io, service_fn(move |req| handle_request(req, src)))
.with_upgrades();
tokio::spawn(conn);
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let addr = ([127, 0, 0, 1], 3000).into();
let make_svc = make_service_fn(|conn: AddrStream| {
let src = conn.remote_addr();
async move {
Ok::<_, Infallible>(service_fn(move |req| handle_request(req, src)))
}
});
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{{}}", addr);
server.await?;
Ok(())
}
```
--------------------------------
### Manual Service Trait Implementation
Source: https://github.com/hyperium/hyper/blob/master/examples/README.md
Implements the `Service` trait manually for a struct, demonstrating how to manage shared state across requests using a counter. Useful for custom service logic.
```rust
use hyper::service::{Service, make_service_fn};
use hyper::{Body, Request, Response, Server, StatusCode};
use std::cell::RefCell;
use std::convert::Infallible;
use std::rc::Rc;
struct AppState {
counter: RefCell,
}
struct App {
state: Rc,
}
impl Service> for App {
type Response = Response;
type Error = Infallible;
type Future = futures_util::future::Ready>;
fn call(&self, _req: Request) -> Self::Future {
let mut counter = self.state.counter.borrow_mut();
*counter += 1;
let response = Response::new(Body::from(format!("Request count: {}", *counter)));
futures_util::future::ready(Ok(response))
}
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let state = Rc::new(AppState {
counter: RefCell::new(0),
});
let make_svc = make_service_fn(move |_| {
let state = Rc::clone(&state);
async move {
Ok::<_, Infallible>(App { state })
}
});
let addr = ([127, 0 0 1], 3000).into();
let server = Server::bind(&addr).serve(make_svc);
println!("Listening on http://{{}}", addr);
server.await?;
Ok(())
}
```
--------------------------------
### Commit Message Format
Source: https://github.com/hyperium/hyper/blob/master/docs/COMMITS.md
The standard format for commit messages includes a header, body, and footer. Ensure no line exceeds 100 characters.
```git
():