fix: handle raw URI paths in SigV4 (#2593)

Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
安正超
2026-04-19 01:09:00 +08:00
committed by GitHub
parent 9677320f23
commit b8c788ffca
3 changed files with 62 additions and 3 deletions
Generated
+1 -1
View File
@@ -8778,7 +8778,7 @@ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
name = "s3s"
version = "0.14.0-dev"
source = "git+https://github.com/rustfs/s3s?rev=0dd8fcaaa72eda68fafd49c38daea43bb8697558#0dd8fcaaa72eda68fafd49c38daea43bb8697558"
source = "git+https://github.com/rustfs/s3s?rev=a3b16608df35aaeed8fff08b4988d03f4ca9445b#a3b16608df35aaeed8fff08b4988d03f4ca9445b"
dependencies = [
"arc-swap",
"arrayvec",
+1 -1
View File
@@ -248,7 +248,7 @@ rumqttc = { package = "rumqttc-next", version = "0.30.0", features = ["websocket
rustix = { version = "1.1.4", features = ["fs"] }
rust-embed = { version = "8.11.0" }
rustc-hash = { version = "2.1.2" }
s3s = { git = "https://github.com/rustfs/s3s", rev = "0dd8fcaaa72eda68fafd49c38daea43bb8697558", features = ["minio"] }
s3s = { git = "https://github.com/rustfs/s3s", rev = "a3b16608df35aaeed8fff08b4988d03f4ca9445b", features = ["minio"] }
serial_test = "3.4.0"
shadow-rs = { version = "1.7.1", default-features = false }
siphasher = "1.0.2"
+60 -1
View File
@@ -26,10 +26,16 @@
#[cfg(test)]
mod tests {
use crate::common::{RustFSTestEnvironment, init_logging};
use crate::common::{RustFSTestEnvironment, init_logging, local_http_client};
use aws_sdk_s3::Client;
use aws_sdk_s3::primitives::ByteStream;
use http::StatusCode;
use http::header::HOST;
use rustfs_signer::constants::UNSIGNED_PAYLOAD;
use rustfs_signer::sign_v4;
use s3s::Body;
use serial_test::serial;
use std::error::Error;
use tracing::{debug, info};
/// Helper function to create an S3 client for testing
@@ -56,6 +62,30 @@ mod tests {
}
}
async fn signed_get(
url: &str,
access_key: &str,
secret_key: &str,
) -> Result<reqwest::Response, Box<dyn Error + Send + Sync>> {
let uri = url.parse::<http::Uri>()?;
let authority = uri.authority().ok_or("request URL missing authority")?.to_string();
let request = http::Request::builder()
.method(http::Method::GET)
.uri(uri)
.header(HOST, authority)
.header("x-amz-content-sha256", UNSIGNED_PAYLOAD)
.body(Body::empty())?;
let signed = sign_v4(request, 0, access_key, secret_key, "", "us-east-1");
let client = local_http_client();
let mut request_builder = client.get(url);
for (name, value) in signed.headers() {
request_builder = request_builder.header(name, value);
}
Ok(request_builder.send().await?)
}
/// Test PUT and GET with space character in path
///
/// This reproduces Part A of the issue:
@@ -274,6 +304,35 @@ mod tests {
info!("Test completed successfully");
}
#[tokio::test]
#[serial]
async fn test_signed_get_missing_object_with_trailing_equals_returns_no_such_key() -> Result<(), Box<dyn Error + Send + Sync>>
{
init_logging();
let mut env = RustFSTestEnvironment::new().await?;
env.start_rustfs_server(vec![]).await?;
let client = create_s3_client(&env);
let bucket = "test-missing-equals-key";
create_bucket(&client, bucket).await?;
let url = format!("{}/{}/path/sitemap.xmlage=", env.url, bucket);
let response = signed_get(&url, &env.access_key, &env.secret_key).await?;
assert_eq!(
response.status(),
StatusCode::NOT_FOUND,
"missing object key ending with '=' should pass signature validation before object lookup"
);
let body = response.text().await?;
assert!(body.contains("<Code>NoSuchKey</Code>"), "expected NoSuchKey XML response, got: {body}");
env.stop_server();
Ok(())
}
/// Test DELETE operation with special characters
#[tokio::test]
#[serial]