This is an automated email from the ASF dual-hosted git repository.

hubcio pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/master by this push:
     new a69b4e36f fix(connectors): meilisearch_sink URL scheme check is 
case-sensitive (#4158)
a69b4e36f is described below

commit a69b4e36f5e57543e37f7855ac973fd16fe1b6e6
Author: Matthew Patton <[email protected]>
AuthorDate: Mon Sep 21 06:07:10 2026 -0400

    fix(connectors): meilisearch_sink URL scheme check is case-sensitive (#4158)
---
 core/connectors/sinks/meilisearch_sink/src/lib.rs | 69 ++++++++++++++++++++---
 1 file changed, 60 insertions(+), 9 deletions(-)

diff --git a/core/connectors/sinks/meilisearch_sink/src/lib.rs 
b/core/connectors/sinks/meilisearch_sink/src/lib.rs
index 27f0a04ae..5f6be75db 100644
--- a/core/connectors/sinks/meilisearch_sink/src/lib.rs
+++ b/core/connectors/sinks/meilisearch_sink/src/lib.rs
@@ -985,10 +985,23 @@ fn normalize_host(raw: &str) -> Result<String, Error> {
         ));
     }
 
-    let with_scheme = if trimmed.starts_with("http://";) || 
trimmed.starts_with("https://";) {
-        trimmed.to_string()
-    } else {
-        format!("http://{trimmed}";)
+    // `://` (rather than a plain colon) is the marker of an explicit scheme,
+    // since a bare `host:port` also contains a colon. Detected
+    // case-insensitively so `HTTPS://host` isn't missed and mistaken for a
+    // schemeless host, which would otherwise get `http://` prepended and
+    // send the request to a bogus host built from the original string.
+    let with_scheme = match trimmed.split_once("://") {
+        Some((scheme, _))
+            if scheme.eq_ignore_ascii_case("http") || 
scheme.eq_ignore_ascii_case("https") =>
+        {
+            trimmed.to_string()
+        }
+        Some((scheme, _)) => {
+            return Err(Error::Connection(format!(
+                "Invalid Meilisearch URL: unsupported scheme '{scheme}', 
expected http or https"
+            )));
+        }
+        None => format!("http://{trimmed}";),
     };
     let url = Url::parse(&with_scheme)
         .map_err(|error| Error::Connection(format!("Invalid Meilisearch URL: 
{error}")))?;
@@ -1002,6 +1015,15 @@ fn normalize_host(raw: &str) -> Result<String, Error> {
     Ok(base_url.as_str().trim_end_matches('/').to_string())
 }
 
+// Case-insensitive for the same reason as `normalize_host`'s scheme check:
+// `HTTP://host` is an explicit scheme, just not a lowercase one.
+fn explicit_http_scheme_hint(raw: &str) -> &'static str {
+    match raw.trim().split_once("://") {
+        Some((scheme, _)) if scheme.eq_ignore_ascii_case("http") => "explicit 
http://";,
+        _ => "implicit http://";,
+    }
+}
+
 fn warn_if_api_key_uses_insecure_http(raw: &str, normalized: &str, 
has_api_key: bool) {
     if !has_api_key {
         return;
@@ -1020,11 +1042,7 @@ fn warn_if_api_key_uses_insecure_http(raw: &str, 
normalized: &str, has_api_key:
         return;
     }
 
-    let scheme_hint = if raw.trim().starts_with("http://";) {
-        "explicit http://";
-    } else {
-        "implicit http://";
-    };
+    let scheme_hint = explicit_http_scheme_hint(raw);
     warn!(
         "Meilisearch API key is configured with {scheme_hint} for non-loopback 
host '{host}'. Credentials will be sent without TLS; use https:// unless this 
is intentional."
     );
@@ -1367,6 +1385,39 @@ mod tests {
         assert_eq!(url, "https://localhost:7700";);
     }
 
+    #[test]
+    fn normalize_host_should_accept_uppercase_https_scheme() {
+        // Regression: a case-sensitive `starts_with("https://";)` check fell
+        // through to the schemeless branch and produced
+        // `http://HTTPS://realhost:9200`, which `Url::parse` accepted with
+        // scheme=http, host="https" — silently dropping TLS and connecting
+        // to the wrong host.
+        let url = normalize_host("HTTPS://realhost:9200").expect("normalize 
host");
+
+        assert_eq!(url, "https://realhost:9200";);
+    }
+
+    #[test]
+    fn normalize_host_should_accept_mixed_case_http_scheme() {
+        let url = normalize_host("HtTp://realhost:7700").expect("normalize 
host");
+
+        assert_eq!(url, "http://realhost:7700";);
+    }
+
+    #[test]
+    fn normalize_host_should_reject_unsupported_scheme() {
+        let error = 
normalize_host("ftp://realhost:7700";).expect_err("unsupported scheme");
+
+        assert!(matches!(error, Error::Connection(_)));
+    }
+
+    #[test]
+    fn explicit_http_scheme_hint_should_be_case_insensitive() {
+        assert_eq!(explicit_http_scheme_hint("HTTP://host"), "explicit 
http://";);
+        assert_eq!(explicit_http_scheme_hint("http://host";), "explicit 
http://";);
+        assert_eq!(explicit_http_scheme_hint("host"), "implicit http://";);
+    }
+
     #[test]
     fn validate_config_should_reject_empty_index() {
         let mut config = base_config();

Reply via email to