From 8c701e8cf8b288f7d103ddb956705b624851b2e6 Mon Sep 17 00:00:00 2001 From: Moritz Bitsch Date: Tue, 16 Apr 2024 17:06:30 +0200 Subject: [PATCH] feat: add embedded-svc based http transport (#654) embedded-svc is used on esp32 for doing https --- sentry/Cargo.toml | 4 ++ sentry/src/transports/embedded_svc_http.rs | 64 ++++++++++++++++++++++ sentry/src/transports/mod.rs | 21 +++++++ 3 files changed, 89 insertions(+) create mode 100644 sentry/src/transports/embedded_svc_http.rs diff --git a/sentry/Cargo.toml b/sentry/Cargo.toml index 117ccde4..8958d20b 100644 --- a/sentry/Cargo.toml +++ b/sentry/Cargo.toml @@ -50,6 +50,7 @@ ureq = ["dep:ureq", "httpdate"] # transport settings native-tls = ["dep:native-tls", "reqwest?/default-tls", "ureq?/native-tls"] rustls = ["dep:rustls", "reqwest?/rustls-tls", "ureq?/tls", "webpki-roots"] +embedded-svc-http = ["dep:embedded-svc", "dep:esp-idf-svc"] [dependencies] sentry-core = { version = "0.32.3", path = "../sentry-core", features = [ @@ -82,6 +83,9 @@ rustls = { version = "0.21.2", optional = true, features = [ "dangerous_configuration", ] } webpki-roots = { version = "0.25.1", optional = true } +embedded-svc = { version = "0.27.1", optional = true } +[target.'cfg(target_os = "espidf")'.dependencies] +esp-idf-svc = { version = "0.48.1", optional = true } [dev-dependencies] sentry-anyhow = { path = "../sentry-anyhow" } diff --git a/sentry/src/transports/embedded_svc_http.rs b/sentry/src/transports/embedded_svc_http.rs new file mode 100644 index 00000000..f040cb95 --- /dev/null +++ b/sentry/src/transports/embedded_svc_http.rs @@ -0,0 +1,64 @@ +use crate::{sentry_debug, ClientOptions, Transport}; +use embedded_svc::http::client::Client as HttpClient; +use esp_idf_svc::{http::client::EspHttpConnection, io::Write}; + +/// Transport using the embedded-svc http client +pub struct EmbeddedSVCHttpTransport { + options: ClientOptions, +} + +impl EmbeddedSVCHttpTransport { + /// Creates a new transport + pub fn new(options: &ClientOptions) -> Self { + Self { + options: options.clone(), + } + } +} + +impl EmbeddedSVCHttpTransport { + fn send_envelope( + &self, + envelope: sentry_core::Envelope, + ) -> Result<(), Box> { + let dsn = self + .options + .dsn + .as_ref() + .ok_or_else(|| "No DSN specified")?; + let user_agent = &self.options.user_agent; + let auth = dsn.to_auth(Some(user_agent)).to_string(); + let headers = [("X-Sentry-Auth", auth.as_str())]; + let url = dsn.envelope_api_url(); + + let mut body = Vec::new(); + envelope.to_writer(&mut body)?; + + let config = esp_idf_svc::http::client::Configuration { + use_global_ca_store: true, + crt_bundle_attach: Some(esp_idf_svc::sys::esp_crt_bundle_attach), + ..Default::default() + }; + + let mut client = HttpClient::wrap(EspHttpConnection::new(&config)?); + + let mut request = client.post(url.as_str(), &headers)?; + request.write_all(&body)?; + request.flush()?; + let mut response = request.submit()?; + + // read the whole response + let mut buf = [0u8; 1024]; + while response.read(&mut buf)? > 0 {} + + Ok(()) + } +} + +impl Transport for EmbeddedSVCHttpTransport { + fn send_envelope(&self, envelope: sentry_core::Envelope) { + if let Err(err) = self.send_envelope(envelope) { + sentry_debug!("Failed to send envelope: {}", err); + } + } +} diff --git a/sentry/src/transports/mod.rs b/sentry/src/transports/mod.rs index 253c7fe0..46a84988 100644 --- a/sentry/src/transports/mod.rs +++ b/sentry/src/transports/mod.rs @@ -18,6 +18,11 @@ mod reqwest; #[cfg(feature = "reqwest")] pub use self::reqwest::ReqwestHttpTransport; +#[cfg(all(target_os = "espidf", feature = "embedded-svc-http"))] +mod embedded_svc_http; +#[cfg(all(target_os = "espidf", feature = "embedded-svc-http"))] +pub use self::embedded_svc_http::EmbeddedSVCHttpTransport; + #[cfg(feature = "curl")] mod curl; #[cfg(feature = "curl")] @@ -38,6 +43,7 @@ type DefaultTransport = ReqwestHttpTransport; #[cfg(all( feature = "curl", + not(all(target_os = "espidf", feature = "embedded-svc-http")), not(feature = "reqwest"), not(feature = "surf"), not(feature = "ureq") @@ -46,6 +52,7 @@ type DefaultTransport = CurlHttpTransport; #[cfg(all( feature = "surf", + not(all(target_os = "espidf", feature = "embedded-svc-http")), not(feature = "reqwest"), not(feature = "curl"), not(feature = "ureq") @@ -54,14 +61,26 @@ type DefaultTransport = SurfHttpTransport; #[cfg(all( feature = "ureq", + not(all(target_os = "espidf", feature = "embedded-svc-http")), not(feature = "reqwest"), not(feature = "curl"), not(feature = "surf") ))] type DefaultTransport = UreqHttpTransport; +#[cfg(all( + target_os = "espidf", + feature = "embedded-svc-http", + not(feature = "reqwest"), + not(feature = "curl"), + not(feature = "surf"), + not(feature = "ureq") +))] +type DefaultTransport = EmbeddedSVCHttpTransport; + /// The default http transport. #[cfg(any( + all(target_os = "espidf", feature = "embedded-svc-http"), feature = "reqwest", feature = "curl", feature = "surf", @@ -80,6 +99,7 @@ pub struct DefaultTransportFactory; impl TransportFactory for DefaultTransportFactory { fn create_transport(&self, options: &ClientOptions) -> Arc { #[cfg(any( + all(target_os = "espidf", feature = "embedded-svc-http"), feature = "reqwest", feature = "curl", feature = "surf", @@ -89,6 +109,7 @@ impl TransportFactory for DefaultTransportFactory { Arc::new(HttpTransport::new(options)) } #[cfg(not(any( + all(target_os = "espidf", feature = "embedded-svc-http"), feature = "reqwest", feature = "curl", feature = "surf",