Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

url decode the search index pattern #4292

Merged
merged 8 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions quickwit/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions quickwit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ openssl-probe = "0.1.5"
opentelemetry = { version = "0.19", features = ["rt-tokio"] }
opentelemetry-otlp = "0.12.0"
ouroboros = "0.18.0"
percent-encoding = "2.3.1"
pin-project = "1.1.0"
pnet = { version = "0.33.0", features = ["std"] }
postcard = { version = "1.0.4", features = [
Expand Down
1 change: 1 addition & 0 deletions quickwit/quickwit-serve/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ itertools = { workspace = true }
mime_guess = { workspace = true }
num_cpus = { workspace = true }
once_cell = { workspace = true }
percent-encoding = { workspace = true }
regex = { workspace = true }
rust-embed = { workspace = true }
serde = { workspace = true }
Expand Down
29 changes: 22 additions & 7 deletions quickwit/quickwit-serve/src/elastic_search_api/rest_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use elasticsearch_dsl::{HitsMetadata, Source, TotalHits, TotalHitsRelation};
use futures_util::StreamExt;
use hyper::StatusCode;
use itertools::Itertools;
use percent_encoding::percent_decode_str;
use quickwit_common::truncate_str;
use quickwit_config::{validate_index_id_pattern, NodeConfig};
use quickwit_proto::search::{
Expand Down Expand Up @@ -345,15 +346,29 @@ async fn es_compat_index_multi_search(
"`_msearch` request header must define at least one index".to_string(),
)));
}

let mut index_ids_patterns = Vec::new();
for index in &request_header.index {
validate_index_id_pattern(index).map_err(|err| {
SearchError::InvalidArgument(format!(
"request header contains an invalid index: {}",
err
))
})?;
match percent_decode_str(index).decode_utf8() {
Ok(decode_index) => {
validate_index_id_pattern(decode_index.to_string().as_str()).map_err(
tuziben marked this conversation as resolved.
Show resolved Hide resolved
|err| {
SearchError::InvalidArgument(format!(
"request header contains an invalid index: {}",
err
))
},
)?;
index_ids_patterns.push(decode_index.to_string());
}
Err(err) => {
SearchError::InvalidArgument(format!(
"request header contains an invalid index: {}",
err
));
}
}
}
let index_ids_patterns = request_header.index.clone();
let search_body = payload_lines
.next()
.ok_or_else(|| {
Expand Down
26 changes: 13 additions & 13 deletions quickwit/quickwit-serve/src/search_api/rest_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@
use std::convert::TryFrom;
use std::sync::Arc;

use anyhow::Context;
use futures::stream::StreamExt;
use hyper::header::HeaderValue;
use hyper::HeaderMap;
use once_cell::sync::Lazy;
use percent_encoding::percent_decode_str;
use quickwit_config::validate_index_id_pattern;
use quickwit_proto::search::{CountHits, OutputFormat, SortField, SortOrder};
use quickwit_proto::ServiceError;
use quickwit_query::query_ast::query_ast_from_user_text;
use quickwit_search::{SearchError, SearchResponseRest, SearchService};
use regex::Regex;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Value as JsonValue;
use tracing::info;
Expand All @@ -56,17 +56,17 @@ use crate::{with_arg, BodyFormat};
)]
pub struct SearchApi;

// Matches index patterns separated by commas or its URL encoded version '%2C'.
static COMMA_SEPARATED_INDEX_PATTERNS_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r",|%2C").expect("the regular expression should compile"));

pub(crate) async fn extract_index_id_patterns(
comma_separated_index_patterns: String,
) -> Result<Vec<String>, Rejection> {
let index_pattern = percent_decode_str(&comma_separated_index_patterns)
.decode_utf8()
.context("index pattern does not contain valid utf8 characters")
.unwrap()
.to_string();

let mut index_ids_patterns = Vec::new();
for index_id_pattern in
COMMA_SEPARATED_INDEX_PATTERNS_REGEX.split(&comma_separated_index_patterns)
{
for index_id_pattern in index_pattern.split(',').collect::<Vec<_>>() {
validate_index_id_pattern(index_id_pattern).map_err(|error| {
warp::reject::custom(crate::rest::InvalidArgument(error.to_string()))
})?;
Expand Down Expand Up @@ -538,16 +538,16 @@ mod tests {
.await
.unwrap();
assert_eq!(
extract_index_id_patterns("my-index-1,my-index-2".to_string())
extract_index_id_patterns("my-index-1,my-index-2%2A".to_string())
.await
.unwrap(),
vec!["my-index-1".to_string(), "my-index-2".to_string()]
vec!["my-index-1".to_string(), "my-index-2*".to_string()]
);
assert_eq!(
extract_index_id_patterns("my-index-1%2Cmy-index-2".to_string())
extract_index_id_patterns("my-index-1%2Cmy-index-%2A".to_string())
.await
.unwrap(),
vec!["my-index-1".to_string(), "my-index-2".to_string()]
vec!["my-index-1".to_string(), "my-index-*".to_string()]
);
extract_index_id_patterns("".to_string()).await.unwrap_err();
extract_index_id_patterns(" ".to_string())
Expand Down