Skip to content

Commit

Permalink
feat: upgrade to hyper v1.0 (#96)
Browse files Browse the repository at this point in the history
* feat: upgrade to hyper v1.0

* feat(viz): add serve_with_upgrades

* feat(viz): export serve_with_upgrades

* lint: move to workspace.lints table

* lint: allow too_many_lines

* lint: allow clippy::type_complexity
  • Loading branch information
fundon authored Nov 22, 2023
1 parent e69c3e5 commit e6e8767
Show file tree
Hide file tree
Showing 33 changed files with 131 additions and 105 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@clippy
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic
- run: cargo clippy --tests

fmt:
name: Fmt
Expand Down
37 changes: 28 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ thiserror = "1.0"
path-tree = "0.7"

# http
headers = "0.3"
http = "0.2"
http-body = "=1.0.0-rc.2"
http-body-util = "=0.1.0-rc.3"
hyper = { version = "=1.0.0-rc.4", features = ["server"] }
hyper-util = { git = "https://github.com/hyperium/hyper-util", rev = "63e84bf", features = ["auto"] }
# TODO: wait headers-v1.0
headers = { git = "https://github.com/hyperium/headers.git", rev = "4400aa9" }
http = "1"
http-body = "1"
http-body-util = "0.1"
hyper = { version = "1", features = ["server"] }
hyper-util = { version = "0.1", features = ["server-auto", "tokio"] }

futures-util = "0.3"
tokio = { version = "1.33", features = ["net"] }
Expand All @@ -86,11 +87,12 @@ hex = "0.4"
rust-embed = "8"

# OpenTelemetry
opentelemetry = { version = "0.20", default-features = false }
opentelemetry-prometheus = { version = "0.13", features = [
opentelemetry = { version = "0.21", default-features = false }
opentelemetry_sdk = { version = "0.21", default-features = false }
opentelemetry-prometheus = { version = "0.14", features = [
"prometheus-encoding",
] }
opentelemetry-semantic-conventions = { version = "0.12" }
opentelemetry-semantic-conventions = { version = "0.13" }
prometheus = "0.13"

# Tracing
Expand All @@ -102,8 +104,25 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[profile.dev]
opt-level = 1
split-debuginfo = "unpacked"

[profile.dev.package."*"]
opt-level = 3
debug = false

[workspace.lints.rust]
unsafe_code = "forbid"
rust_2018_idioms = "warn"
single_use_lifetimes = "warn"
non_ascii_idents = "warn"
unreachable_pub = "warn"
missing_debug_implementations = "warn"
missing_docs = "warn"

[workspace.lints.clippy]
all = "deny"
pedantic = "deny"
module_name_repetitions = { level = "allow", priority = 1 }
too_many_lines = { level = "allow", priority = 1 }
type_complexity = { level = "allow", priority = 1 }
3 changes: 2 additions & 1 deletion clippy.toml
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
msrv = "1.64"
# Clippy configuration
# https://doc.rust-lang.org/nightly/clippy/lint_configuration.html
3 changes: 2 additions & 1 deletion examples/otel/metrics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ publish = false
viz = { workspace = true, features = ["otel-metrics", "otel-prometheus"] }

tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
opentelemetry = { workspace = true, default-features = false, features = ["metrics"]}
opentelemetry = { workspace = true, features = ["metrics"]}
opentelemetry_sdk = { workspace = true, features = ["metrics"] }
11 changes: 4 additions & 7 deletions examples/otel/metrics/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@
use std::{net::SocketAddr, sync::Arc};
use tokio::net::TcpListener;

use opentelemetry::{
global,
sdk::{
metrics::{self, Aggregation, Instrument, MeterProvider, Stream},
Resource,
},
KeyValue,
use opentelemetry::{global, KeyValue};
use opentelemetry_sdk::{
metrics::{self, Aggregation, Instrument, MeterProvider, Stream},
Resource,
};

use viz::{
Expand Down
3 changes: 2 additions & 1 deletion examples/otel/tracing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ viz = { workspace = true, features = ["otel-tracing"] }

tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
opentelemetry.workspace = true
opentelemetry-jaeger = { version = "0.19.0", features = ["rt-tokio-current-thread"]}
opentelemetry_sdk = { workspace = true, features = ["trace", "rt-tokio-current-thread"] }
opentelemetry-jaeger = { version = "0.20", features = ["rt-tokio-current-thread"]}
6 changes: 3 additions & 3 deletions examples/otel/tracing/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#![deny(warnings)]
#![allow(clippy::unused_async)]

use opentelemetry::{
global,
use opentelemetry::global;
use opentelemetry_sdk::{
runtime::TokioCurrentThread,
sdk::{propagation::TraceContextPropagator, trace::Tracer},
{propagation::TraceContextPropagator, trace::Tracer},
};
use std::{net::SocketAddr, sync::Arc};
use tokio::net::TcpListener;
Expand Down
4 changes: 2 additions & 2 deletions examples/routing/openapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }

utoipa = "4.0"
utoipa-swagger-ui = "4.0"
utoipa = "4"
utoipa-swagger-ui = "4"
2 changes: 1 addition & 1 deletion examples/templates/markup/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ viz.workspace = true

tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }

markup = "0.13"
markup = "0.14"
v_htmlescape = "0.15"
2 changes: 2 additions & 0 deletions examples/templates/markup/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![deny(warnings)]
#![allow(clippy::unused_async)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::inherent_to_string_shadow_display)]

use std::{net::SocketAddr, sync::Arc};
use tokio::net::TcpListener;
Expand Down
4 changes: 2 additions & 2 deletions examples/websocket-chat/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{net::SocketAddr, sync::Arc};
use tokio::net::TcpListener;
use tokio::sync::broadcast::{channel, Sender};
use viz::{
get, serve,
get, serve_with_upgrades,
types::{Message, Params, State, WebSocket},
HandlerExt, IntoHandler, IntoResponse, Request, RequestExt, Response, ResponseExt, Result,
Router, Tree,
Expand Down Expand Up @@ -67,7 +67,7 @@ async fn main() -> Result<()> {
let (stream, addr) = listener.accept().await?;
let tree = tree.clone();
tokio::task::spawn(async move {
if let Err(err) = serve(stream, tree, Some(addr)).await {
if let Err(err) = serve_with_upgrades(stream, tree, Some(addr)).await {
eprintln!("Error while serving HTTP connection: {err}");
}
});
Expand Down
5 changes: 4 additions & 1 deletion viz-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ thiserror.workspace = true

rfc7239 = "0.1" # realip
cookie = { version = "0.18", features = ["percent-encode"], optional = true }
form-data = { version = "0.5.0-rc.2", optional = true }
form-data = { version = "0.5.0", optional = true }
serde = { workspace = true, features = ["derive"], optional = true }
serde_json = { workspace = true, optional = true }
serde_urlencoded = { workspace = true, optional = true }
Expand Down Expand Up @@ -105,3 +105,6 @@ tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[lints]
workspace = true
8 changes: 0 additions & 8 deletions viz-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,6 @@
#![doc(html_logo_url = "https://viz.rs/logo.svg")]
#![doc(html_favicon_url = "https://viz.rs/logo.svg")]
#![allow(clippy::module_name_repetitions)]
#![forbid(unsafe_code)]
#![warn(
missing_debug_implementations,
missing_docs,
rust_2018_idioms,
unreachable_pub
)]
#![doc(test(
no_crate_inject,
attr(
Expand Down
2 changes: 0 additions & 2 deletions viz-core/src/middleware/cors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ pub struct Config {
allow_headers: HashSet<HeaderName>,
allow_origins: HashSet<HeaderValue>,
expose_headers: HashSet<HeaderName>,
#[allow(clippy::type_complexity)]
origin_verify: Option<Arc<dyn Fn(&HeaderValue) -> bool + Send + Sync>>,
}

Expand Down Expand Up @@ -118,7 +117,6 @@ impl Config {
}

/// A function to verify the origin. If the function returns false, the request will be rejected.
#[allow(clippy::type_complexity)]
#[must_use]
pub fn origin_verify(
mut self,
Expand Down
49 changes: 25 additions & 24 deletions viz-core/src/middleware/otel/tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ use http::uri::Scheme;
use opentelemetry::{
global,
propagation::Extractor,
trace::{
FutureExt as OtelFutureExt, OrderMap, Span, SpanKind, Status, TraceContextExt, Tracer,
},
Context, Key, Value,
trace::{FutureExt as OtelFutureExt, Span, SpanKind, Status, TraceContextExt, Tracer},
Context, KeyValue,
};
use opentelemetry_semantic_conventions::trace::{
CLIENT_ADDRESS, CLIENT_SOCKET_ADDRESS, EXCEPTION_MESSAGE, HTTP_REQUEST_BODY_SIZE,
Expand Down Expand Up @@ -82,7 +80,7 @@ where
.tracer
.span_builder(format!("{} {}", req.method(), http_route))
.with_kind(SpanKind::Server)
.with_attributes_map(attributes)
.with_attributes(attributes)
.start_with_context(&*self.tracer, &parent_context);

span.add_event("request.started".to_string(), vec![]);
Expand Down Expand Up @@ -143,7 +141,7 @@ impl<'a> RequestHeaderCarrier<'a> {
}
}

impl<'a> Extractor for RequestHeaderCarrier<'a> {
impl Extractor for RequestHeaderCarrier<'_> {
fn get(&self, key: &str) -> Option<&str> {
self.headers.get(key).and_then(|v| v.to_str().ok())
}
Expand All @@ -153,70 +151,73 @@ impl<'a> Extractor for RequestHeaderCarrier<'a> {
}
}

fn build_attributes(req: &Request, http_route: &str) -> OrderMap<Key, Value> {
let mut attributes = OrderMap::<Key, Value>::with_capacity(10);
fn build_attributes(req: &Request, http_route: &str) -> Vec<KeyValue> {
let mut attributes = Vec::with_capacity(10);
// <https://github.com/open-telemetry/semantic-conventions/blob/v1.21.0/docs/http/http-spans.md#http-server>
attributes.insert(HTTP_ROUTE, http_route.to_string().into());
attributes.push(KeyValue::new(HTTP_ROUTE, http_route.to_string()));

// <https://github.com/open-telemetry/semantic-conventions/blob/v1.21.0/docs/http/http-spans.md#common-attributes>
attributes.insert(HTTP_REQUEST_METHOD, req.method().to_string().into());
attributes.insert(
attributes.push(KeyValue::new(HTTP_REQUEST_METHOD, req.method().to_string()));
attributes.push(KeyValue::new(
NETWORK_PROTOCOL_VERSION,
format!("{:?}", req.version()).into(),
);
format!("{:?}", req.version()),
));

let remote_addr = req.remote_addr();
if let Some(remote_addr) = remote_addr {
attributes.insert(CLIENT_ADDRESS, remote_addr.to_string().into());
attributes.push(KeyValue::new(CLIENT_ADDRESS, remote_addr.to_string()));
}
if let Some(realip) = req.realip().map(|value| value.0).filter(|realip| {
remote_addr
.map(SocketAddr::ip)
.map_or(true, |remoteip| &remoteip != realip)
}) {
attributes.insert(CLIENT_SOCKET_ADDRESS, realip.to_string().into());
attributes.push(KeyValue::new(CLIENT_SOCKET_ADDRESS, realip.to_string()));
}

let uri = req.uri();
if let Some(host) = uri.host() {
attributes.insert(SERVER_ADDRESS, host.to_string().into());
attributes.push(KeyValue::new(SERVER_ADDRESS, host.to_string()));
}
if let Some(port) = uri
.port_u16()
.map(i64::from)
.filter(|port| *port != 80 && *port != 443)
{
attributes.insert(SERVER_PORT, port.into());
attributes.push(KeyValue::new(SERVER_PORT, port.to_string()));
}

if let Some(path_query) = uri.path_and_query() {
if path_query.path() != "/" {
attributes.insert(URL_PATH, path_query.path().to_string().into());
attributes.push(KeyValue::new(URL_PATH, path_query.path().to_string()));
}
if let Some(query) = path_query.query() {
attributes.insert(URL_QUERY, query.to_string().into());
attributes.push(KeyValue::new(URL_QUERY, query.to_string()));
}
}

attributes.insert(
attributes.push(KeyValue::new(
URL_SCHEME,
uri.scheme().unwrap_or(&Scheme::HTTP).to_string().into(),
);
uri.scheme().unwrap_or(&Scheme::HTTP).to_string(),
));

if let Some(content_length) = req
.content_length()
.and_then(|len| i64::try_from(len).ok())
.filter(|len| *len > 0)
{
attributes.insert(HTTP_REQUEST_BODY_SIZE, content_length.into());
attributes.push(KeyValue::new(
HTTP_REQUEST_BODY_SIZE,
content_length.to_string(),
));
}

if let Some(user_agent) = req
.header_typed::<UserAgent>()
.as_ref()
.map(UserAgent::as_str)
{
attributes.insert(USER_AGENT_ORIGINAL, user_agent.to_string().into());
attributes.push(KeyValue::new(USER_AGENT_ORIGINAL, user_agent.to_string()));
}

attributes
Expand Down
1 change: 0 additions & 1 deletion viz-core/tests/handler.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#![allow(dead_code)]
#![allow(clippy::unused_async)]
#![allow(clippy::similar_names)]
#![allow(clippy::too_many_lines)]
#![allow(clippy::wildcard_imports)]

use http_body_util::Full;
Expand Down
21 changes: 17 additions & 4 deletions viz-core/tests/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@ use headers::{authorization::Bearer, Authorization, ContentType, HeaderValue};
use http::uri::Scheme;
use serde::{Deserialize, Serialize};
use viz_core::{
header::{AUTHORIZATION, CONTENT_TYPE, COOKIE, SET_COOKIE},
// TODO: reqwest and hyper haven't used the same version of `http`.
// header::{AUTHORIZATION, CONTENT_TYPE, COOKIE, SET_COOKIE},
// StatusCode,
header::CONTENT_TYPE,
types::{self, PayloadError},
Error, IncomingBody, IntoResponse, Request, RequestExt, Response, ResponseExt, Result,
StatusCode,
Error,
IncomingBody,
IntoResponse,
Request,
RequestExt,
Response,
ResponseExt,
Result,
};

#[derive(Debug, Deserialize, Serialize, PartialEq)]
Expand Down Expand Up @@ -62,14 +71,17 @@ fn request_ext() -> Result<()> {
Ok(())
}

#[allow(clippy::too_many_lines)]
#[tokio::test]
async fn request_body() -> Result<()> {
use futures_util::stream::TryStreamExt;
use viz::{
middleware::{cookie, limits},
Router,
};
use viz_test::http::{
header::{AUTHORIZATION, COOKIE},
StatusCode,
};
use viz_test::TestServer;

let router = Router::new()
Expand Down Expand Up @@ -300,6 +312,7 @@ async fn request_session() -> Result<()> {
middleware::{cookie, helper::CookieOptions, session},
Router,
};
use viz_test::http::header::{COOKIE, SET_COOKIE};
use viz_test::{nano_id, sessions, TestServer};

let router = Router::new()
Expand Down
Loading

0 comments on commit e6e8767

Please sign in to comment.