Skip to content

Commit f843b88

Browse files
authored
URL decode s3 key in s3:ObjectCreated (#5692)
When a file includes `:`, it gets converted to `%3A`, and doing `GetObject` fails.
1 parent e49d7ec commit f843b88

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

quickwit/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

quickwit/quickwit-indexing/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ libz-sys = { workspace = true, optional = true }
3232
once_cell = { workspace = true }
3333
oneshot = { workspace = true }
3434
openssl = { workspace = true, optional = true }
35+
percent-encoding = { workspace = true }
3536
pulsar = { workspace = true, optional = true }
3637
quickwit-query = { workspace = true }
3738
regex = { workspace = true }

quickwit/quickwit-indexing/src/source/queue_sources/message.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,10 @@ fn uri_from_s3_notification(message: &[u8], ack_id: &str) -> Result<Uri, PreProc
157157
let bucket = value["Records"][0]["s3"]["bucket"]["name"]
158158
.as_str()
159159
.context("invalid S3 notification: Records[0].s3.bucket.name not found")?;
160-
Uri::from_str(&format!("s3://{}/{}", bucket, key)).map_err(|e| e.into())
160+
let encoded_key = percent_encoding::percent_decode(key.as_bytes())
161+
.decode_utf8()
162+
.context("invalid S3 notification: Records[0].s3.object.key could not be url decoded")?;
163+
Uri::from_str(&format!("s3://{}/{}", bucket, encoded_key)).map_err(|e| e.into())
161164
}
162165

163166
/// A message for which we know as much of the global processing status as
@@ -344,4 +347,51 @@ mod tests {
344347
panic!("Expected skippable error");
345348
}
346349
}
350+
351+
#[test]
352+
fn test_uri_from_s3_notification_url_decode() {
353+
let test_message = r#"
354+
{
355+
"Records": [
356+
{
357+
"eventVersion": "2.1",
358+
"eventSource": "aws:s3",
359+
"awsRegion": "us-west-2",
360+
"eventTime": "2021-05-22T09:22:41.789Z",
361+
"eventName": "ObjectCreated:Put",
362+
"userIdentity": {
363+
"principalId": "AWS:AIDAJDPLRKLG7UEXAMPLE"
364+
},
365+
"requestParameters": {
366+
"sourceIPAddress": "127.0.0.1"
367+
},
368+
"responseElements": {
369+
"x-amz-request-id": "C3D13FE58DE4C810",
370+
"x-amz-id-2": "FMyUVURIx7Zv2cPi/IZb9Fk1/U4QfTaVK5fahHPj/"
371+
},
372+
"s3": {
373+
"s3SchemaVersion": "1.0",
374+
"configurationId": "testConfigRule",
375+
"bucket": {
376+
"name": "mybucket",
377+
"ownerIdentity": {
378+
"principalId": "A3NL1KOZZKExample"
379+
},
380+
"arn": "arn:aws:s3:::mybucket"
381+
},
382+
"object": {
383+
"key": "hello%3A%3Aworld%3A%3Alogs.json",
384+
"size": 1024,
385+
"eTag": "d41d8cd98f00b204e9800998ecf8427e",
386+
"versionId": "096fKKXTRTtl3on89fVO.nfljtsv6qko",
387+
"sequencer": "0055AED6DCD90281E5"
388+
}
389+
}
390+
}
391+
]
392+
}"#;
393+
let actual_uri = uri_from_s3_notification(test_message.as_bytes(), "myackid").unwrap();
394+
let expected_uri = Uri::from_str("s3://mybucket/hello::world::logs.json").unwrap();
395+
assert_eq!(actual_uri, expected_uri);
396+
}
347397
}

0 commit comments

Comments
 (0)