Unverified Commit fe0b125d authored by Russell Cohen's avatar Russell Cohen Committed by GitHub
Browse files

Fix label & query URI encoding (#953)

* Fix label & query URI encoding

https://github.com/awslabs/aws-sdk-rust/issues/331 demonstrated that we were failing to properly encode characters for URI path components and query components in several situation. This:
- Fixes the specific bugs
- Adds proptests (run locally with 16K cases) to verify that this is the complete set.
- Adds an S3-specific protocol test that targets this issue

* Make the test a bit stronger

* Update changelog
parent c4ba838a
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -129,3 +129,15 @@ message = "The features `aws-hyper/rustls` and `aws-hyper/native-tls` have been
meta = { "breaking" = true, "tada" = false, "bug" = false }
references = ["smithy-rs#947"]
author = "rcoh"

[[aws-sdk-rust]]
message = "Fixed a bug where certain characters caused a panic during URI encoding."
meta = { "breaking" = false, "tada" = false, "bug" = true }
references = ["smithy-rs#953", "aws-sdk-rust#331"]
author = "rcoh"

[[smithy-rs]]
message = "Fixed a bug where certain characters caused a panic during URI encoding."
meta = { "breaking" = false, "tada" = false, "bug" = true }
references = ["smithy-rs#953", "aws-sdk-rust#331"]
author = "rcoh"
+16 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ apply NotFound @httpResponseTests([
    }
])


apply GetBucketLocation @httpResponseTests([
    {
        id: "GetBucketLocation",
@@ -183,3 +184,18 @@ apply PutObject @httpRequestTests([
        }
    }
])

apply HeadObject @httpRequestTests([
    {
        id: "HeadObjectUriEncoding",
        documentation: "https://github.com/awslabs/aws-sdk-rust/issues/331",

        method: "HEAD",
        protocol: "aws.protocols#restXml",
        uri: "/test-bucket/%3C%3E%20%60%3F%F0%9F%90%B1",
        params: {
            Bucket: "test-bucket",
            Key: "<> `?🐱",
        }
    }
])
+10 −0
Original line number Diff line number Diff line
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc dfac816a3fc3fff8523f1a1707da0065b72fc3c0d70fce001627a8e2e7ee5e0e # shrinks to s = ">"
cc 22bce3cd581f5f5a55e6ba18b1fb027481a496f6b35fee6dc4ef84659b99ddca # shrinks to s = "`"
cc be619cccfee48e3bf642cf0f82e98e00dceccbe10963fbaf3a622a68a55a3227 # shrinks to s = "?\""
cc 3e0b2e6f64642d7c58e5d2fe9223f75238a874bd8c3812dcb3ecc721d9aa0243 # shrinks to s = " "
+9 −0
Original line number Diff line number Diff line
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc b8ff8401495a7e4b4604f4438d8fc6b0ba63a58ddf58273ddcb3bb511e5cf91a # shrinks to s = "<"
cc 59ee40f6a097f80254a91d0ee7d6cde97a353f7ccdf83eddd1d437781019431f # shrinks to s = "\""
cc 65e6e5f9082c6cbebf599af889721d30d8ee2388f2f7be372520aa86526c8379 # shrinks to s = ">"
+13 −3
Original line number Diff line number Diff line
@@ -6,15 +6,15 @@
//! Formatting values as Smithy
//! [httpLabel](https://awslabs.github.io/smithy/1.0/spec/core/http-traits.html#httplabel-trait)

use crate::urlencode::BASE_SET;
use crate::urlencode::LABEL_SET;
use aws_smithy_types::date_time::{DateTimeFormatError, Format};
use aws_smithy_types::DateTime;
use percent_encoding::AsciiSet;

const GREEDY: &AsciiSet = &BASE_SET.remove(b'/');
const GREEDY: &AsciiSet = &LABEL_SET.remove(b'/');

pub fn fmt_string<T: AsRef<str>>(t: T, greedy: bool) -> String {
    let uri_set = if greedy { GREEDY } else { BASE_SET };
    let uri_set = if greedy { GREEDY } else { LABEL_SET };
    percent_encoding::utf8_percent_encode(t.as_ref(), uri_set).to_string()
}

@@ -25,10 +25,20 @@ pub fn fmt_timestamp(t: &DateTime, format: Format) -> Result<String, DateTimeFor
#[cfg(test)]
mod test {
    use crate::label::fmt_string;
    use http::Uri;
    use proptest::proptest;

    #[test]
    fn greedy_params() {
        assert_eq!(fmt_string("a/b", false), "a%2Fb");
        assert_eq!(fmt_string("a/b", true), "a/b");
    }

    proptest! {
        #[test]
        fn test_encode_request(s: String) {
            let _: Uri = format!("http://host.example.com/{}", fmt_string(&s, false)).parse().expect("all strings should be encoded properly");
            let _: Uri = format!("http://host.example.com/{}", fmt_string(&s, true)).parse().expect("all strings should be encoded properly");
        }
    }
}
Loading