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();