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

Fix for parsing string headers (#525)

* Fix for parsing string headers

* Rename function & add docs
parent f89f9417
Loading
Loading
Loading
Loading
+31 −1
Original line number Diff line number Diff line
@@ -17,7 +17,8 @@ service RestXmlExtras {
        XmlMapsFlattenedNestedXmlNamespace,
        EnumKeys,
        PrimitiveIntOpXml,
        ChecksumRequired
        ChecksumRequired,
        StringHeader,
    ]
}

@@ -203,3 +204,32 @@ operation ChecksumRequired {
structure ChecksumRequiredInput {
    field: String
}


@httpResponseTests([{
    id: "DeserHeaderStringCommas",
    code: 200,
    documentation: """
    Regression test for https://github.com/awslabs/aws-sdk-rust/issues/122
    where `,` was eagerly used to split fields in cases where the input was not
    a list.
    """,
    body: "",
    headers: { "x-field": "a,b,c" },
    params: {
        field: "a,b,c"
    },
    protocol: "aws.protocols#restXml"
}])
@http(uri: "/StringHeader", method: "POST")
operation StringHeader {
    output: StringHeaderOutput
}

structure StringHeaderOutput {
    @httpHeader("x-field")
    field: String,

    @httpHeader("x-enum")
    enumHeader: StringEnum
}
+7 −0
Original line number Diff line number Diff line
@@ -212,6 +212,13 @@ class ResponseBindingGenerator(protocolConfig: ProtocolConfig, private val opera
     */
    private fun RustWriter.deserializeFromHeader(targetType: Shape, memberShape: MemberShape) {
        val rustType = symbolProvider.toSymbol(targetType).rustType().stripOuter<RustType.Option>()
        // Normally, we go through a flow that looks for `,`s but that's wrong if the output
        // is just a single string (which might include `,`s.).
        // MediaType doesn't include `,` since it's base64, send that through the normal path
        if (targetType is StringShape && !targetType.hasTrait<MediaTypeTrait>()) {
            rust("#T::one_or_none(headers)", headerUtil)
            return
        }
        val (coreType, coreShape) = if (targetType is CollectionShape) {
            rustType.stripOuter<RustType.Container>() to model.expectShape(targetType.member.target)
        } else {
+18 −1
Original line number Diff line number Diff line
@@ -73,8 +73,25 @@ where
    Ok(out)
}

/// Read exactly one or none from a headers iterator
///
/// This function does not perform comma splitting like `read_many`
pub fn one_or_none<T: FromStr>(
    mut values: ValueIter<HeaderValue>,
) -> Result<Option<T>, ParseError> {
    let first = match values.next() {
        Some(v) => v,
        None => return Ok(None),
    };
    let value = std::str::from_utf8(first.as_bytes()).map_err(|_| ParseError)?;
    match values.next() {
        None => T::from_str(value.trim()).map_err(|_| ParseError).map(Some),
        Some(_) => Err(ParseError),
    }
}

/// Read one comma delimited value for `FromStr` types
pub fn read_one<T>(s: &[u8]) -> Result<(T, &[u8]), ParseError>
fn read_one<T>(s: &[u8]) -> Result<(T, &[u8]), ParseError>
where
    T: FromStr,
{