summaryrefslogtreecommitdiffstats
path: root/third_party/rust/viaduct/src/backend.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /third_party/rust/viaduct/src/backend.rs
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/viaduct/src/backend.rs')
-rw-r--r--third_party/rust/viaduct/src/backend.rs154
1 files changed, 154 insertions, 0 deletions
diff --git a/third_party/rust/viaduct/src/backend.rs b/third_party/rust/viaduct/src/backend.rs
new file mode 100644
index 0000000000..599a26bd98
--- /dev/null
+++ b/third_party/rust/viaduct/src/backend.rs
@@ -0,0 +1,154 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use crate::GLOBAL_SETTINGS;
+use ffi::FfiBackend;
+use once_cell::sync::OnceCell;
+mod ffi;
+
+pub fn note_backend(which: &str) {
+ // If trace logs are enabled: log on every request. Otherwise, just log on
+ // the first request at `info` level. We remember if the Once was triggered
+ // to avoid logging twice in the first case.
+ static NOTE_BACKEND_ONCE: std::sync::Once = std::sync::Once::new();
+ let mut called = false;
+ NOTE_BACKEND_ONCE.call_once(|| {
+ log::info!("Using HTTP backend {}", which);
+ called = true;
+ });
+ if !called {
+ log::trace!("Using HTTP backend {}", which);
+ }
+}
+
+pub trait Backend: Send + Sync + 'static {
+ fn send(&self, request: crate::Request) -> Result<crate::Response, crate::Error>;
+}
+
+static BACKEND: OnceCell<&'static dyn Backend> = OnceCell::new();
+
+pub fn set_backend(b: &'static dyn Backend) -> Result<(), crate::Error> {
+ BACKEND
+ .set(b)
+ .map_err(|_| crate::error::Error::SetBackendError)
+}
+
+pub(crate) fn get_backend() -> &'static dyn Backend {
+ *BACKEND.get_or_init(|| Box::leak(Box::new(FfiBackend)))
+}
+
+pub fn send(request: crate::Request) -> Result<crate::Response, crate::Error> {
+ validate_request(&request)?;
+ get_backend().send(request)
+}
+
+pub fn validate_request(request: &crate::Request) -> Result<(), crate::Error> {
+ if request.url.scheme() != "https"
+ && match request.url.host() {
+ Some(url::Host::Domain(d)) => d != "localhost",
+ Some(url::Host::Ipv4(addr)) => !addr.is_loopback(),
+ Some(url::Host::Ipv6(addr)) => !addr.is_loopback(),
+ None => true,
+ }
+ && {
+ let settings = GLOBAL_SETTINGS.read();
+ settings
+ .addn_allowed_insecure_url
+ .as_ref()
+ .map(|url| url.host() != request.url.host() || url.scheme() != request.url.scheme())
+ .unwrap_or(true)
+ }
+ {
+ return Err(crate::Error::NonTlsUrl);
+ }
+ Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_validate_request() {
+ let _https_request = crate::Request::new(
+ crate::Method::Get,
+ url::Url::parse("https://www.example.com").unwrap(),
+ );
+ assert!(validate_request(&_https_request).is_ok());
+
+ let _http_request = crate::Request::new(
+ crate::Method::Get,
+ url::Url::parse("http://www.example.com").unwrap(),
+ );
+ assert!(validate_request(&_http_request).is_err());
+
+ let _localhost_https_request = crate::Request::new(
+ crate::Method::Get,
+ url::Url::parse("https://127.0.0.1/index.html").unwrap(),
+ );
+ assert!(validate_request(&_localhost_https_request).is_ok());
+
+ let _localhost_https_request_2 = crate::Request::new(
+ crate::Method::Get,
+ url::Url::parse("https://localhost:4242/").unwrap(),
+ );
+ assert!(validate_request(&_localhost_https_request_2).is_ok());
+
+ let _localhost_http_request = crate::Request::new(
+ crate::Method::Get,
+ url::Url::parse("http://localhost:4242/").unwrap(),
+ );
+ assert!(validate_request(&_localhost_http_request).is_ok());
+
+ let localhost_request = crate::Request::new(
+ crate::Method::Get,
+ url::Url::parse("localhost:4242/").unwrap(),
+ );
+ assert!(validate_request(&localhost_request).is_err());
+
+ let localhost_request_shorthand_ipv6 =
+ crate::Request::new(crate::Method::Get, url::Url::parse("http://[::1]").unwrap());
+ assert!(validate_request(&localhost_request_shorthand_ipv6).is_ok());
+
+ let localhost_request_ipv6 = crate::Request::new(
+ crate::Method::Get,
+ url::Url::parse("http://[0:0:0:0:0:0:0:1]").unwrap(),
+ );
+ assert!(validate_request(&localhost_request_ipv6).is_ok());
+ }
+
+ #[test]
+ fn test_validate_request_addn_allowed_insecure_url() {
+ let request_root = crate::Request::new(
+ crate::Method::Get,
+ url::Url::parse("http://anything").unwrap(),
+ );
+ let request = crate::Request::new(
+ crate::Method::Get,
+ url::Url::parse("http://anything/path").unwrap(),
+ );
+ // This should never be accepted.
+ let request_ftp = crate::Request::new(
+ crate::Method::Get,
+ url::Url::parse("ftp://anything/path").unwrap(),
+ );
+ assert!(validate_request(&request_root).is_err());
+ assert!(validate_request(&request).is_err());
+ {
+ let mut settings = GLOBAL_SETTINGS.write();
+ settings.addn_allowed_insecure_url =
+ Some(url::Url::parse("http://something-else").unwrap());
+ }
+ assert!(validate_request(&request_root).is_err());
+ assert!(validate_request(&request).is_err());
+
+ {
+ let mut settings = GLOBAL_SETTINGS.write();
+ settings.addn_allowed_insecure_url = Some(url::Url::parse("http://anything").unwrap());
+ }
+ assert!(validate_request(&request_root).is_ok());
+ assert!(validate_request(&request).is_ok());
+ assert!(validate_request(&request_ftp).is_err());
+ }
+}