From 88e26bab2434fb36f6bab4b44c479f9d22a3e622 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Tue, 12 Dec 2023 15:55:57 +0100 Subject: [PATCH 01/12] build: Update axum and http --- Cargo.lock | 277 ++++++++++++------ relay-log/Cargo.toml | 11 +- relay-server/Cargo.toml | 11 +- relay-server/src/actors/server.rs | 7 +- relay-server/src/endpoints/attachments.rs | 8 +- relay-server/src/endpoints/envelope.rs | 19 +- relay-server/src/endpoints/forward.rs | 32 +- relay-server/src/endpoints/minidump.rs | 21 +- relay-server/src/endpoints/mod.rs | 8 +- relay-server/src/endpoints/monitor.rs | 25 +- relay-server/src/endpoints/nel.rs | 7 +- relay-server/src/endpoints/project_configs.rs | 10 +- relay-server/src/endpoints/security_report.rs | 7 +- relay-server/src/endpoints/spans.rs | 8 +- relay-server/src/endpoints/store.rs | 7 +- relay-server/src/endpoints/unreal.rs | 7 +- relay-server/src/extractors/signed_json.rs | 14 +- relay-server/src/middlewares/metrics.rs | 8 +- relay-server/src/utils/multipart.rs | 5 +- 19 files changed, 256 insertions(+), 236 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a09ad24ca7f..d51fa84dbd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,6 +206,19 @@ name = "async-compression" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" +dependencies = [ + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-compression" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc2d0cfb2a7388d34f590e76686704c494ed7aaceed62ee1ba35cbf363abc2a5" dependencies = [ "brotli", "flate2", @@ -243,21 +256,21 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.20" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +checksum = "202651474fe73c62d9e0a56c6133f7a0ff1dc1c8cf7a5b03381af2a26553ac9d" dependencies = [ "async-trait", "axum-core", "axum-macros", "base64 0.21.0", - "bitflags 1.3.2", "bytes", "futures-util", - "headers", - "http", - "http-body", - "hyper", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.0.1", + "hyper-util", "itoa", "matchit", "memchr", @@ -282,17 +295,20 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +checksum = "77cb22c689c44d4c07b0ab44ebc25d69d8ae601a2f28fb8d672d344178fa17aa" dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", "mime", + "pin-project-lite", "rustversion", + "sync_wrapper", "tower-layer", "tower-service", "tracing", @@ -300,9 +316,9 @@ dependencies = [ [[package]] name = "axum-macros" -version = "0.3.8" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62" +checksum = "5a2edad600410b905404c594e2523549f1bcd4bded1e252c8f74524ccce0b867" dependencies = [ "heck", "proc-macro2", @@ -312,15 +328,15 @@ dependencies = [ [[package]] name = "axum-server" -version = "0.4.7" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bace45b270e36e3c27a190c65883de6dfc9f1d18c829907c127464815dc67b24" +checksum = "447f28c85900215cc1bea282f32d4a2f22d55c5a300afdfbc661c8d6a632e063" dependencies = [ "bytes", "futures-util", - "http", - "http-body", - "hyper", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.26", "tokio", "tower-service", ] @@ -507,9 +523,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" dependencies = [ "serde", ] @@ -1704,7 +1720,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils 0.1.7", - "http", + "http 0.2.9", "js-sys", "pin-project", "serde", @@ -1725,7 +1741,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils 0.2.0", - "http", + "http 0.2.9", "js-sys", "pin-project", "serde", @@ -1827,7 +1843,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", "indexmap 1.9.2", "slab", "tokio", @@ -1835,6 +1851,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "h2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d308f63daf4181410c242d34c11f928dcb3aa105852019e043c9d1f4e4368a" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 1.0.0", + "indexmap 2.0.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "1.8.2" @@ -1883,31 +1918,6 @@ dependencies = [ "hashbrown 0.12.3", ] -[[package]] -name = "headers" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" -dependencies = [ - "base64 0.13.1", - "bitflags 1.3.2", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] - [[package]] name = "heck" version = "0.4.1" @@ -1987,6 +1997,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -1994,15 +2015,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", + "http 0.2.9", "pin-project-lite", ] [[package]] -name = "http-range-header" -version = "0.3.0" +name = "http-body" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.0.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "pin-project-lite", +] [[package]] name = "httparse" @@ -2032,9 +2070,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.17", + "http 0.2.9", + "http-body 0.4.5", "httparse", "httpdate", "itoa", @@ -2046,6 +2084,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.0", + "http 1.0.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "tokio", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -2053,12 +2110,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.26", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "hyper 1.0.1", + "pin-project-lite", + "socket2 0.5.3", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.53" @@ -2592,7 +2669,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 0.2.9", "httparse", "log", "memchr", @@ -3494,7 +3571,7 @@ dependencies = [ "once_cell", "parking_lot", "regex", - "sentry-types", + "sentry-types 0.31.8", "serde", "serde_test", ] @@ -4032,16 +4109,16 @@ version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" dependencies = [ - "async-compression", + "async-compression 0.3.15", "base64 0.21.0", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.17", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.26", "hyper-tls", "ipnet", "js-sys", @@ -4358,9 +4435,9 @@ checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" [[package]] name = "sentry" -version = "0.31.7" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0097a48cd1999d983909f07cb03b15241c5af29e5e679379efac1c06296abecc" +checksum = "9b596ee5f4e76638de6063ca96fd3d923675416461fc7f1b77406dc2f32d1979" dependencies = [ "httpdate", "native-tls", @@ -4378,9 +4455,9 @@ dependencies = [ [[package]] name = "sentry-backtrace" -version = "0.31.7" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a7b80fa1dd6830a348d38a8d3a9761179047757b7dca29aef82db0118b9670" +checksum = "e6510a97162c288989a6310766bcadfc83ec98ad73121674463b055c42189e85" dependencies = [ "backtrace", "once_cell", @@ -4390,9 +4467,9 @@ dependencies = [ [[package]] name = "sentry-contexts" -version = "0.31.7" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7615dc588930f1fd2e721774f25844ae93add2dbe2d3c2f995ce5049af898147" +checksum = "64e2552a4a578aade01bd44691e6805c32bac34fc918f1675739fbbf2add8460" dependencies = [ "hostname", "libc", @@ -4404,22 +4481,22 @@ dependencies = [ [[package]] name = "sentry-core" -version = "0.31.7" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f51264e4013ed9b16558cce43917b983fa38170de2ca480349ceb57d71d6053" +checksum = "ebb7a6ad833035f6b36db3e61e450643eec8a3c5f2839b8e41c74a73e57c6bae" dependencies = [ "once_cell", "rand", - "sentry-types", + "sentry-types 0.32.0", "serde", "serde_json", ] [[package]] name = "sentry-debug-images" -version = "0.31.7" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fe6180fa564d40bb942c9f0084ffb5de691c7357ead6a2b7a3154fae9e401dd" +checksum = "0bcd02214397892a3ec25372cc68c210d858f39314535f5d640bdf41294fd441" dependencies = [ "findshlibs", "once_cell", @@ -4439,9 +4516,9 @@ dependencies = [ [[package]] name = "sentry-panic" -version = "0.31.7" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "323160213bba549f9737317b152af116af35c0410f4468772ee9b606d3d6e0fa" +checksum = "0866e2ba7615fe37e0e485f2373bf9dabbb255f82637b5fe47902095790bbbc9" dependencies = [ "sentry-backtrace", "sentry-core", @@ -4460,12 +4537,12 @@ dependencies = [ [[package]] name = "sentry-tower" -version = "0.31.7" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffe3ab7bf7f65c9f8ccd20aa136ce5b2140aa6d6a11339e823cd43a7d694a9e" +checksum = "e275f07e9e7d9cf3b85130ab6893a9790c3ab2d8fedca29215aeafad0539c4f4" dependencies = [ "axum", - "http", + "http 1.0.0", "pin-project", "sentry-core", "tower-layer", @@ -4475,9 +4552,9 @@ dependencies = [ [[package]] name = "sentry-tracing" -version = "0.31.7" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38033822128e73f7b6ca74c1631cef8868890c6cb4008a291cf73530f87b4eac" +checksum = "53ef38653386354058f30b3c6d0bf764c59ee6270cd769ac4620a2d2fd60c8fe" dependencies = [ "sentry-backtrace", "sentry-core", @@ -4487,9 +4564,26 @@ dependencies = [ [[package]] name = "sentry-types" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e663b3eb62ddfc023c9cf5432daf5f1a4f6acb1df4d78dd80b740b32dd1a740" +checksum = "da956cca56e0101998c8688bc65ce1a96f00673a0e58e663664023d4c7911e82" +dependencies = [ + "debugid", + "hex", + "rand", + "serde", + "serde_json", + "thiserror", + "time", + "url", + "uuid", +] + +[[package]] +name = "sentry-types" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26342e85c6b3332273b820d5be6b93027fe991ded23a2aa6fb88a5a28c845c40" dependencies = [ "debugid", "hex", @@ -5382,18 +5476,17 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658" +checksum = "09e12e6351354851911bdf8c2b8f2ab15050c567d70a8b9a37ae7b8301a4080d" dependencies = [ - "async-compression", - "bitflags 1.3.2", + "async-compression 0.4.5", + "bitflags 2.4.1", "bytes", - "futures-core", "futures-util", - "http", - "http-body", - "http-range-header", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", "pin-project-lite", "tokio", "tokio-util", @@ -5551,7 +5644,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.9", "httparse", "log", "rand", diff --git a/relay-log/Cargo.toml b/relay-log/Cargo.toml index fd7844b6332..65d4c442a42 100644 --- a/relay-log/Cargo.toml +++ b/relay-log/Cargo.toml @@ -15,12 +15,19 @@ chrono = { workspace = true, features = ["clock"], optional = true } console = { version = "0.15.5", optional = true } once_cell = { version = "1.13.1", optional = true } relay-crash = { path = "../relay-crash", optional = true } -sentry = { version = "0.31.7", features = [ +sentry = { version = "0.32.0", features = [ "debug-images", "tower-axum-matched-path", "tracing", ], optional = true } -sentry-core = { version = "0.31.7" } +sentry-core = { version = "0.32.0" } +# sentry = { git = "https://github.com/getsentry/sentry-rust", rev = "139cdf3922e31b53f5256fd14a590e61ee6dc240", features = [ +# "debug-images", +# "tower-axum-matched-path", +# "tracing", +# "UNSTABLE_metrics", +# ], optional = true } +# sentry-core = { git = "https://github.com/getsentry/sentry-rust", rev = "139cdf3922e31b53f5256fd14a590e61ee6dc240" } tokio = { version = "1", default-features = false, features = [ "sync", ], optional = true } diff --git a/relay-server/Cargo.toml b/relay-server/Cargo.toml index 0bd96cec852..2cc28bf4f46 100644 --- a/relay-server/Cargo.toml +++ b/relay-server/Cargo.toml @@ -34,18 +34,17 @@ processing = [ [dependencies] anyhow = { workspace = true } -axum = { version = "0.6.20", features = [ - "headers", +axum = { version = "0.7.2", features = [ "macros", "matched-path", "multipart", "tracing", ] } -axum-server = "0.4.7" +axum-server = "0.5.1" backoff = "0.4.0" brotli = "3.3.4" bytecount = "0.6.0" -bytes = { version = "1.4.0" } +bytes = { version = "1.5.0" } chrono = { workspace = true, features = ["clock"] } data-encoding = "2.3.3" flate2 = "1.0.19" @@ -93,7 +92,7 @@ rmp-serde = "1.1.1" rust-embed = { version = "8.0.0", optional = true } serde = { workspace = true } serde_json = { workspace = true } -smallvec = { workspace = true, features = ["drain_filter"] } +smallvec = { workspace = true, features = ["drain_filter"] } sqlx = { version = "0.7.0", features = [ "macros", "migrate", @@ -107,7 +106,7 @@ symbolic-unreal = { version = "12.1.2", optional = true, default-features = fals thiserror = { workspace = true } tokio = { workspace = true, features = ["rt-multi-thread"] } tower = { version = "0.4.13", default-features = false } -tower-http = { version = "0.4.0", default-features = false, features = [ +tower-http = { version = "0.5.0", default-features = false, features = [ "catch-panic", "cors", "decompression-br", diff --git a/relay-server/src/actors/server.rs b/relay-server/src/actors/server.rs index 1613672e940..cbf3fa72d1a 100644 --- a/relay-server/src/actors/server.rs +++ b/relay-server/src/actors/server.rs @@ -82,9 +82,10 @@ impl Service for HttpServer { .layer(NewSentryLayer::new_from_top()) .layer(SentryHttpLayer::with_transaction()) .layer(middlewares::trace_http_layer()) - .layer(HandleErrorLayer::new(middlewares::decompression_error)) - .map_request(middlewares::remove_empty_encoding) - .layer(RequestDecompressionLayer::new()); + // .layer(HandleErrorLayer::new(middlewares::decompression_error)) + // .map_request(middlewares::remove_empty_encoding) + // .layer(RequestDecompressionLayer::new()); + ; let router = crate::endpoints::routes(service.config()) .layer(middleware) diff --git a/relay-server/src/endpoints/attachments.rs b/relay-server/src/endpoints/attachments.rs index dff9dcdd689..b112ab113fa 100644 --- a/relay-server/src/endpoints/attachments.rs +++ b/relay-server/src/endpoints/attachments.rs @@ -2,7 +2,6 @@ use axum::extract::{DefaultBodyLimit, Multipart, Path}; use axum::http::StatusCode; use axum::response::IntoResponse; use axum::routing::{post, MethodRouter}; -use bytes::Bytes; use relay_config::Config; use relay_event_schema::protocol::EventId; use serde::Deserialize; @@ -45,11 +44,6 @@ async fn handle( Ok(StatusCode::CREATED) } -pub fn route(config: &Config) -> MethodRouter -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send + Into, - B::Error: Into, -{ +pub fn route(config: &Config) -> MethodRouter { post(handle).route_layer(DefaultBodyLimit::max(config.max_attachments_size())) } diff --git a/relay-server/src/endpoints/envelope.rs b/relay-server/src/endpoints/envelope.rs index 47e38c09547..287b9909c56 100644 --- a/relay-server/src/endpoints/envelope.rs +++ b/relay-server/src/endpoints/envelope.rs @@ -3,8 +3,7 @@ use std::convert::Infallible; use axum::extract::rejection::BytesRejection; -use axum::extract::{DefaultBodyLimit, FromRequest}; -use axum::http::Request; +use axum::extract::{DefaultBodyLimit, FromRequest, Request}; use axum::response::IntoResponse; use axum::routing::{post, MethodRouter}; use axum::{Json, RequestExt}; @@ -71,16 +70,11 @@ impl EnvelopeParams { } #[axum::async_trait] -impl FromRequest for EnvelopeParams -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send, - B::Error: Into, -{ +impl FromRequest for EnvelopeParams { type Rejection = BadEnvelopeParams; async fn from_request( - mut request: Request, + mut request: Request, state: &ServiceState, ) -> Result { let result = request.extract_parts_with_state(state).await; @@ -125,11 +119,6 @@ async fn handle( Ok(Json(StoreResponse { id })) } -pub fn route(config: &Config) -> MethodRouter -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send, - B::Error: Into, -{ +pub fn route(config: &Config) -> MethodRouter { post(handle).route_layer(DefaultBodyLimit::max(config.max_envelope_size())) } diff --git a/relay-server/src/endpoints/forward.rs b/relay-server/src/endpoints/forward.rs index 2030022574e..2c3d8b3fa5b 100644 --- a/relay-server/src/endpoints/forward.rs +++ b/relay-server/src/endpoints/forward.rs @@ -9,9 +9,9 @@ use std::fmt; use std::future::Future; use std::pin::Pin; -use axum::extract::DefaultBodyLimit; +use axum::extract::{DefaultBodyLimit, Request}; use axum::handler::Handler; -use axum::http::{header, HeaderMap, HeaderName, HeaderValue, Request, StatusCode, Uri}; +use axum::http::{header, HeaderMap, HeaderName, HeaderValue, StatusCode, Uri}; use axum::response::{IntoResponse, Response}; use bytes::Bytes; use once_cell::sync::Lazy; @@ -46,6 +46,14 @@ static IGNORED_REQUEST_HEADERS: &[HeaderName] = &[ /// Root path of all API endpoints. const API_PATH: &str = "/api/"; +fn status_to_1(status: reqwest::StatusCode) -> StatusCode { + StatusCode::from_u16(status.as_u16()).unwrap() +} + +fn status_to_1_opt(status: Option) -> Option { + Some(StatusCode::from_u16(status?.as_u16()).unwrap()) +} + /// A wrapper struct that allows conversion of UpstreamRequestError into a `dyn ResponseError`. The /// conversion logic is really only acceptable for blindly forwarded requests. #[derive(Debug, thiserror::Error)] @@ -65,8 +73,7 @@ impl IntoResponse for ForwardError { HttpError::Overflow => StatusCode::PAYLOAD_TOO_LARGE.into_response(), HttpError::Reqwest(error) => { relay_log::error!(error = error as &dyn Error); - error - .status() + status_to_1_opt(error.status()) .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR) .into_response() } @@ -162,12 +169,18 @@ impl UpstreamRequest for ForwardRequest { Box::pin(async move { let result = match result { Ok(response) => { - let status = response.status(); + let status = status_to_1(response.status()); let headers = response .headers() .iter() .filter(|(name, _)| !HOP_BY_HOP_HEADERS.contains(name)) - .map(|(name, value)| (name.clone(), value.clone())) + .map(|(name, value)| { + ( + // TODO: Undo this once reqwest is updated + name.as_str().parse().unwrap(), + value.as_str().parse().unwrap(), + ) + }) .collect(); match response.bytes(self.max_response_size).await { @@ -268,12 +281,7 @@ fn get_limit_for_path(path: &str, config: &Config) -> usize { /// /// - Use it as [`Handler`] directly in router methods when registering this as a route. /// - Call this manually from other request handlers to conditionally forward from other endpoints. -pub fn forward(state: ServiceState, req: Request) -> impl Future -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send, - B::Error: Into, -{ +pub fn forward(state: ServiceState, req: Request) -> impl Future { let limit = get_limit_for_path(req.uri().path(), state.config()); handle.layer(DefaultBodyLimit::max(limit)).call(req, state) } diff --git a/relay-server/src/endpoints/minidump.rs b/relay-server/src/endpoints/minidump.rs index 0d2d7ea875c..a91f7410723 100644 --- a/relay-server/src/endpoints/minidump.rs +++ b/relay-server/src/endpoints/minidump.rs @@ -1,7 +1,6 @@ use std::convert::Infallible; -use axum::extract::{DefaultBodyLimit, Multipart}; -use axum::http::Request; +use axum::extract::{DefaultBodyLimit, Multipart, Request}; use axum::response::IntoResponse; use axum::routing::{post, MethodRouter}; use axum::RequestExt; @@ -126,17 +125,12 @@ fn extract_raw_minidump(data: Bytes, meta: RequestMeta) -> Result, Ok(envelope) } -async fn handle( +async fn handle( state: ServiceState, meta: RequestMeta, content_type: RawContentType, - request: Request, -) -> axum::response::Result -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send + Into, - B::Error: Into, -{ + request: Request, +) -> axum::response::Result { // The minidump can either be transmitted as the request body, or as // `upload_file_minidump` in a multipart form-data/ request. // Minidump request payloads do not have the same structure as usual events from other SDKs. The @@ -161,12 +155,7 @@ where Ok(TextResponse(id)) } -pub fn route(config: &Config) -> MethodRouter -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send + Into, - B::Error: Into, -{ +pub fn route(config: &Config) -> MethodRouter { post(handle).route_layer(DefaultBodyLimit::max(config.max_attachments_size())) } diff --git a/relay-server/src/endpoints/mod.rs b/relay-server/src/endpoints/mod.rs index 462914ad136..a00687e9a3e 100644 --- a/relay-server/src/endpoints/mod.rs +++ b/relay-server/src/endpoints/mod.rs @@ -29,19 +29,13 @@ mod unreal; use axum::extract::DefaultBodyLimit; use axum::routing::{any, get, post, Router}; -use bytes::Bytes; use relay_config::Config; use crate::middlewares; use crate::service::ServiceState; #[rustfmt::skip] -pub fn routes(config: &Config) -> Router -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send + Into, - B::Error: Into, -{ +pub fn routes(config: &Config) -> Router { #[cfg(feature = "dashboard")] let dashboard = Router::new().route("/dashboard/",get(dashboard::index_handle)) .route("/dashboard/*file", get(dashboard::handle)); diff --git a/relay-server/src/endpoints/monitor.rs b/relay-server/src/endpoints/monitor.rs index 0364cff8307..3c52ee20b01 100644 --- a/relay-server/src/endpoints/monitor.rs +++ b/relay-server/src/endpoints/monitor.rs @@ -1,9 +1,8 @@ -use axum::extract::{DefaultBodyLimit, Path, Query}; -use axum::http::{Request, StatusCode}; +use axum::extract::{DefaultBodyLimit, Path, Query, Request}; +use axum::http::StatusCode; use axum::response::IntoResponse; use axum::routing::{on, MethodFilter, MethodRouter}; use axum::{Json, RequestExt}; -use bytes::Bytes; use relay_config::Config; use relay_event_schema::protocol::EventId; use relay_monitors::{CheckIn, CheckInStatus}; @@ -28,18 +27,13 @@ struct MonitorQuery { duration: Option, } -async fn handle( +async fn handle( state: ServiceState, content_type: RawContentType, meta: RequestMeta, Path(path): Path, - request: Request, -) -> axum::response::Result -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send + Into, - B::Error: Into, -{ + request: Request, +) -> axum::response::Result { let check_in = if content_type.as_ref().starts_with("application/json") { let Json(mut check_in): Json = request.extract().await?; check_in.monitor_slug = path.monitor_slug; @@ -74,12 +68,7 @@ where Ok(StatusCode::ACCEPTED) } -pub fn route(config: &Config) -> MethodRouter -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send + Into, - B::Error: Into, -{ - on(MethodFilter::GET | MethodFilter::POST, handle) +pub fn route(config: &Config) -> MethodRouter { + on(MethodFilter::GET.or(MethodFilter::POST), handle) .route_layer(DefaultBodyLimit::max(config.max_event_size())) } diff --git a/relay-server/src/endpoints/nel.rs b/relay-server/src/endpoints/nel.rs index 28aabb4e9ce..dbecf449649 100644 --- a/relay-server/src/endpoints/nel.rs +++ b/relay-server/src/endpoints/nel.rs @@ -59,11 +59,6 @@ async fn handle( Ok(().into_response()) } -pub fn route(config: &Config) -> MethodRouter -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send, - B::Error: Into, -{ +pub fn route(config: &Config) -> MethodRouter { post(handle).route_layer(DefaultBodyLimit::max(config.max_event_size())) } diff --git a/relay-server/src/endpoints/project_configs.rs b/relay-server/src/endpoints/project_configs.rs index 76901497cc6..0cab73c0590 100644 --- a/relay-server/src/endpoints/project_configs.rs +++ b/relay-server/src/endpoints/project_configs.rs @@ -1,9 +1,8 @@ use std::collections::HashMap; use std::sync::Arc; -use axum::extract::Query; +use axum::extract::{Query, Request}; use axum::handler::Handler; -use axum::http::Request; use axum::response::{IntoResponse, Result}; use axum::{Json, RequestExt}; use futures::future; @@ -196,12 +195,7 @@ fn is_compatible(Query(query): Query) -> bool { /// Relays can drop compatibility with old versions of the project config endpoint, for instance the /// initial version 1. However, Sentry's HTTP endpoint will retain compatibility for much longer to /// support old Relay versions. -pub async fn handle(state: ServiceState, mut req: Request) -> Result -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send, - B::Error: Into, -{ +pub async fn handle(state: ServiceState, mut req: Request) -> Result { let data = req.extract_parts().await?; Ok(if is_compatible(data) { inner.call(req, state).await diff --git a/relay-server/src/endpoints/security_report.rs b/relay-server/src/endpoints/security_report.rs index e402ca07f33..3bfa52a042f 100644 --- a/relay-server/src/endpoints/security_report.rs +++ b/relay-server/src/endpoints/security_report.rs @@ -87,11 +87,6 @@ async fn handle( Ok(().into_response()) } -pub fn route(config: &Config) -> MethodRouter -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send, - B::Error: Into, -{ +pub fn route(config: &Config) -> MethodRouter { post(handle).route_layer(DefaultBodyLimit::max(config.max_event_size())) } diff --git a/relay-server/src/endpoints/spans.rs b/relay-server/src/endpoints/spans.rs index ed478bc0ba9..2a677e941ac 100644 --- a/relay-server/src/endpoints/spans.rs +++ b/relay-server/src/endpoints/spans.rs @@ -2,7 +2,6 @@ use axum::extract::{DefaultBodyLimit, Json}; use axum::http::StatusCode; use axum::response::IntoResponse; use axum::routing::{post, MethodRouter}; -use bytes::Bytes; use relay_config::Config; use relay_spans::TracesData; @@ -34,11 +33,6 @@ async fn handle( Ok(StatusCode::ACCEPTED) } -pub fn route(config: &Config) -> MethodRouter -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send + Into, - B::Error: Into, -{ +pub fn route(config: &Config) -> MethodRouter { post(handle).route_layer(DefaultBodyLimit::max(config.max_span_size())) } diff --git a/relay-server/src/endpoints/store.rs b/relay-server/src/endpoints/store.rs index edf7ffc9e5c..facc5033a71 100644 --- a/relay-server/src/endpoints/store.rs +++ b/relay-server/src/endpoints/store.rs @@ -143,11 +143,6 @@ async fn handle_get( Ok(([(header::CONTENT_TYPE, "image/gif")], PIXEL)) } -pub fn route(config: &Config) -> MethodRouter -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send, - B::Error: Into, -{ +pub fn route(config: &Config) -> MethodRouter { (post(handle_post).get(handle_get)).route_layer(DefaultBodyLimit::max(config.max_event_size())) } diff --git a/relay-server/src/endpoints/unreal.rs b/relay-server/src/endpoints/unreal.rs index 3207980db6c..0f23fc2ac73 100644 --- a/relay-server/src/endpoints/unreal.rs +++ b/relay-server/src/endpoints/unreal.rs @@ -67,11 +67,6 @@ async fn handle( Ok(TextResponse(id)) } -pub fn route(config: &Config) -> MethodRouter -where - B: axum::body::HttpBody + Send + 'static, - B::Data: Send, - B::Error: Into, -{ +pub fn route(config: &Config) -> MethodRouter { post(handle).route_layer(DefaultBodyLimit::max(config.max_attachments_size())) } diff --git a/relay-server/src/extractors/signed_json.rs b/relay-server/src/extractors/signed_json.rs index 74aa3c7baed..5168d505b69 100644 --- a/relay-server/src/extractors/signed_json.rs +++ b/relay-server/src/extractors/signed_json.rs @@ -1,6 +1,6 @@ use axum::extract::rejection::BytesRejection; -use axum::extract::FromRequest; -use axum::http::{Request, StatusCode}; +use axum::extract::{FromRequest, Request}; +use axum::http::StatusCode; use axum::response::{IntoResponse, Response}; use bytes::Bytes; use relay_auth::{RelayId, UnpackError}; @@ -72,19 +72,13 @@ fn get_header<'a, B>( } #[axum::async_trait] -impl FromRequest for SignedJson +impl FromRequest for SignedJson where T: DeserializeOwned, - B: axum::body::HttpBody + Send + 'static, - B::Data: Send, - B::Error: Into, { type Rejection = SignatureError; - async fn from_request( - request: Request, - state: &ServiceState, - ) -> Result { + async fn from_request(request: Request, state: &ServiceState) -> Result { let relay_id = get_header(&request, "x-sentry-relay-id")? .parse::() .map_err(|_| SignatureError::MalformedHeader("x-sentry-relay-id"))?; diff --git a/relay-server/src/middlewares/metrics.rs b/relay-server/src/middlewares/metrics.rs index 39ebe09e848..4c966c8cc5d 100644 --- a/relay-server/src/middlewares/metrics.rs +++ b/relay-server/src/middlewares/metrics.rs @@ -1,5 +1,4 @@ -use axum::extract::MatchedPath; -use axum::http::Request; +use axum::extract::{MatchedPath, Request}; use axum::middleware::Next; use axum::response::Response; use axum::RequestExt; @@ -10,10 +9,7 @@ use crate::statsd::{RelayCounters, RelayTimers}; /// A middleware that logs web request timings as statsd metrics. /// /// Use this with [`axum::middleware::from_fn`]. -pub async fn metrics(mut request: Request, next: Next) -> Response -where - B: Send + 'static, -{ +pub async fn metrics(mut request: Request, next: Next) -> Response { let start_time = StartTime::now(); request.extensions_mut().insert(start_time); diff --git a/relay-server/src/utils/multipart.rs b/relay-server/src/utils/multipart.rs index 305b45bfba2..02131b57054 100644 --- a/relay-server/src/utils/multipart.rs +++ b/relay-server/src/utils/multipart.rs @@ -217,10 +217,9 @@ where #[cfg(test)] mod tests { - use axum::body::Full; + use axum::body::Body; use axum::extract::FromRequest; use axum::http::Request; - use bytes::Bytes; use super::*; @@ -284,7 +283,7 @@ mod tests { let request = Request::builder() .header("content-type", "multipart/form-data; boundary=X-BOUNDARY") - .body(Full::new(Bytes::from(data))) + .body(Body::from(data)) .unwrap(); let mut multipart = Multipart::from_request(request, &()).await?; From aa3e6d269281a6d2b3b768f642a3208f880ec432 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Wed, 13 Dec 2023 12:30:37 +0100 Subject: [PATCH 02/12] More fixes --- Cargo.lock | 13 ++-- relay-server/Cargo.toml | 4 +- relay-server/src/actors/server.rs | 63 +++++++------------ relay-server/src/endpoints/forward.rs | 47 ++++++++++---- relay-server/src/middlewares/decompression.rs | 17 +---- 5 files changed, 70 insertions(+), 74 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d51fa84dbd0..2b261683e1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -329,15 +329,18 @@ dependencies = [ [[package]] name = "axum-server" version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447f28c85900215cc1bea282f32d4a2f22d55c5a300afdfbc661c8d6a632e063" +source = "git+https://github.com/programatik29/axum-server?rev=e575e90d1fc796401d144f306648553909336700#e575e90d1fc796401d144f306648553909336700" dependencies = [ "bytes", "futures-util", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.26", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.0.1", + "hyper-util", + "pin-project-lite", "tokio", + "tower", "tower-service", ] diff --git a/relay-server/Cargo.toml b/relay-server/Cargo.toml index 2cc28bf4f46..3b385585d3a 100644 --- a/relay-server/Cargo.toml +++ b/relay-server/Cargo.toml @@ -40,7 +40,7 @@ axum = { version = "0.7.2", features = [ "multipart", "tracing", ] } -axum-server = "0.5.1" +axum-server = { git = "https://github.com/programatik29/axum-server", rev = "e575e90d1fc796401d144f306648553909336700" } backoff = "0.4.0" brotli = "3.3.4" bytecount = "0.6.0" @@ -82,6 +82,8 @@ relay-sampling = { path = "../relay-sampling" } relay-spans = { path = "../relay-spans" } relay-statsd = { path = "../relay-statsd" } relay-system = { path = "../relay-system" } +# NOTE: When upgrading to a version of reqwest that depends on hyper/http 1.0, go to +# relay-server/src/endpoints/forward.rs and remove `mod legacy_shims`. reqwest = { version = "0.11.1", features = [ "gzip", "stream", diff --git a/relay-server/src/actors/server.rs b/relay-server/src/actors/server.rs index cbf3fa72d1a..2ce02992d7a 100644 --- a/relay-server/src/actors/server.rs +++ b/relay-server/src/actors/server.rs @@ -4,7 +4,7 @@ use std::time::Duration; use axum::http::{header, HeaderName, HeaderValue}; use axum::ServiceExt; -use axum_server::{AddrIncomingConfig, Handle, HttpConfig}; +use axum_server::Handle; use relay_config::Config; use relay_log::tower::{NewSentryLayer, SentryHttpLayer}; use relay_system::{Controller, Service, Shutdown}; @@ -12,9 +12,7 @@ use tower::ServiceBuilder; use tower_http::set_header::SetResponseHeaderLayer; use crate::constants; -use crate::middlewares::{ - self, CatchPanicLayer, HandleErrorLayer, NormalizePathLayer, RequestDecompressionLayer, -}; +use crate::middlewares::{self, CatchPanicLayer, NormalizePathLayer, RequestDecompressionLayer}; use crate::service::ServiceState; use crate::statsd::RelayCounters; @@ -36,10 +34,6 @@ pub struct HttpServer { service: ServiceState, } -/// Set the number of keep-alive retransmissions to be carried out before declaring that remote end -/// is not available. -const KEEPALIVE_RETRIES: u32 = 5; - /// Set a timeout for reading client request headers. If a client does not transmit the entire /// header within this time, the connection is closed. const CLIENT_HEADER_TIMEOUT: Duration = Duration::from_secs(5); @@ -82,10 +76,8 @@ impl Service for HttpServer { .layer(NewSentryLayer::new_from_top()) .layer(SentryHttpLayer::with_transaction()) .layer(middlewares::trace_http_layer()) - // .layer(HandleErrorLayer::new(middlewares::decompression_error)) - // .map_request(middlewares::remove_empty_encoding) - // .layer(RequestDecompressionLayer::new()); - ; + .map_request(middlewares::remove_empty_encoding) + .layer(RequestDecompressionLayer::new()); let router = crate::endpoints::routes(service.config()) .layer(middleware) @@ -98,39 +90,32 @@ impl Service for HttpServer { .service(router) .into_make_service_with_connect_info::(); - let http_config = HttpConfig::new() - .http1_half_close(true) - .http1_header_read_timeout(CLIENT_HEADER_TIMEOUT) - .http1_writev(true) - .http2_keep_alive_timeout(config.keepalive_timeout()) - .build(); - - let addr_config = AddrIncomingConfig::new() - .tcp_keepalive(Some(config.keepalive_timeout()).filter(|d| !d.is_zero())) - .tcp_keepalive_interval(Some(config.keepalive_timeout()).filter(|d| !d.is_zero())) - .tcp_keepalive_retries(Some(KEEPALIVE_RETRIES)) - .build(); + relay_log::info!("spawning http server"); + relay_log::info!(" listening on http://{}/", config.listen_addr()); + relay_statsd::metric!(counter(RelayCounters::ServerStarting) += 1); - let handle = Handle::new(); - match TcpListener::bind(config.listen_addr()) { - Ok(listener) => { - listener.set_nonblocking(true).ok(); - let server = axum_server::from_tcp(listener) - .http_config(http_config) - .addr_incoming_config(addr_config) - .handle(handle.clone()); - - relay_log::info!("spawning http server"); - relay_log::info!(" listening on http://{}/", config.listen_addr()); - relay_statsd::metric!(counter(RelayCounters::ServerStarting) += 1); - tokio::spawn(server.serve(app)); - } + let listener = match TcpListener::bind(config.listen_addr()) { + Ok(listener) => listener, Err(err) => { relay_log::error!("Failed to start the HTTP server: {err}"); std::process::exit(1); } - } + }; + + let server = axum_server::from_tcp(listener); + server + .http_builder() + .http1() + .half_close(true) + .header_read_timeout(CLIENT_HEADER_TIMEOUT) + .writev(true); + server + .http_builder() + .http2() + .keep_alive_timeout(config.keepalive_timeout()); + let handle = Handle::new(); + tokio::spawn(server.handle(handle.clone()).serve(app)); tokio::spawn(async move { let Shutdown { timeout } = Controller::shutdown_handle().notified().await; relay_log::info!("Shutting down HTTP server"); diff --git a/relay-server/src/endpoints/forward.rs b/relay-server/src/endpoints/forward.rs index 2c3d8b3fa5b..45a79bd3874 100644 --- a/relay-server/src/endpoints/forward.rs +++ b/relay-server/src/endpoints/forward.rs @@ -46,14 +46,41 @@ static IGNORED_REQUEST_HEADERS: &[HeaderName] = &[ /// Root path of all API endpoints. const API_PATH: &str = "/api/"; -fn status_to_1(status: reqwest::StatusCode) -> StatusCode { - StatusCode::from_u16(status.as_u16()).unwrap() -} +/// Shims to convert between http 0.2 and http 1.0. This is needed until reqwest is updated to a +/// version that builds on hyper/http 1.0. +mod legacy_shims { + use axum::http::StatusCode as AxumCode; + use reqwest::StatusCode as ReqwestCode; + + use super::HOP_BY_HOP_HEADERS; + + pub fn status_to_1(status: ReqwestCode) -> AxumCode { + AxumCode::from_u16(status.as_u16()).unwrap() + } + + pub fn status_to_1_opt(status: Option) -> Option { + Some(AxumCode::from_u16(status?.as_u16()).unwrap()) + } + + pub fn is_hop_by_hop(header: &reqwest::header::HeaderName) -> bool { + HOP_BY_HOP_HEADERS + .iter() + .any(|h| h.as_str() == header.as_str()) + } -fn status_to_1_opt(status: Option) -> Option { - Some(StatusCode::from_u16(status?.as_u16()).unwrap()) + pub fn header_to_1( + name: &reqwest::header::HeaderName, + value: &reqwest::header::HeaderValue, + ) -> (axum::http::HeaderName, axum::http::HeaderValue) { + ( + name.as_str().parse().unwrap(), + axum::http::HeaderValue::from_bytes(value.as_bytes()).unwrap(), + ) + } } +use legacy_shims::*; + /// A wrapper struct that allows conversion of UpstreamRequestError into a `dyn ResponseError`. The /// conversion logic is really only acceptable for blindly forwarded requests. #[derive(Debug, thiserror::Error)] @@ -173,14 +200,8 @@ impl UpstreamRequest for ForwardRequest { let headers = response .headers() .iter() - .filter(|(name, _)| !HOP_BY_HOP_HEADERS.contains(name)) - .map(|(name, value)| { - ( - // TODO: Undo this once reqwest is updated - name.as_str().parse().unwrap(), - value.as_str().parse().unwrap(), - ) - }) + .filter(|(name, _)| is_hop_by_hop(name)) + .map(|(name, value)| header_to_1(name, value)) .collect(); match response.bytes(self.max_response_size).await { diff --git a/relay-server/src/middlewares/decompression.rs b/relay-server/src/middlewares/decompression.rs index 65c5a879258..364793bf311 100644 --- a/relay-server/src/middlewares/decompression.rs +++ b/relay-server/src/middlewares/decompression.rs @@ -1,10 +1,5 @@ -pub use axum::error_handling::HandleErrorLayer; -use axum::http::{header, Request, StatusCode}; -use axum::response::IntoResponse; +use axum::http::{header, Request}; pub use tower_http::decompression::RequestDecompressionLayer; -use tower_http::BoxError; - -use crate::utils::ApiErrorResponse; /// Map request middleware that removes empty content encoding headers. /// @@ -25,13 +20,3 @@ fn should_ignore_encoding(value: &[u8]) -> bool { // sentry.java.android/2.0.0 sends "UTF-8" value == b"" || value.eq_ignore_ascii_case(b"utf-8") } - -/// Error function to be used with [`RequestDecompressionLayer`]. -/// -/// To use decompression in axum, wrap it in a [`HandleErrorLayer`] with this function. -pub async fn decompression_error(error: BoxError) -> impl IntoResponse { - ( - StatusCode::BAD_REQUEST, - ApiErrorResponse::from_error(error.as_ref()), - ) -} From 0c65be8fa47656001ab2a0d0e824abdfa6aa57b1 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Wed, 13 Dec 2023 12:45:36 +0100 Subject: [PATCH 03/12] fix: Forward endpoint --- relay-server/src/endpoints/forward.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/relay-server/src/endpoints/forward.rs b/relay-server/src/endpoints/forward.rs index 45a79bd3874..f94ce34c86a 100644 --- a/relay-server/src/endpoints/forward.rs +++ b/relay-server/src/endpoints/forward.rs @@ -11,7 +11,7 @@ use std::pin::Pin; use axum::extract::{DefaultBodyLimit, Request}; use axum::handler::Handler; -use axum::http::{header, HeaderMap, HeaderName, HeaderValue, StatusCode, Uri}; +use axum::http::{header, HeaderMap, HeaderName, HeaderValue, Method, StatusCode, Uri}; use axum::response::{IntoResponse, Response}; use bytes::Bytes; use once_cell::sync::Lazy; @@ -20,7 +20,7 @@ use relay_config::Config; use tokio::sync::oneshot; use tokio::sync::oneshot::error::RecvError; -use crate::actors::upstream::{Method, SendRequest, UpstreamRequest, UpstreamRequestError}; +use crate::actors::upstream::{SendRequest, UpstreamRequest, UpstreamRequestError}; use crate::extractors::ForwardedFor; use crate::http::{HttpError, RequestBuilder, Response as UpstreamResponse}; use crate::service::ServiceState; @@ -146,8 +146,8 @@ impl fmt::Debug for ForwardRequest { } impl UpstreamRequest for ForwardRequest { - fn method(&self) -> Method { - self.method.clone() + fn method(&self) -> reqwest::Method { + self.method.as_str().parse().unwrap() } fn path(&self) -> Cow<'_, str> { From 05403a4f8b07e896bff309254e7ed6a306d69aca Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Wed, 13 Dec 2023 13:10:02 +0100 Subject: [PATCH 04/12] fix: Build --- relay-server/src/actors/server.rs | 64 +++++++++++-------- .../src/middlewares/normalize_path.rs | 3 +- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/relay-server/src/actors/server.rs b/relay-server/src/actors/server.rs index 2ce02992d7a..d6c9e0a39c8 100644 --- a/relay-server/src/actors/server.rs +++ b/relay-server/src/actors/server.rs @@ -1,7 +1,9 @@ +use std::io; use std::net::{SocketAddr, TcpListener}; use std::sync::Arc; use std::time::Duration; +use axum::extract::Request; use axum::http::{header, HeaderName, HeaderValue}; use axum::ServiceExt; use axum_server::Handle; @@ -12,14 +14,18 @@ use tower::ServiceBuilder; use tower_http::set_header::SetResponseHeaderLayer; use crate::constants; -use crate::middlewares::{self, CatchPanicLayer, NormalizePathLayer, RequestDecompressionLayer}; +use crate::middlewares::{self, CatchPanicLayer, NormalizePath, RequestDecompressionLayer}; use crate::service::ServiceState; use crate::statsd::RelayCounters; /// Indicates the type of failure of the server. #[allow(clippy::enum_variant_names)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, thiserror::Error)] +#[derive(Debug, thiserror::Error)] pub enum ServerError { + /// Binding failed. + #[error("bind to interface failed")] + BindFailed(#[source] io::Error), + /// TLS support was not compiled in. #[error("SSL is no longer supported by Relay, please use a proxy in front")] TlsNotSupported, @@ -32,6 +38,7 @@ pub enum ServerError { pub struct HttpServer { config: Arc, service: ServiceState, + server: axum_server::Server, } /// Set a timeout for reading client request headers. If a client does not transmit the entire @@ -48,7 +55,25 @@ impl HttpServer { return Err(ServerError::TlsNotSupported); } - Ok(Self { config, service }) + let listener = TcpListener::bind(config.listen_addr()).map_err(ServerError::BindFailed)?; + + let mut server = axum_server::from_tcp(listener); + server + .http_builder() + .http1() + .half_close(true) + .header_read_timeout(CLIENT_HEADER_TIMEOUT) + .writev(true); + server + .http_builder() + .http2() + .keep_alive_timeout(config.keepalive_timeout()); + + Ok(Self { + config, + service, + server, + }) } } @@ -56,7 +81,11 @@ impl Service for HttpServer { type Interface = (); fn spawn_handler(self, _rx: relay_system::Receiver) { - let Self { config, service } = self; + let Self { + config, + service, + server, + } = self; // Build the router middleware into a single service which runs _after_ routing. Service // builder order defines layers added first will be called first. This means: @@ -85,37 +114,16 @@ impl Service for HttpServer { // Bundle middlewares that need to run _before_ routing, which need to wrap the router. // ConnectInfo is special as it needs to last. - let app = ServiceBuilder::new() - .layer(NormalizePathLayer::new()) - .service(router) - .into_make_service_with_connect_info::(); + let app = NormalizePath::new(router); + let app = ServiceExt::::into_make_service_with_connect_info::(app); relay_log::info!("spawning http server"); relay_log::info!(" listening on http://{}/", config.listen_addr()); relay_statsd::metric!(counter(RelayCounters::ServerStarting) += 1); - let listener = match TcpListener::bind(config.listen_addr()) { - Ok(listener) => listener, - Err(err) => { - relay_log::error!("Failed to start the HTTP server: {err}"); - std::process::exit(1); - } - }; - - let server = axum_server::from_tcp(listener); - server - .http_builder() - .http1() - .half_close(true) - .header_read_timeout(CLIENT_HEADER_TIMEOUT) - .writev(true); - server - .http_builder() - .http2() - .keep_alive_timeout(config.keepalive_timeout()); - let handle = Handle::new(); tokio::spawn(server.handle(handle.clone()).serve(app)); + tokio::spawn(async move { let Shutdown { timeout } = Controller::shutdown_handle().notified().await; relay_log::info!("Shutting down HTTP server"); diff --git a/relay-server/src/middlewares/normalize_path.rs b/relay-server/src/middlewares/normalize_path.rs index 268f2c606b7..137d6a73a39 100644 --- a/relay-server/src/middlewares/normalize_path.rs +++ b/relay-server/src/middlewares/normalize_path.rs @@ -1,8 +1,7 @@ use std::borrow::Cow; use std::task::{Context, Poll}; -use axum::http::{Request, Uri}; -use axum::response::Response; +use axum::http::{Request, Response, Uri}; use once_cell::sync::Lazy; use regex::Regex; use tower::{Layer, Service}; From e28446714f97415538e929cda5012a35045268b3 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Wed, 13 Dec 2023 13:11:05 +0100 Subject: [PATCH 05/12] fix: Warning --- relay-server/src/middlewares/normalize_path.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/relay-server/src/middlewares/normalize_path.rs b/relay-server/src/middlewares/normalize_path.rs index 137d6a73a39..95793944662 100644 --- a/relay-server/src/middlewares/normalize_path.rs +++ b/relay-server/src/middlewares/normalize_path.rs @@ -11,6 +11,7 @@ use tower::{Layer, Service}; pub struct NormalizePathLayer; impl NormalizePathLayer { + #[allow(unused)] pub fn new() -> Self { Self } From 448a2571bdac992e32e32cf807cbf42e55899135 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Wed, 13 Dec 2023 13:58:45 +0100 Subject: [PATCH 06/12] ref: Beautify server --- relay-server/src/actors/server.rs | 128 ++++++++++++++++-------------- 1 file changed, 70 insertions(+), 58 deletions(-) diff --git a/relay-server/src/actors/server.rs b/relay-server/src/actors/server.rs index d6c9e0a39c8..7570998854d 100644 --- a/relay-server/src/actors/server.rs +++ b/relay-server/src/actors/server.rs @@ -5,8 +5,8 @@ use std::time::Duration; use axum::extract::Request; use axum::http::{header, HeaderName, HeaderValue}; -use axum::ServiceExt; -use axum_server::Handle; +use axum::{Router, ServiceExt}; +use axum_server::{Handle, Server}; use relay_config::Config; use relay_log::tower::{NewSentryLayer, SentryHttpLayer}; use relay_system::{Controller, Service, Shutdown}; @@ -18,6 +18,10 @@ use crate::middlewares::{self, CatchPanicLayer, NormalizePath, RequestDecompress use crate::service::ServiceState; use crate::statsd::RelayCounters; +/// Set a timeout for reading client request headers. If a client does not transmit the entire +/// header within this time, the connection is closed. +const CLIENT_HEADER_TIMEOUT: Duration = Duration::from_secs(5); + /// Indicates the type of failure of the server. #[allow(clippy::enum_variant_names)] #[derive(Debug, thiserror::Error)] @@ -31,6 +35,62 @@ pub enum ServerError { TlsNotSupported, } +fn listen(config: &Config) -> Result { + // Inform the user about a removed feature. + if config.tls_listen_addr().is_some() + || config.tls_identity_password().is_some() + || config.tls_identity_path().is_some() + { + return Err(ServerError::TlsNotSupported); + } + + TcpListener::bind(config.listen_addr()).map_err(ServerError::BindFailed) +} + +fn build_server(listener: TcpListener, config: &Config) -> Server { + let mut server = axum_server::from_tcp(listener); + + server + .http_builder() + .http1() + .half_close(true) + .header_read_timeout(CLIENT_HEADER_TIMEOUT) + .writev(true); + server + .http_builder() + .http2() + .keep_alive_timeout(config.keepalive_timeout()); + + server +} + +fn make_app(service: ServiceState) -> Router { + // Build the router middleware into a single service which runs _after_ routing. Service + // builder order defines layers added first will be called first. This means: + // - Requests go from top to bottom + // - Responses go from bottom to top + let middleware = ServiceBuilder::new() + .layer(axum::middleware::from_fn(middlewares::metrics)) + .layer(CatchPanicLayer::custom(middlewares::handle_panic)) + .layer(SetResponseHeaderLayer::overriding( + header::SERVER, + HeaderValue::from_static(constants::SERVER), + )) + .layer(SetResponseHeaderLayer::overriding( + HeaderName::from_static("cross-origin-resource-policy"), + HeaderValue::from_static("cross-origin"), + )) + .layer(NewSentryLayer::new_from_top()) + .layer(SentryHttpLayer::with_transaction()) + .layer(middlewares::trace_http_layer()) + .map_request(middlewares::remove_empty_encoding) + .layer(RequestDecompressionLayer::new()); + + crate::endpoints::routes(service.config()) + .layer(middleware) + .with_state(service) +} + /// HTTP server service. /// /// This is the main HTTP server of Relay which hosts all [services](ServiceState) and dispatches @@ -38,36 +98,13 @@ pub enum ServerError { pub struct HttpServer { config: Arc, service: ServiceState, - server: axum_server::Server, + server: Server, } -/// Set a timeout for reading client request headers. If a client does not transmit the entire -/// header within this time, the connection is closed. -const CLIENT_HEADER_TIMEOUT: Duration = Duration::from_secs(5); - impl HttpServer { pub fn new(config: Arc, service: ServiceState) -> Result { - // Inform the user about a removed feature. - if config.tls_listen_addr().is_some() - || config.tls_identity_password().is_some() - || config.tls_identity_path().is_some() - { - return Err(ServerError::TlsNotSupported); - } - - let listener = TcpListener::bind(config.listen_addr()).map_err(ServerError::BindFailed)?; - - let mut server = axum_server::from_tcp(listener); - server - .http_builder() - .http1() - .half_close(true) - .header_read_timeout(CLIENT_HEADER_TIMEOUT) - .writev(true); - server - .http_builder() - .http2() - .keep_alive_timeout(config.keepalive_timeout()); + let listener = listen(&config)?; + let server = build_server(listener, &config); Ok(Self { config, @@ -87,41 +124,16 @@ impl Service for HttpServer { server, } = self; - // Build the router middleware into a single service which runs _after_ routing. Service - // builder order defines layers added first will be called first. This means: - // - Requests go from top to bottom - // - Responses go from bottom to top - let middleware = ServiceBuilder::new() - .layer(axum::middleware::from_fn(middlewares::metrics)) - .layer(CatchPanicLayer::custom(middlewares::handle_panic)) - .layer(SetResponseHeaderLayer::overriding( - header::SERVER, - HeaderValue::from_static(constants::SERVER), - )) - .layer(SetResponseHeaderLayer::overriding( - HeaderName::from_static("cross-origin-resource-policy"), - HeaderValue::from_static("cross-origin"), - )) - .layer(NewSentryLayer::new_from_top()) - .layer(SentryHttpLayer::with_transaction()) - .layer(middlewares::trace_http_layer()) - .map_request(middlewares::remove_empty_encoding) - .layer(RequestDecompressionLayer::new()); - - let router = crate::endpoints::routes(service.config()) - .layer(middleware) - .with_state(service); - - // Bundle middlewares that need to run _before_ routing, which need to wrap the router. - // ConnectInfo is special as it needs to last. - let app = NormalizePath::new(router); - let app = ServiceExt::::into_make_service_with_connect_info::(app); - relay_log::info!("spawning http server"); relay_log::info!(" listening on http://{}/", config.listen_addr()); relay_statsd::metric!(counter(RelayCounters::ServerStarting) += 1); + // Bundle middlewares that need to run _before_ routing, which need to wrap the router. + // ConnectInfo is special as it needs to last. + let app = NormalizePath::new(make_app(service)); + let app = ServiceExt::::into_make_service_with_connect_info::(app); let handle = Handle::new(); + tokio::spawn(server.handle(handle.clone()).serve(app)); tokio::spawn(async move { From 734caebbd6a1de097dc569ee596a8aaa0e647db6 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Thu, 14 Dec 2023 15:27:31 +0100 Subject: [PATCH 07/12] fix: Replace axum-server with custom scaffolding --- Cargo.lock | 42 ++++---- relay-server/Cargo.toml | 6 +- relay-server/src/actors/server.rs | 168 ++++++++++++++++++++++-------- 3 files changed, 152 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b261683e1b..ce31c7754e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -270,7 +270,7 @@ dependencies = [ "http-body 1.0.0", "http-body-util", "hyper 1.0.1", - "hyper-util", + "hyper-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "itoa", "matchit", "memchr", @@ -326,24 +326,6 @@ dependencies = [ "syn 2.0.38", ] -[[package]] -name = "axum-server" -version = "0.5.1" -source = "git+https://github.com/programatik29/axum-server?rev=e575e90d1fc796401d144f306648553909336700#e575e90d1fc796401d144f306648553909336700" -dependencies = [ - "bytes", - "futures-util", - "http 1.0.0", - "http-body 1.0.0", - "http-body-util", - "hyper 1.0.1", - "hyper-util", - "pin-project-lite", - "tokio", - "tower", - "tower-service", -] - [[package]] name = "backoff" version = "0.4.0" @@ -2139,6 +2121,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "hyper-util" +version = "0.1.1" +source = "git+https://github.com/hyperium/hyper-util?rev=99409f5c4059633b7e2fa8b9c2e6c110b0f2f64b#99409f5c4059633b7e2fa8b9c2e6c110b0f2f64b" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "hyper 1.0.1", + "pin-project-lite", + "socket2 0.5.3", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.53" @@ -3980,7 +3981,6 @@ version = "23.11.2" dependencies = [ "anyhow", "axum", - "axum-server", "backoff", "brotli", "bytecount", @@ -3991,6 +3991,8 @@ dependencies = [ "futures", "hash32", "hashbrown 0.13.2", + "hyper 1.0.1", + "hyper-util 0.1.1 (git+https://github.com/hyperium/hyper-util?rev=99409f5c4059633b7e2fa8b9c2e6c110b0f2f64b)", "insta", "itertools", "json-forensics", diff --git a/relay-server/Cargo.toml b/relay-server/Cargo.toml index 3b385585d3a..3c22a0d735e 100644 --- a/relay-server/Cargo.toml +++ b/relay-server/Cargo.toml @@ -40,7 +40,6 @@ axum = { version = "0.7.2", features = [ "multipart", "tracing", ] } -axum-server = { git = "https://github.com/programatik29/axum-server", rev = "e575e90d1fc796401d144f306648553909336700" } backoff = "0.4.0" brotli = "3.3.4" bytecount = "0.6.0" @@ -51,6 +50,11 @@ flate2 = "1.0.19" futures = { workspace = true } hash32 = { workspace = true } hashbrown = { workspace = true } +hyper = { version = "1.0.1", features = ["http1", "http2", "server"] } +hyper-util = { git = "https://github.com/hyperium/hyper-util", rev = "99409f5c4059633b7e2fa8b9c2e6c110b0f2f64b", features = [ + "server-auto", + "tokio", +] } itertools = { workspace = true } json-forensics = { version = "0.1.1" } mime = "0.3.16" diff --git a/relay-server/src/actors/server.rs b/relay-server/src/actors/server.rs index 7570998854d..9ea77a0bcca 100644 --- a/relay-server/src/actors/server.rs +++ b/relay-server/src/actors/server.rs @@ -1,16 +1,19 @@ use std::io; -use std::net::{SocketAddr, TcpListener}; +use std::net::{SocketAddr, TcpListener as StdTcpListener}; use std::sync::Arc; use std::time::Duration; -use axum::extract::Request; +use axum::extract::ConnectInfo; use axum::http::{header, HeaderName, HeaderValue}; -use axum::{Router, ServiceExt}; -use axum_server::{Handle, Server}; +use hyper_util::rt::{TokioExecutor, TokioIo, TokioTimer}; +use hyper_util::server::conn::auto::Builder; +use hyper_util::service::TowerToHyperService; use relay_config::Config; use relay_log::tower::{NewSentryLayer, SentryHttpLayer}; -use relay_system::{Controller, Service, Shutdown}; -use tower::ServiceBuilder; +use relay_system::{Controller, Service}; +use tokio::net::{TcpListener, TcpStream}; +use tokio::sync::{watch, Notify}; +use tower::{Layer, ServiceBuilder}; use tower_http::set_header::SetResponseHeaderLayer; use crate::constants; @@ -28,7 +31,7 @@ const CLIENT_HEADER_TIMEOUT: Duration = Duration::from_secs(5); pub enum ServerError { /// Binding failed. #[error("bind to interface failed")] - BindFailed(#[source] io::Error), + BindFailed(#[from] io::Error), /// TLS support was not compiled in. #[error("SSL is no longer supported by Relay, please use a proxy in front")] @@ -44,27 +47,14 @@ fn listen(config: &Config) -> Result { return Err(ServerError::TlsNotSupported); } - TcpListener::bind(config.listen_addr()).map_err(ServerError::BindFailed) + let listener = StdTcpListener::bind(config.listen_addr())?; + listener.set_nonblocking(true)?; + Ok(listener.try_into()?) } -fn build_server(listener: TcpListener, config: &Config) -> Server { - let mut server = axum_server::from_tcp(listener); +type App = NormalizePath; - server - .http_builder() - .http1() - .half_close(true) - .header_read_timeout(CLIENT_HEADER_TIMEOUT) - .writev(true); - server - .http_builder() - .http2() - .keep_alive_timeout(config.keepalive_timeout()); - - server -} - -fn make_app(service: ServiceState) -> Router { +fn make_app(service: ServiceState) -> App { // Build the router middleware into a single service which runs _after_ routing. Service // builder order defines layers added first will be called first. This means: // - Requests go from top to bottom @@ -86,9 +76,11 @@ fn make_app(service: ServiceState) -> Router { .map_request(middlewares::remove_empty_encoding) .layer(RequestDecompressionLayer::new()); - crate::endpoints::routes(service.config()) + let router = crate::endpoints::routes(service.config()) .layer(middleware) - .with_state(service) + .with_state(service); + + NormalizePath::new(router) } /// HTTP server service. @@ -98,18 +90,18 @@ fn make_app(service: ServiceState) -> Router { pub struct HttpServer { config: Arc, service: ServiceState, - server: Server, + listener: TcpListener, } impl HttpServer { pub fn new(config: Arc, service: ServiceState) -> Result { let listener = listen(&config)?; - let server = build_server(listener, &config); + // let server = build_server(listener, &config); Ok(Self { config, service, - server, + listener, }) } } @@ -121,29 +113,119 @@ impl Service for HttpServer { let Self { config, service, - server, + listener, } = self; relay_log::info!("spawning http server"); relay_log::info!(" listening on http://{}/", config.listen_addr()); relay_statsd::metric!(counter(RelayCounters::ServerStarting) += 1); - // Bundle middlewares that need to run _before_ routing, which need to wrap the router. - // ConnectInfo is special as it needs to last. - let app = NormalizePath::new(make_app(service)); - let app = ServiceExt::::into_make_service_with_connect_info::(app); - let handle = Handle::new(); + let app = make_app(service); - tokio::spawn(server.handle(handle.clone()).serve(app)); + tokio::spawn(serve(listener, app, config.clone())); + } +} - tokio::spawn(async move { - let Shutdown { timeout } = Controller::shutdown_handle().notified().await; - relay_log::info!("Shutting down HTTP server"); +async fn serve(mut listener: TcpListener, app: App, config: Arc) { + // Create channels to track shutdown and open connections. + let hard_shutdown = monitor_hard_shutdown(); + let mut graceful_shutdown = Controller::shutdown_handle(); + let (connections_tx, connections_rx) = watch::channel(()); + + // Create a connection builder to reuse across connections + let builder = Arc::new(connection_builder(&config)); + + loop { + let (stream, addr) = tokio::select! { + biased; + result = accept(&mut listener) => result, + _ = graceful_shutdown.notified() => break, // stop connecting on shutdown signal + }; + + // We don't need to call `poll_ready` because `Router` is always ready. + let tower_service = axum::Extension(ConnectInfo(addr)).layer(app.clone()); + let hyper_service = TowerToHyperService::new(tower_service); - match timeout { - Some(timeout) => handle.graceful_shutdown(Some(timeout)), - None => handle.shutdown(), + let connection_rx = connections_rx.clone(); + let hard_shutdown = hard_shutdown.clone(); + let connection_builder = builder.clone(); + + tokio::spawn(async move { + tokio::select! { + biased; + _ = connection_builder.serve_connection_with_upgrades(stream, hyper_service) => (), + _ = hard_shutdown.notified() => () // keep polling until we reach hard shutdown } + + drop(connection_rx); }); } + + // Close the listener to stop accepting new connections. + drop(listener); + + // Drop the last rx and wait for all open connections to close (or hard shutdown). + drop(connections_rx); + connections_tx.closed().await; +} + +fn connection_builder(config: &Config) -> Builder { + let mut builder = Builder::new(TokioExecutor::new()); + + builder + .http1() + .timer(TokioTimer::new()) + .half_close(true) + .header_read_timeout(CLIENT_HEADER_TIMEOUT) + .writev(true); + + builder + .http2() + .timer(TokioTimer::new()) + .keep_alive_timeout(config.keepalive_timeout()); + + builder +} + +fn monitor_hard_shutdown() -> Arc { + let shutdown_tx = Arc::new(Notify::new()); + let shutdown_rx = shutdown_tx.clone(); + + // `finished()` is not thread-safe, so we need a dedicated task and a notify. + tokio::spawn(async move { + Controller::shutdown_handle().finished().await; + shutdown_tx.notify_waiters(); + }); + + shutdown_rx +} + +async fn accept(listener: &mut TcpListener) -> (TokioIo, SocketAddr) { + loop { + match listener.accept().await { + Ok((stream, addr)) => return (TokioIo::new(stream), addr), + Err(e) => { + // Connection errors can be ignored directly, continue + // by accepting the next request. + if is_connection_error(&e) { + continue; + } + + // A possible scenario is that the process has hit the max open files allowed, and + // so trying to accept a new connection will fail with `EMFILE`. In some cases, it's + // preferable to just wait for some time, if the application will likely close some + // files (or connections), and try to accept the connection again. + tokio::time::sleep(Duration::from_millis(50)).await + } + } + } +} + +fn is_connection_error(e: &io::Error) -> bool { + matches!( + e.kind(), + io::ErrorKind::ConnectionRefused + | io::ErrorKind::ConnectionAborted + | io::ErrorKind::ConnectionReset + ) } From 895f3a5c1ab0d31d6dfce43baec6d880932d6061 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Thu, 14 Dec 2023 16:09:22 +0100 Subject: [PATCH 08/12] ref: Revert SDK experiment --- relay-log/Cargo.toml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/relay-log/Cargo.toml b/relay-log/Cargo.toml index 65d4c442a42..5b60745d2eb 100644 --- a/relay-log/Cargo.toml +++ b/relay-log/Cargo.toml @@ -21,13 +21,6 @@ sentry = { version = "0.32.0", features = [ "tracing", ], optional = true } sentry-core = { version = "0.32.0" } -# sentry = { git = "https://github.com/getsentry/sentry-rust", rev = "139cdf3922e31b53f5256fd14a590e61ee6dc240", features = [ -# "debug-images", -# "tower-axum-matched-path", -# "tracing", -# "UNSTABLE_metrics", -# ], optional = true } -# sentry-core = { git = "https://github.com/getsentry/sentry-rust", rev = "139cdf3922e31b53f5256fd14a590e61ee6dc240" } tokio = { version = "1", default-features = false, features = [ "sync", ], optional = true } From 46b98f2576802d86f0cd0eb468e521c5abc25ca0 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Thu, 14 Dec 2023 16:10:31 +0100 Subject: [PATCH 09/12] fix: Lint --- relay-server/src/actors/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relay-server/src/actors/server.rs b/relay-server/src/actors/server.rs index 9ea77a0bcca..1b02a0f6240 100644 --- a/relay-server/src/actors/server.rs +++ b/relay-server/src/actors/server.rs @@ -86,7 +86,7 @@ fn make_app(service: ServiceState) -> App { /// HTTP server service. /// /// This is the main HTTP server of Relay which hosts all [services](ServiceState) and dispatches -/// incoming traffic to them. The server stops when a [`Shutdown`] is triggered. +/// incoming traffic to them. The server stops when a shutdown is triggered. pub struct HttpServer { config: Arc, service: ServiceState, From e48eb9e585f3efefaa3624730b6c6dc710c38617 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Fri, 15 Dec 2023 12:55:40 +0100 Subject: [PATCH 10/12] fix(forward): Properly filter headers --- relay-server/src/endpoints/forward.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relay-server/src/endpoints/forward.rs b/relay-server/src/endpoints/forward.rs index f94ce34c86a..83fbdd07884 100644 --- a/relay-server/src/endpoints/forward.rs +++ b/relay-server/src/endpoints/forward.rs @@ -200,7 +200,7 @@ impl UpstreamRequest for ForwardRequest { let headers = response .headers() .iter() - .filter(|(name, _)| is_hop_by_hop(name)) + .filter(|(name, _)| !is_hop_by_hop(name)) .map(|(name, value)| header_to_1(name, value)) .collect(); From 0a8a272f86a125ddbbb65faa8ba5e01ea10ef53d Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Fri, 15 Dec 2023 15:20:26 +0100 Subject: [PATCH 11/12] fix: Review comments --- relay-server/src/actors/server.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/relay-server/src/actors/server.rs b/relay-server/src/actors/server.rs index 1b02a0f6240..56f431131da 100644 --- a/relay-server/src/actors/server.rs +++ b/relay-server/src/actors/server.rs @@ -96,7 +96,6 @@ pub struct HttpServer { impl HttpServer { pub fn new(config: Arc, service: ServiceState) -> Result { let listener = listen(&config)?; - // let server = build_server(listener, &config); Ok(Self { config, @@ -132,7 +131,7 @@ async fn serve(mut listener: TcpListener, app: App, config: Arc) { let mut graceful_shutdown = Controller::shutdown_handle(); let (connections_tx, connections_rx) = watch::channel(()); - // Create a connection builder to reuse across connections + // Create a connection builder to reuse across connections. let builder = Arc::new(connection_builder(&config)); loop { From 45521e43af9cc917ed1337b113650f706fc6655c Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Mon, 18 Dec 2023 10:37:57 +0100 Subject: [PATCH 12/12] fix: Improve comments --- relay-server/src/actors/server.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/relay-server/src/actors/server.rs b/relay-server/src/actors/server.rs index 56f431131da..43cb723cd7f 100644 --- a/relay-server/src/actors/server.rs +++ b/relay-server/src/actors/server.rs @@ -54,6 +54,7 @@ fn listen(config: &Config) -> Result { type App = NormalizePath; +/// Build the axum application with all routes and middleware. fn make_app(service: ServiceState) -> App { // Build the router middleware into a single service which runs _after_ routing. Service // builder order defines layers added first will be called first. This means: @@ -80,6 +81,8 @@ fn make_app(service: ServiceState) -> App { .layer(middleware) .with_state(service); + // Add middlewares that need to run _before_ routing, which need to wrap the router. This are + // especially middlewares that modify the request path for the router: NormalizePath::new(router) }