// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. use glean::net::{PingUploader, UploadResult}; use url::Url; use viaduct::{Error::*, Request}; extern "C" { fn FOG_TooLateToSend() -> bool; } /// An uploader that uses [Viaduct](https://github.com/mozilla/application-services/tree/main/components/viaduct). #[derive(Debug)] pub(crate) struct ViaductUploader; impl PingUploader for ViaductUploader { /// Uploads a ping to a server. /// /// # Arguments /// /// * `url` - the URL path to upload the data to. /// * `body` - the serialized text data to send. /// * `headers` - a vector of tuples containing the headers to send with /// the request, i.e. (Name, Value). fn upload(&self, url: String, body: Vec, headers: Vec<(String, String)>) -> UploadResult { log::trace!("FOG Ping Uploader uploading to {}", url); let url_clone = url.clone(); let result: std::result::Result = (move || { // SAFETY NOTE: Safe because it returns a primitive by value. if unsafe { FOG_TooLateToSend() } { log::trace!("Attempted to send ping too late into shutdown."); return Ok(UploadResult::done()); } let debug_tagged = headers.iter().any(|(name, _)| name == "X-Debug-ID"); let localhost_port = static_prefs::pref!("telemetry.fog.test.localhost_port"); if localhost_port < 0 || (localhost_port == 0 && !debug_tagged && cfg!(feature = "disable_upload")) { log::info!("FOG Ping uploader faking success"); return Ok(UploadResult::http_status(200)); } let parsed_url = Url::parse(&url_clone)?; log::info!("FOG Ping uploader uploading to {:?}", parsed_url); let mut req = Request::post(parsed_url.clone()).body(body.clone()); for (header_key, header_value) in &headers { req = req.header(header_key.to_owned(), header_value)?; } log::trace!("FOG Ping Uploader sending ping to {}", parsed_url); let res = req.send()?; Ok(UploadResult::http_status(res.status as i32)) })(); log::trace!( "FOG Ping Uploader completed uploading to {} (Result {:?})", url, result ); match result { Ok(result) => result, Err(NonTlsUrl | UrlError(_)) => UploadResult::unrecoverable_failure(), Err( RequestHeaderError(_) | BackendError(_) | NetworkError(_) | BackendNotInitialized | SetBackendError, ) => UploadResult::recoverable_failure(), } } }