fix(mongo): normalize MongoDB URI query path
This commit is contained in:
parent
fd46869c14
commit
cedf4f1be3
|
|
@ -747,6 +747,7 @@ impl ConnectionConfig {
|
|||
suffix.push_str("&directConnection=true");
|
||||
}
|
||||
}
|
||||
let db_part = mongo_uri_db_part_for_suffix(&db_part, &suffix);
|
||||
format!("mongodb://{host}:{port}{db_part}{suffix}")
|
||||
}
|
||||
DatabaseType::Oracle => format!("oracle://{host}:{port}{db_part}"),
|
||||
|
|
@ -884,6 +885,7 @@ impl ConnectionConfig {
|
|||
suffix.push_str("&directConnection=true");
|
||||
}
|
||||
}
|
||||
let db_part = mongo_uri_db_part_for_suffix(&db_part, &suffix);
|
||||
if self.username.is_empty() {
|
||||
format!("mongodb://{host}:{port}{db_part}{suffix}")
|
||||
} else {
|
||||
|
|
@ -1186,15 +1188,24 @@ fn normalize_mongo_url_params(value: &str, force_tls: bool, default_auth_source:
|
|||
parts.join("&")
|
||||
}
|
||||
|
||||
fn mongo_uri_db_part_for_suffix<'a>(db_part: &'a str, suffix: &str) -> &'a str {
|
||||
if db_part.is_empty() && !suffix.is_empty() {
|
||||
"/"
|
||||
} else {
|
||||
db_part
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_mongo_uri_direct_connection(uri: &str) -> String {
|
||||
if !mongo_uri_has_multiple_seeds(uri) || !mongo_uri_has_direct_connection_true(uri) {
|
||||
return uri.to_string();
|
||||
let uri = normalize_mongo_uri_query_path(uri);
|
||||
if !mongo_uri_has_multiple_seeds(&uri) || !mongo_uri_has_direct_connection_true(&uri) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
let (before_fragment, fragment) =
|
||||
uri.split_once('#').map(|(base, fragment)| (base, Some(fragment))).unwrap_or((uri, None));
|
||||
uri.split_once('#').map(|(base, fragment)| (base, Some(fragment))).unwrap_or((uri.as_str(), None));
|
||||
let Some((base, query)) = before_fragment.split_once('?') else {
|
||||
return uri.to_string();
|
||||
return uri;
|
||||
};
|
||||
let params =
|
||||
query.split('&').filter(|part| !mongo_url_param_is_direct_connection_true(part)).collect::<Vec<_>>().join("&");
|
||||
|
|
@ -1207,6 +1218,26 @@ fn normalize_mongo_uri_direct_connection(uri: &str) -> String {
|
|||
normalized
|
||||
}
|
||||
|
||||
fn normalize_mongo_uri_query_path(uri: &str) -> String {
|
||||
let Some(rest_start) = uri.find("://").map(|idx| idx + "://".len()) else {
|
||||
return uri.to_string();
|
||||
};
|
||||
if !uri[..rest_start].eq_ignore_ascii_case("mongodb://")
|
||||
&& !uri[..rest_start].eq_ignore_ascii_case("mongodb+srv://")
|
||||
{
|
||||
return uri.to_string();
|
||||
}
|
||||
let rest = &uri[rest_start..];
|
||||
let Some(first_path_or_query) = rest.find(['/', '?', '#']) else {
|
||||
return uri.to_string();
|
||||
};
|
||||
if rest.as_bytes()[first_path_or_query] != b'?' {
|
||||
return uri.to_string();
|
||||
}
|
||||
let insert_at = rest_start + first_path_or_query;
|
||||
format!("{}/{}", &uri[..insert_at], &uri[insert_at..])
|
||||
}
|
||||
|
||||
fn mongo_uri_has_multiple_seeds(uri: &str) -> bool {
|
||||
mongo_uri_host_section(uri)
|
||||
.map(|hosts| hosts.split(',').filter(|host| !host.trim().is_empty()).count() > 1)
|
||||
|
|
@ -2154,6 +2185,14 @@ mod tests {
|
|||
assert_eq!(config.connection_url(), "mongodb://root:secret@10.1.2.3:17000/app?authSource=admin");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mongodb_form_url_without_database_keeps_slash_before_params() {
|
||||
let config = mongodb_config("root", "secret", None);
|
||||
|
||||
assert_eq!(config.connection_url(), "mongodb://root:secret@10.1.2.3:17000/?authSource=admin");
|
||||
assert_eq!(config.redacted_connection_url(), "mongodb://10.1.2.3:17000/?authSource=admin");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mongodb_form_url_without_username_does_not_default_auth_source() {
|
||||
let config = mongodb_config("", "", Some("app"));
|
||||
|
|
@ -2323,6 +2362,26 @@ mod tests {
|
|||
assert_eq!(url, "mongodb://read:pass@host1:27017,host2:27017/admin?replicaSet=rs0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mongodb_connection_string_without_database_keeps_slash_before_params() {
|
||||
let mut config = mongodb_config("root", "secret", None);
|
||||
config.connection_string = Some("mongodb://read:pass@host1:27017?authSource=admin".to_string());
|
||||
|
||||
let url = config.connection_url();
|
||||
|
||||
assert_eq!(url, "mongodb://read:pass@host1:27017/?authSource=admin");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mongodb_connection_string_without_database_keeps_slash_when_tunneled() {
|
||||
let mut config = mongodb_config("root", "secret", None);
|
||||
config.connection_string = Some("mongodb://read:pass@host1:27017?authSource=admin".to_string());
|
||||
|
||||
let url = config.connection_url_with_host("127.0.0.1", 54321);
|
||||
|
||||
assert_eq!(url, "mongodb://read:pass@127.0.0.1:54321/?authSource=admin&directConnection=true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mongodb_multi_seed_connection_string_removes_direct_connection_true() {
|
||||
let mut config = mongodb_config("root", "secret", Some("admin"));
|
||||
|
|
@ -2360,6 +2419,15 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mongodb_form_url_without_database_keeps_slash_before_tunneled_params() {
|
||||
let config = mongodb_config("root", "secret", None);
|
||||
|
||||
let url = config.connection_url_with_host("127.0.0.1", 54321);
|
||||
|
||||
assert_eq!(url, "mongodb://root:secret@127.0.0.1:54321/?authSource=admin&directConnection=true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mongodb_form_url_no_duplicate_direct_connection() {
|
||||
let mut config = mongodb_config("root", "secret", Some("admin"));
|
||||
|
|
|
|||
Loading…
Reference in New Issue