AWS SDK

AWS SDK

rev. e063993ca0ab793f44c575dbe707d50a5e3e2406

Files changed:

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-json/src/codec/serializer.rs

@@ -26,26 +160,172 @@
   46     46   
   47     47   
    /// Handles comma separators and member names before writing a value.
   48     48   
    /// When inside a map (map_depth > 0), restores expecting_map_key after
   49     49   
    /// the value so the next write_string is treated as a map key.
   50     50   
    fn prefix(&mut self, schema: &Schema) {
   51     51   
        if self.needs_comma {
   52     52   
            self.output.push(',');
   53     53   
        }
   54     54   
        if let Some(name) = self.field_name(schema) {
   55     55   
            self.output.push('"');
   56         -
            self.output.push_str(name);
          56  +
            self.output.push_str(&crate::escape::escape_string(name));
   57     57   
            self.output.push_str("\":");
   58     58   
        }
   59     59   
        self.needs_comma = true;
   60     60   
        // Inside a map, after writing a value the next write_string should be a key.
   61     61   
        // This is safe because write_string checks expecting_map_key *before* calling
   62     62   
        // prefix(), so this only affects the *next* write_string call.
   63     63   
        if self.map_depth > 0 {
   64     64   
            self.expecting_map_key = true;
   65     65   
        }
   66     66   
    }
   67     67   
   68     68   
    /// Resolves the JSON field name for a member schema.
   69     69   
    fn field_name<'a>(&self, schema: &'a Schema) -> Option<&'a str> {
   70     70   
        self.settings.member_to_field(schema)
   71     71   
    }
   72     72   
   73     73   
    /// Gets the timestamp format to use, respecting @timestampFormat trait.
   74     74   
    fn get_timestamp_format(&self, schema: &Schema) -> TimestampFormat {
   75     75   
        if let Some(ts_trait) = schema.timestamp_format() {
   76     76   
            return match ts_trait.format() {
   77     77   
                aws_smithy_schema::traits::TimestampFormat::EpochSeconds => {
   78     78   
                    TimestampFormat::EpochSeconds
   79     79   
                }
   80     80   
                aws_smithy_schema::traits::TimestampFormat::HttpDate => TimestampFormat::HttpDate,
   81     81   
                aws_smithy_schema::traits::TimestampFormat::DateTime => TimestampFormat::DateTime,
   82     82   
            };
   83     83   
        }
   84     84   
        self.settings.default_timestamp_format
   85     85   
    }
   86     86   
   87     87   
    fn write_json_value(&mut self, doc: &Document) {
   88     88   
        use crate::serialize::JsonValueWriter;
   89     89   
        let writer = JsonValueWriter::new(&mut self.output);
   90     90   
        writer.document(doc);
   91     91   
    }
   92     92   
}
   93     93   
          94  +
impl aws_smithy_schema::codec::FinishSerializer for JsonSerializer {
          95  +
    fn finish(self) -> Vec<u8> {
          96  +
        self.output.into_bytes()
          97  +
    }
          98  +
}
          99  +
   94    100   
impl ShapeSerializer for JsonSerializer {
   95    101   
    fn write_struct(
   96    102   
        &mut self,
   97    103   
        schema: &Schema,
   98    104   
        value: &dyn SerializableStruct,
   99    105   
    ) -> Result<(), SerdeError> {
  100    106   
        self.prefix(schema);
  101    107   
        self.output.push('{');
  102         -
        let saved = self.needs_comma;
         108  +
        let saved_comma = self.needs_comma;
  103    109   
        let saved_depth = self.map_depth;
         110  +
        let saved_map_key = self.expecting_map_key;
  104    111   
        self.needs_comma = false;
  105         -
        // Reset map_depth so struct members don't trigger map-key logic in prefix().
         112  +
        // Reset map state so struct members don't trigger map-key logic.
  106    113   
        // Restored after the struct body so an enclosing map resumes correctly.
  107    114   
        self.map_depth = 0;
         115  +
        self.expecting_map_key = false;
  108    116   
        value.serialize_members(self)?;
  109    117   
        self.output.push('}');
  110         -
        self.needs_comma = saved;
         118  +
        self.needs_comma = saved_comma;
  111    119   
        self.map_depth = saved_depth;
         120  +
        self.expecting_map_key = saved_map_key;
  112    121   
        Ok(())
  113    122   
    }
  114    123   
  115    124   
    fn write_list(
  116    125   
        &mut self,
  117    126   
        schema: &Schema,
  118    127   
        write_elements: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
  119    128   
    ) -> Result<(), SerdeError> {
  120    129   
        self.prefix(schema);
  121    130   
        self.output.push('[');
  122    131   
        let saved = self.needs_comma;
  123    132   
        let saved_depth = self.map_depth;
         133  +
        let saved_map_key = self.expecting_map_key;
  124    134   
        self.needs_comma = false;
  125         -
        // Reset map_depth so list elements don't trigger map-key logic in prefix().
         135  +
        // Reset map state so list elements don't trigger map-key logic in prefix().
  126    136   
        self.map_depth = 0;
         137  +
        self.expecting_map_key = false;
  127    138   
        write_elements(self)?;
  128    139   
        self.output.push(']');
  129    140   
        self.needs_comma = saved;
  130    141   
        self.map_depth = saved_depth;
         142  +
        self.expecting_map_key = saved_map_key;
  131    143   
        Ok(())
  132    144   
    }
  133    145   
  134    146   
    fn write_map(
  135    147   
        &mut self,
  136    148   
        schema: &Schema,
  137    149   
        write_entries: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
  138    150   
    ) -> Result<(), SerdeError> {
  139    151   
        self.prefix(schema);
  140    152   
        self.output.push('{');
@@ -169,181 +239,275 @@
  189    201   
        use std::fmt::Write;
  190    202   
        self.prefix(schema);
  191    203   
        write!(&mut self.output, "{}", value).map_err(|e| SerdeError::WriteFailed {
  192    204   
            message: e.to_string(),
  193    205   
        })
  194    206   
    }
  195    207   
  196    208   
    fn write_float(&mut self, schema: &Schema, value: f32) -> Result<(), SerdeError> {
  197    209   
        use std::fmt::Write;
  198    210   
        self.prefix(schema);
  199         -
        write!(&mut self.output, "{}", value).map_err(|e| SerdeError::WriteFailed {
  200         -
            message: e.to_string(),
  201         -
        })
         211  +
        if value.is_nan() {
         212  +
            self.output.push_str("\"NaN\"");
         213  +
            Ok(())
         214  +
        } else if value.is_infinite() {
         215  +
            if value.is_sign_positive() {
         216  +
                self.output.push_str("\"Infinity\"");
         217  +
            } else {
         218  +
                self.output.push_str("\"-Infinity\"");
         219  +
            }
         220  +
            Ok(())
         221  +
        } else {
         222  +
            write!(&mut self.output, "{}", value).map_err(|e| SerdeError::WriteFailed {
         223  +
                message: e.to_string(),
         224  +
            })
         225  +
        }
  202    226   
    }
  203    227   
  204    228   
    fn write_double(&mut self, schema: &Schema, value: f64) -> Result<(), SerdeError> {
  205    229   
        use std::fmt::Write;
  206    230   
        self.prefix(schema);
  207         -
        write!(&mut self.output, "{}", value).map_err(|e| SerdeError::WriteFailed {
  208         -
            message: e.to_string(),
  209         -
        })
         231  +
        if value.is_nan() {
         232  +
            self.output.push_str("\"NaN\"");
         233  +
            Ok(())
         234  +
        } else if value.is_infinite() {
         235  +
            if value.is_sign_positive() {
         236  +
                self.output.push_str("\"Infinity\"");
         237  +
            } else {
         238  +
                self.output.push_str("\"-Infinity\"");
         239  +
            }
         240  +
            Ok(())
         241  +
        } else {
         242  +
            write!(&mut self.output, "{}", value).map_err(|e| SerdeError::WriteFailed {
         243  +
                message: e.to_string(),
         244  +
            })
         245  +
        }
  210    246   
    }
  211    247   
  212    248   
    fn write_big_integer(&mut self, schema: &Schema, value: &BigInteger) -> Result<(), SerdeError> {
  213    249   
        self.prefix(schema);
  214    250   
        self.output.push_str(value.as_ref());
  215    251   
        Ok(())
  216    252   
    }
  217    253   
  218    254   
    fn write_big_decimal(&mut self, schema: &Schema, value: &BigDecimal) -> Result<(), SerdeError> {
  219    255   
        self.prefix(schema);
@@ -265,301 +324,361 @@
  285    321   
        self.prefix(schema);
  286    322   
        self.output.push_str("null");
  287    323   
        Ok(())
  288    324   
    }
  289    325   
}
  290    326   
  291    327   
#[cfg(test)]
  292    328   
mod tests {
  293    329   
    use super::*;
  294    330   
    use aws_smithy_schema::prelude::*;
         331  +
    use aws_smithy_schema::ShapeType;
  295    332   
  296    333   
    #[test]
  297    334   
    fn test_write_boolean() {
  298    335   
        let mut ser = JsonSerializer::new(Arc::new(JsonCodecSettings::default()));
  299    336   
        ser.write_boolean(&BOOLEAN, true).unwrap();
  300    337   
        let output = ser.finish();
  301    338   
        assert_eq!(String::from_utf8(output).unwrap(), "true");
  302    339   
    }
  303    340   
  304    341   
    #[test]
@@ -607,644 +637,719 @@
  627    664   
        assert_eq!(output, r#"{"foo":"hello","Baz":42}"#);
  628    665   
  629    666   
        // With use_json_name=false, "bar" should stay as "bar"
  630    667   
        let mut ser = JsonSerializer::new(Arc::new(
  631    668   
            JsonCodecSettings::builder().use_json_name(false).build(),
  632    669   
        ));
  633    670   
        ser.write_struct(&struct_schema, &TestStruct).unwrap();
  634    671   
        let output = String::from_utf8(ser.finish()).unwrap();
  635    672   
        assert_eq!(output, r#"{"foo":"hello","bar":42}"#);
  636    673   
    }
         674  +
         675  +
    #[test]
         676  +
    fn struct_inside_map_serializes_member_names_correctly() {
         677  +
        // Regression test: when a struct is a map value, the map's expecting_map_key
         678  +
        // flag must not leak into the struct's member serialization.
         679  +
        use aws_smithy_schema::serde::{SerializableStruct, ShapeSerializer};
         680  +
         681  +
        static INNER_NAME: Schema = Schema::new_member(
         682  +
            aws_smithy_schema::shape_id!("test", "Inner"),
         683  +
            ShapeType::String,
         684  +
            "name",
         685  +
            0,
         686  +
        );
         687  +
        static INNER_MEMBERS: &[&Schema] = &[&INNER_NAME];
         688  +
        static INNER_SCHEMA: Schema = Schema::new_struct(
         689  +
            aws_smithy_schema::shape_id!("test", "Inner"),
         690  +
            ShapeType::Structure,
         691  +
            INNER_MEMBERS,
         692  +
        );
         693  +
         694  +
        struct Inner;
         695  +
        impl SerializableStruct for Inner {
         696  +
            fn serialize_members(
         697  +
                &self,
         698  +
                ser: &mut dyn ShapeSerializer,
         699  +
            ) -> Result<(), aws_smithy_schema::serde::SerdeError> {
         700  +
                ser.write_string(&INNER_NAME, "Alice")
         701  +
            }
         702  +
        }
         703  +
         704  +
        static MAP_SCHEMA: Schema = Schema::new(
         705  +
            aws_smithy_schema::shape_id!("test", "MyMap"),
         706  +
            ShapeType::Map,
         707  +
        );
         708  +
         709  +
        let mut ser = JsonSerializer::new(Arc::new(JsonCodecSettings::default()));
         710  +
        ser.write_map(&MAP_SCHEMA, &|ser| {
         711  +
            ser.write_string(&aws_smithy_schema::prelude::STRING, "key1")?;
         712  +
            ser.write_struct(&INNER_SCHEMA, &Inner)?;
         713  +
            Ok(())
         714  +
        })
         715  +
        .unwrap();
         716  +
        let output = String::from_utf8(ser.finish()).unwrap();
         717  +
        assert_eq!(output, r#"{"key1":{"name":"Alice"}}"#);
         718  +
    }
  637    719   
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-json/src/lib.rs

@@ -1,1 +23,24 @@
   13     13   
    unreachable_pub,
   14     14   
    // Enabling this requires fixing a macro but I don't understand how to do that.
   15     15   
    // rust_2018_idioms
   16     16   
)]
   17     17   
   18     18   
//! JSON Abstractions for Smithy
   19     19   
   20     20   
pub mod codec;
   21     21   
pub mod deserialize;
   22     22   
mod escape;
          23  +
pub mod protocol;
   23     24   
pub mod serialize;

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-json/src/protocol/aws_json_rpc.rs

@@ -0,1 +0,198 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
           6  +
//! AWS JSON RPC protocol implementation (`awsJson1_0` and `awsJson1_1`).
           7  +
//!
           8  +
//! # Protocol behaviors
           9  +
//!
          10  +
//! - HTTP method: always POST, path: always `/`
          11  +
//! - `X-Amz-Target`: `{ServiceName}.{OperationName}` (required)
          12  +
//! - Does **not** use `@jsonName` trait
          13  +
//! - Default timestamp format: `epoch-seconds`
          14  +
//! - Ignores HTTP binding traits
          15  +
//!
          16  +
//! # Differences between 1.0 and 1.1
          17  +
//!
          18  +
//! - Content-Type: `application/x-amz-json-1.0` vs `application/x-amz-json-1.1`
          19  +
//! - Error `__type` serialization differs on the server side, but clients MUST
          20  +
//!   accept either format for both versions.
          21  +
          22  +
use crate::codec::{JsonCodec, JsonCodecSettings};
          23  +
use aws_smithy_runtime_api::client::orchestrator::Metadata;
          24  +
use aws_smithy_schema::http_protocol::HttpRpcProtocol;
          25  +
use aws_smithy_schema::{shape_id, Schema, ShapeId};
          26  +
use aws_smithy_types::config_bag::ConfigBag;
          27  +
          28  +
/// AWS JSON RPC protocol (`awsJson1_0` / `awsJson1_1`).
          29  +
#[derive(Debug)]
          30  +
pub struct AwsJsonRpcProtocol {
          31  +
    inner: HttpRpcProtocol<JsonCodec>,
          32  +
    target_prefix: String,
          33  +
}
          34  +
          35  +
impl AwsJsonRpcProtocol {
          36  +
    /// Creates an AWS JSON 1.0 protocol instance.
          37  +
    ///
          38  +
    /// `target_prefix` is the Smithy service shape name used in the `X-Amz-Target` header
          39  +
    /// (e.g., `"TrentService"` for KMS, `"DynamoDB_20120810"` for DynamoDB).
          40  +
    pub fn aws_json_1_0(target_prefix: impl Into<String>) -> Self {
          41  +
        Self::new(
          42  +
            shape_id!("aws.protocols", "awsJson1_0"),
          43  +
            "application/x-amz-json-1.0",
          44  +
            target_prefix.into(),
          45  +
        )
          46  +
    }
          47  +
          48  +
    /// Creates an AWS JSON 1.1 protocol instance.
          49  +
    ///
          50  +
    /// `target_prefix` is the Smithy service shape name used in the `X-Amz-Target` header.
          51  +
    pub fn aws_json_1_1(target_prefix: impl Into<String>) -> Self {
          52  +
        Self::new(
          53  +
            shape_id!("aws.protocols", "awsJson1_1"),
          54  +
            "application/x-amz-json-1.1",
          55  +
            target_prefix.into(),
          56  +
        )
          57  +
    }
          58  +
          59  +
    fn new(protocol_id: ShapeId, content_type: &'static str, target_prefix: String) -> Self {
          60  +
        let codec = JsonCodec::new(
          61  +
            JsonCodecSettings::builder()
          62  +
                .use_json_name(false)
          63  +
                .default_timestamp_format(aws_smithy_types::date_time::Format::EpochSeconds)
          64  +
                .build(),
          65  +
        );
          66  +
        Self {
          67  +
            inner: HttpRpcProtocol::new(protocol_id, codec, content_type),
          68  +
            target_prefix,
          69  +
        }
          70  +
    }
          71  +
}
          72  +
          73  +
impl aws_smithy_schema::protocol::ClientProtocol for AwsJsonRpcProtocol {
          74  +
    fn protocol_id(&self) -> &ShapeId {
          75  +
        self.inner.protocol_id()
          76  +
    }
          77  +
          78  +
    fn serialize_request(
          79  +
        &self,
          80  +
        input: &dyn aws_smithy_schema::serde::SerializableStruct,
          81  +
        input_schema: &Schema,
          82  +
        endpoint: &str,
          83  +
        cfg: &ConfigBag,
          84  +
    ) -> Result<aws_smithy_runtime_api::http::Request, aws_smithy_schema::serde::SerdeError> {
          85  +
        let mut request = self
          86  +
            .inner
          87  +
            .serialize_request(input, input_schema, endpoint, cfg)?;
          88  +
        if let Some(metadata) = cfg.load::<Metadata>() {
          89  +
            request.headers_mut().insert(
          90  +
                "X-Amz-Target",
          91  +
                format!("{}.{}", self.target_prefix, metadata.name()),
          92  +
            );
          93  +
        }
          94  +
        Ok(request)
          95  +
    }
          96  +
          97  +
    fn deserialize_response<'a>(
          98  +
        &self,
          99  +
        response: &'a aws_smithy_runtime_api::http::Response,
         100  +
        output_schema: &Schema,
         101  +
        cfg: &ConfigBag,
         102  +
    ) -> Result<
         103  +
        Box<dyn aws_smithy_schema::serde::ShapeDeserializer + 'a>,
         104  +
        aws_smithy_schema::serde::SerdeError,
         105  +
    > {
         106  +
        self.inner
         107  +
            .deserialize_response(response, output_schema, cfg)
         108  +
    }
         109  +
}
         110  +
         111  +
#[cfg(test)]
         112  +
mod tests {
         113  +
    use super::*;
         114  +
    use aws_smithy_schema::protocol::ClientProtocol;
         115  +
    use aws_smithy_schema::serde::{SerdeError, SerializableStruct, ShapeSerializer};
         116  +
    use aws_smithy_schema::ShapeType;
         117  +
    use aws_smithy_types::config_bag::Layer;
         118  +
         119  +
    struct EmptyStruct;
         120  +
    impl SerializableStruct for EmptyStruct {
         121  +
        fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
         122  +
            Ok(())
         123  +
        }
         124  +
    }
         125  +
         126  +
    static TEST_SCHEMA: aws_smithy_schema::Schema =
         127  +
        aws_smithy_schema::Schema::new(shape_id!("test", "Input"), ShapeType::Structure);
         128  +
         129  +
    fn cfg_with_metadata(service: &str, operation: &str) -> ConfigBag {
         130  +
        let mut layer = Layer::new("test");
         131  +
        layer.store_put(Metadata::new(operation.to_string(), service.to_string()));
         132  +
        ConfigBag::of_layers(vec![layer])
         133  +
    }
         134  +
         135  +
    #[test]
         136  +
    fn json_1_0_content_type() {
         137  +
        let request = AwsJsonRpcProtocol::aws_json_1_0("TestService")
         138  +
            .serialize_request(
         139  +
                &EmptyStruct,
         140  +
                &TEST_SCHEMA,
         141  +
                "https://example.com",
         142  +
                &ConfigBag::base(),
         143  +
            )
         144  +
            .unwrap();
         145  +
        assert_eq!(
         146  +
            request.headers().get("Content-Type").unwrap(),
         147  +
            "application/x-amz-json-1.0"
         148  +
        );
         149  +
    }
         150  +
         151  +
    #[test]
         152  +
    fn json_1_1_content_type() {
         153  +
        let request = AwsJsonRpcProtocol::aws_json_1_1("TestService")
         154  +
            .serialize_request(
         155  +
                &EmptyStruct,
         156  +
                &TEST_SCHEMA,
         157  +
                "https://example.com",
         158  +
                &ConfigBag::base(),
         159  +
            )
         160  +
            .unwrap();
         161  +
        assert_eq!(
         162  +
            request.headers().get("Content-Type").unwrap(),
         163  +
            "application/x-amz-json-1.1"
         164  +
        );
         165  +
    }
         166  +
         167  +
    #[test]
         168  +
    fn sets_x_amz_target() {
         169  +
        let cfg = cfg_with_metadata("MyService", "DoThing");
         170  +
        let request = AwsJsonRpcProtocol::aws_json_1_0("MyService")
         171  +
            .serialize_request(&EmptyStruct, &TEST_SCHEMA, "https://example.com", &cfg)
         172  +
            .unwrap();
         173  +
        assert_eq!(
         174  +
            request.headers().get("X-Amz-Target").unwrap(),
         175  +
            "MyService.DoThing"
         176  +
        );
         177  +
    }
         178  +
         179  +
    #[test]
         180  +
    fn json_1_0_protocol_id() {
         181  +
        assert_eq!(
         182  +
            AwsJsonRpcProtocol::aws_json_1_0("Svc")
         183  +
                .protocol_id()
         184  +
                .as_str(),
         185  +
            "aws.protocols#awsJson1_0"
         186  +
        );
         187  +
    }
         188  +
         189  +
    #[test]
         190  +
    fn json_1_1_protocol_id() {
         191  +
        assert_eq!(
         192  +
            AwsJsonRpcProtocol::aws_json_1_1("Svc")
         193  +
                .protocol_id()
         194  +
                .as_str(),
         195  +
            "aws.protocols#awsJson1_1"
         196  +
        );
         197  +
    }
         198  +
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-json/src/protocol/aws_rest_json_1.rs

@@ -0,1 +0,87 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
           6  +
//! AWS REST JSON 1.0 protocol implementation.
           7  +
//!
           8  +
//! This module provides [`AwsRestJsonProtocol`], which constructs an
           9  +
//! [`HttpBindingProtocol`] with a [`JsonCodec`] configured for the
          10  +
//! `aws.protocols#restJson1` protocol:
          11  +
//!
          12  +
//! - Uses `@jsonName` trait for JSON property names
          13  +
//! - Default timestamp format: `epoch-seconds`
          14  +
//! - Content-Type: `application/json`
          15  +
          16  +
use crate::codec::{JsonCodec, JsonCodecSettings};
          17  +
use aws_smithy_schema::http_protocol::HttpBindingProtocol;
          18  +
use aws_smithy_schema::{Schema, ShapeId};
          19  +
use aws_smithy_types::config_bag::ConfigBag;
          20  +
          21  +
static PROTOCOL_ID: ShapeId = ShapeId::from_static("aws.protocols", "restJson1", "");
          22  +
          23  +
/// AWS REST JSON 1.0 protocol (`aws.protocols#restJson1`).
          24  +
///
          25  +
/// This is a thin configuration wrapper that constructs an [`HttpBindingProtocol`]
          26  +
/// with a [`JsonCodec`] using REST JSON settings. The `HttpBindingProtocol` handles
          27  +
/// splitting members between HTTP bindings and the JSON payload.
          28  +
#[derive(Debug)]
          29  +
pub struct AwsRestJsonProtocol {
          30  +
    inner: HttpBindingProtocol<JsonCodec>,
          31  +
}
          32  +
          33  +
impl AwsRestJsonProtocol {
          34  +
    /// Creates a new REST JSON protocol with default settings.
          35  +
    pub fn new() -> Self {
          36  +
        let codec = JsonCodec::new(
          37  +
            JsonCodecSettings::builder()
          38  +
                .use_json_name(true)
          39  +
                .default_timestamp_format(aws_smithy_types::date_time::Format::EpochSeconds)
          40  +
                .build(),
          41  +
        );
          42  +
        Self {
          43  +
            inner: HttpBindingProtocol::new(PROTOCOL_ID, codec, "application/json"),
          44  +
        }
          45  +
    }
          46  +
          47  +
    /// Returns a reference to the inner `HttpBindingProtocol`.
          48  +
    pub fn inner(&self) -> &HttpBindingProtocol<JsonCodec> {
          49  +
        &self.inner
          50  +
    }
          51  +
}
          52  +
          53  +
impl Default for AwsRestJsonProtocol {
          54  +
    fn default() -> Self {
          55  +
        Self::new()
          56  +
    }
          57  +
}
          58  +
          59  +
impl aws_smithy_schema::protocol::ClientProtocol for AwsRestJsonProtocol {
          60  +
    fn protocol_id(&self) -> &ShapeId {
          61  +
        self.inner.protocol_id()
          62  +
    }
          63  +
          64  +
    fn serialize_request(
          65  +
        &self,
          66  +
        input: &dyn aws_smithy_schema::serde::SerializableStruct,
          67  +
        input_schema: &Schema,
          68  +
        endpoint: &str,
          69  +
        cfg: &ConfigBag,
          70  +
    ) -> Result<aws_smithy_runtime_api::http::Request, aws_smithy_schema::serde::SerdeError> {
          71  +
        self.inner
          72  +
            .serialize_request(input, input_schema, endpoint, cfg)
          73  +
    }
          74  +
          75  +
    fn deserialize_response<'a>(
          76  +
        &self,
          77  +
        response: &'a aws_smithy_runtime_api::http::Response,
          78  +
        output_schema: &Schema,
          79  +
        cfg: &ConfigBag,
          80  +
    ) -> Result<
          81  +
        Box<dyn aws_smithy_schema::serde::ShapeDeserializer + 'a>,
          82  +
        aws_smithy_schema::serde::SerdeError,
          83  +
    > {
          84  +
        self.inner
          85  +
            .deserialize_response(response, output_schema, cfg)
          86  +
    }
          87  +
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-json/src/protocol/mod.rs

@@ -0,1 +0,9 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
           6  +
//! Protocol implementations for JSON-based Smithy protocols.
           7  +
           8  +
pub mod aws_json_rpc;
           9  +
pub mod aws_rest_json_1;

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-legacy-http/Cargo.toml

@@ -1,1 +73,73 @@
    1      1   
# Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
    2      2   
[package]
    3      3   
name = "aws-smithy-legacy-http"
    4         -
version = "0.62.14"
           4  +
version = "0.62.15"
    5      5   
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>", "Russell Cohen <rcoh@amazon.com>"]
    6      6   
description = "Smithy HTTP-0x logic for smithy-rs."
    7      7   
edition = "2021"
    8      8   
license = "Apache-2.0"
    9      9   
repository = "https://github.com/smithy-lang/smithy-rs"
   10     10   
rust-version = "1.91.1"
   11     11   
[package.metadata.docs.rs]
   12     12   
all-features = true
   13     13   
targets = ["x86_64-unknown-linux-gnu"]
   14     14   
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
   15     15   
rustdoc-args = ["--cfg", "docsrs"]
   16     16   
   17     17   
[features]
   18     18   
event-stream = ["aws-smithy-eventstream", "aws-smithy-http/event-stream"]
   19     19   
rt-tokio = ["aws-smithy-types/rt-tokio"]
   20     20   
   21     21   
[dependencies]
   22     22   
bytes = "1.11.1"
   23     23   
bytes-utils = "0.1"
   24     24   
percent-encoding = "2.3.1"
   25     25   
pin-project-lite = "0.2.14"
   26     26   
pin-utils = "0.1.0"
   27     27   
tracing = "0.1.44"
   28     28   
futures-core = "0.3.31"
   29     29   
   30     30   
[dependencies.aws-smithy-eventstream]
   31     31   
path = "../aws-smithy-eventstream"
   32     32   
optional = true
   33     33   
version = "0.60.20"
   34     34   
   35     35   
[dependencies.aws-smithy-http]
   36     36   
path = "../aws-smithy-http"
   37     37   
optional = true
   38     38   
version = "0.63.6"
   39     39   
   40     40   
[dependencies.aws-smithy-runtime-api]
   41     41   
path = "../aws-smithy-runtime-api"
   42     42   
features = ["client", "http-02x"]
   43         -
version = "1.11.6"
          43  +
version = "1.11.7"
   44     44   
   45     45   
[dependencies.aws-smithy-types]
   46     46   
path = "../aws-smithy-types"
   47     47   
features = ["byte-stream-poll-next", "http-body-0-4-x"]
   48     48   
version = "1.4.7"
   49     49   
   50     50   
[dependencies.http-02x]
   51     51   
package = "http"
   52     52   
version = "0.2.12"
   53     53   

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-mocks/Cargo.toml

@@ -1,1 +0,45 @@
   17     17   
[dependencies]
   18     18   
http = "1.3.1"
   19     19   
   20     20   
[dependencies.aws-smithy-types]
   21     21   
path = "../aws-smithy-types"
   22     22   
version = "1.4.7"
   23     23   
   24     24   
[dependencies.aws-smithy-runtime-api]
   25     25   
path = "../aws-smithy-runtime-api"
   26     26   
features = ["client", "http-1x", "test-util"]
   27         -
version = "1.11.6"
          27  +
version = "1.11.7"
   28     28   
   29     29   
[dependencies.aws-smithy-http-client]
   30     30   
path = "../aws-smithy-http-client"
   31     31   
features = ["test-util"]
   32     32   
version = "1.1.12"
   33     33   
[dev-dependencies.tokio]
   34     34   
version = "1"
   35     35   
features = ["full"]
   36     36   
   37     37   
[dev-dependencies.aws-smithy-async]
   38     38   
path = "../aws-smithy-async"
   39     39   
features = ["rt-tokio"]
   40     40   
version = "1.2.14"
   41     41   
   42     42   
[dev-dependencies.aws-smithy-runtime]
   43     43   
path = "../aws-smithy-runtime"
   44     44   
features = ["client"]
   45         -
version = "1.10.3"
          45  +
version = "1.10.4"

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-observability/Cargo.toml

@@ -1,1 +21,21 @@
    8      8   
license = "Apache-2.0"
    9      9   
repository = "https://github.com/awslabs/smithy-rs"
   10     10   
rust-version = "1.91.1"
   11     11   
[package.metadata.docs.rs]
   12     12   
all-features = true
   13     13   
targets = ["x86_64-unknown-linux-gnu"]
   14     14   
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
   15     15   
rustdoc-args = ["--cfg", "docsrs"]
   16     16   
[dependencies.aws-smithy-runtime-api]
   17     17   
path = "../aws-smithy-runtime-api"
   18         -
version = "1.11.6"
          18  +
version = "1.11.7"
   19     19   
   20     20   
[dev-dependencies]
   21     21   
serial_test = "3.1.1"

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-protocol-test/Cargo.toml

@@ -6,6 +46,46 @@
   26     26   
ciborium = "0.2"
   27     27   
pretty_assertions = "1.3"
   28     28   
regex-lite = "0.1.5"
   29     29   
roxmltree = "0.14.1"
   30     30   
serde_json = "1.0.146"
   31     31   
thiserror = "2"
   32     32   
   33     33   
[dependencies.aws-smithy-runtime-api]
   34     34   
path = "../aws-smithy-runtime-api"
   35     35   
features = ["client"]
   36         -
version = "1.11.6"
          36  +
version = "1.11.7"
   37     37   
   38     38   
[dependencies.http-0x]
   39     39   
package = "http"
   40     40   
version = "0.2.12"
   41     41   
optional = true
   42     42   
   43     43   
[dependencies.http-1x]
   44     44   
package = "http"
   45     45   
version = "1.3.1"
   46     46   
optional = true

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime-api/Cargo.toml

@@ -1,1 +34,34 @@
    1      1   
# Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
    2      2   
[package]
    3      3   
name = "aws-smithy-runtime-api"
    4         -
version = "1.11.6"
           4  +
version = "1.11.7"
    5      5   
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>", "Zelda Hessler <zhessler@amazon.com>"]
    6      6   
description = "Smithy runtime types."
    7      7   
edition = "2021"
    8      8   
license = "Apache-2.0"
    9      9   
repository = "https://github.com/smithy-lang/smithy-rs"
   10     10   
rust-version = "1.91.1"
   11     11   
[package.metadata.docs.rs]
   12     12   
all-features = true
   13     13   
targets = ["x86_64-unknown-linux-gnu"]
   14     14   
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime-api/src/client/ser_de.rs

@@ -25,25 +110,178 @@
   45     45   
    }
   46     46   
}
   47     47   
   48     48   
impl Storable for SharedRequestSerializer {
   49     49   
    type Storer = StoreReplace<Self>;
   50     50   
}
   51     51   
   52     52   
impl_shared_conversions!(convert SharedRequestSerializer from SerializeRequest using SharedRequestSerializer::new);
   53     53   
   54     54   
/// Deserialization implementation that converts an [`HttpResponse`] into an [`Output`] or [`Error`].
          55  +
///
          56  +
/// This trait uses a backward-compatible versioning pattern for methods that need
          57  +
/// access to [`ConfigBag`]. Each method has a `_with_config` variant:
          58  +
///
          59  +
/// - **Legacy implementations** override the original method (without config).
          60  +
///   The default `_with_config` variant delegates to it, ignoring the config.
          61  +
/// - **New implementations** override the `_with_config` variant.
          62  +
///   The default original method delegates to it with an empty config bag.
          63  +
///
          64  +
/// The orchestrator always calls the `_with_config` variants.
   55     65   
pub trait DeserializeResponse: Send + Sync + fmt::Debug {
   56     66   
    /// For streaming requests, deserializes the response headers.
   57     67   
    ///
   58         -
    /// The orchestrator will call `deserialize_streaming` first, and if it returns `None`,
   59         -
    /// then it will continue onto `deserialize_nonstreaming`. This method should only be
   60         -
    /// implemented for streaming requests where the streaming response body needs to be a part
   61         -
    /// of the deserialized output.
          68  +
    /// The orchestrator will call [`deserialize_streaming_with_config`](Self::deserialize_streaming_with_config)
          69  +
    /// first, and if it returns `None`, then it will continue onto
          70  +
    /// [`deserialize_nonstreaming_with_config`](Self::deserialize_nonstreaming_with_config).
          71  +
    ///
          72  +
    /// Override this or [`deserialize_streaming_with_config`](Self::deserialize_streaming_with_config),
          73  +
    /// but not both.
          74  +
    #[deprecated(
          75  +
        note = "Implement `deserialize_streaming_with_config` instead. This method will be removed in a future release."
          76  +
    )]
   62     77   
    fn deserialize_streaming(
   63     78   
        &self,
   64     79   
        response: &mut HttpResponse,
   65     80   
    ) -> Option<Result<Output, OrchestratorError<Error>>> {
   66     81   
        let _ = response;
   67     82   
        None
   68     83   
    }
   69     84   
          85  +
    /// For streaming requests, deserializes the response headers with access to the config bag.
          86  +
    ///
          87  +
    /// This is the method called by the orchestrator. The default implementation
          88  +
    /// delegates to [`deserialize_streaming`](Self::deserialize_streaming), ignoring the config.
          89  +
    fn deserialize_streaming_with_config(
          90  +
        &self,
          91  +
        response: &mut HttpResponse,
          92  +
        _cfg: &ConfigBag,
          93  +
    ) -> Option<Result<Output, OrchestratorError<Error>>> {
          94  +
        #[allow(deprecated)]
          95  +
        self.deserialize_streaming(response)
          96  +
    }
          97  +
   70     98   
    /// Deserialize the entire response including its body into an output or error.
          99  +
    ///
         100  +
    /// Override this or [`deserialize_nonstreaming_with_config`](Self::deserialize_nonstreaming_with_config),
         101  +
    /// but not both.
         102  +
    #[deprecated(
         103  +
        note = "Implement `deserialize_nonstreaming_with_config` instead. This method will be removed in a future release."
         104  +
    )]
   71    105   
    fn deserialize_nonstreaming(
   72    106   
        &self,
   73    107   
        response: &HttpResponse,
   74         -
    ) -> Result<Output, OrchestratorError<Error>>;
         108  +
    ) -> Result<Output, OrchestratorError<Error>> {
         109  +
        self.deserialize_nonstreaming_with_config(response, &ConfigBag::base())
         110  +
    }
         111  +
         112  +
    /// Deserialize the entire response including its body into an output or error,
         113  +
    /// with access to the config bag.
         114  +
    ///
         115  +
    /// This is the method called by the orchestrator. The default implementation
         116  +
    /// delegates to [`deserialize_nonstreaming`](Self::deserialize_nonstreaming),
         117  +
    /// ignoring the config bag.
         118  +
    fn deserialize_nonstreaming_with_config(
         119  +
        &self,
         120  +
        response: &HttpResponse,
         121  +
        _cfg: &ConfigBag,
         122  +
    ) -> Result<Output, OrchestratorError<Error>> {
         123  +
        #[allow(deprecated)]
         124  +
        self.deserialize_nonstreaming(response)
         125  +
    }
   75    126   
}
   76    127   
   77    128   
/// Shared response deserializer.
   78    129   
///
   79    130   
/// This is a simple shared ownership wrapper type for the [`DeserializeResponse`] trait.
   80    131   
#[derive(Debug)]
   81    132   
pub struct SharedResponseDeserializer(Arc<dyn DeserializeResponse>);
   82    133   
   83    134   
impl SharedResponseDeserializer {
   84    135   
    /// Creates a new [`SharedResponseDeserializer`].
   85    136   
    pub fn new(serializer: impl DeserializeResponse + 'static) -> Self {
   86    137   
        Self(Arc::new(serializer))
   87    138   
    }
   88    139   
}
   89    140   
         141  +
#[allow(deprecated)]
   90    142   
impl DeserializeResponse for SharedResponseDeserializer {
   91    143   
    fn deserialize_nonstreaming(
   92    144   
        &self,
   93    145   
        response: &HttpResponse,
   94    146   
    ) -> Result<Output, OrchestratorError<Error>> {
   95    147   
        self.0.deserialize_nonstreaming(response)
   96    148   
    }
   97    149   
         150  +
    fn deserialize_nonstreaming_with_config(
         151  +
        &self,
         152  +
        response: &HttpResponse,
         153  +
        cfg: &ConfigBag,
         154  +
    ) -> Result<Output, OrchestratorError<Error>> {
         155  +
        self.0.deserialize_nonstreaming_with_config(response, cfg)
         156  +
    }
         157  +
   98    158   
    fn deserialize_streaming(
   99    159   
        &self,
  100    160   
        response: &mut HttpResponse,
  101    161   
    ) -> Option<Result<Output, OrchestratorError<Error>>> {
  102    162   
        self.0.deserialize_streaming(response)
  103    163   
    }
         164  +
         165  +
    fn deserialize_streaming_with_config(
         166  +
        &self,
         167  +
        response: &mut HttpResponse,
         168  +
        cfg: &ConfigBag,
         169  +
    ) -> Option<Result<Output, OrchestratorError<Error>>> {
         170  +
        self.0.deserialize_streaming_with_config(response, cfg)
         171  +
    }
  104    172   
}
  105    173   
  106    174   
impl Storable for SharedResponseDeserializer {
  107    175   
    type Storer = StoreReplace<Self>;
  108    176   
}
  109    177   
  110    178   
impl_shared_conversions!(convert SharedResponseDeserializer from DeserializeResponse using SharedResponseDeserializer::new);

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime-api/src/http/error.rs

@@ -1,1 +155,164 @@
   19     19   
pub struct HttpError {
   20     20   
    kind: Kind,
   21     21   
    source: Option<BoxError>,
   22     22   
}
   23     23   
   24     24   
#[derive(Debug)]
   25     25   
enum Kind {
   26     26   
    InvalidExtensions,
   27     27   
    InvalidHeaderName,
   28     28   
    InvalidHeaderValue,
          29  +
    InvalidMethod,
   29     30   
    InvalidStatusCode,
   30     31   
    InvalidUri,
   31     32   
    InvalidUriParts,
   32     33   
    MissingAuthority,
   33     34   
    MissingScheme,
   34     35   
    NonUtf8Header(NonUtf8Header),
   35     36   
}
   36     37   
   37     38   
#[derive(Debug)]
   38     39   
pub(super) struct NonUtf8Header {
   39     40   
    error: Utf8Error,
   40     41   
    value: Vec<u8>,
   41     42   
    name: Option<String>,
   42     43   
}
   43     44   
   44     45   
impl NonUtf8Header {
   45     46   
    #[cfg(any(feature = "http-1x", feature = "http-02x"))]
   46     47   
    pub(super) fn new(name: String, value: Vec<u8>, error: Utf8Error) -> Self {
   47     48   
        Self {
   48     49   
            error,
   49     50   
            value,
   50     51   
            name: Some(name),
   51     52   
        }
   52     53   
    }
   53     54   
   54     55   
    pub(super) fn new_missing_name(value: Vec<u8>, error: Utf8Error) -> Self {
   55     56   
        Self {
   56     57   
            error,
   57     58   
            value,
   58     59   
            name: None,
   59     60   
        }
   60     61   
    }
   61     62   
}
   62     63   
   63     64   
impl HttpError {
   64     65   
    pub(super) fn invalid_extensions() -> Self {
   65     66   
        Self {
   66     67   
            kind: Kind::InvalidExtensions,
   67     68   
            source: None,
   68     69   
        }
   69     70   
    }
   70     71   
   71     72   
    pub(super) fn invalid_header_name(err: InvalidHeaderName) -> Self {
   72     73   
        Self {
   73     74   
            kind: Kind::InvalidHeaderName,
   74     75   
            source: Some(Box::new(err)),
   75     76   
        }
   76     77   
    }
   77     78   
          79  +
    pub(super) fn invalid_method(err: http_1x::method::InvalidMethod) -> Self {
          80  +
        Self {
          81  +
            kind: Kind::InvalidMethod,
          82  +
            source: Some(Box::new(err)),
          83  +
        }
          84  +
    }
          85  +
   78     86   
    pub(super) fn invalid_header_value(err: InvalidHeaderValue) -> Self {
   79     87   
        Self {
   80     88   
            kind: Kind::InvalidHeaderValue,
   81     89   
            source: Some(Box::new(err)),
   82     90   
        }
   83     91   
    }
   84     92   
   85     93   
    pub(super) fn invalid_status_code() -> Self {
   86     94   
        Self {
   87     95   
            kind: Kind::InvalidStatusCode,
   88     96   
            source: None,
   89     97   
        }
   90     98   
    }
   91     99   
   92    100   
    pub(super) fn invalid_uri(err: InvalidUri) -> Self {
   93    101   
        Self {
   94    102   
            kind: Kind::InvalidUri,
   95    103   
            source: Some(Box::new(err)),
   96    104   
        }
   97    105   
    }
   98    106   
   99    107   
    pub(super) fn invalid_uri_parts(err: http_02x::Error) -> Self {
  100    108   
        Self {
  101    109   
            kind: Kind::InvalidUriParts,
  102    110   
            source: Some(Box::new(err)),
  103    111   
        }
  104    112   
    }
  105    113   
  106    114   
    pub(super) fn missing_authority() -> Self {
  107    115   
        Self {
  108    116   
            kind: Kind::MissingAuthority,
  109    117   
            source: None,
  110    118   
        }
  111    119   
    }
  112    120   
  113    121   
    pub(super) fn missing_scheme() -> Self {
  114    122   
        Self {
  115    123   
            kind: Kind::MissingScheme,
  116    124   
            source: None,
  117    125   
        }
  118    126   
    }
  119    127   
  120    128   
    pub(super) fn non_utf8_header(non_utf8_header: NonUtf8Header) -> Self {
  121    129   
        Self {
  122    130   
            kind: Kind::NonUtf8Header(non_utf8_header),
  123    131   
            source: None,
  124    132   
        }
  125    133   
    }
  126    134   
}
  127    135   
  128    136   
impl Display for HttpError {
  129    137   
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
  130    138   
        use Kind::*;
  131    139   
        match &self.kind {
  132    140   
            InvalidExtensions => write!(f, "Extensions were provided during initialization. This prevents the request format from being converted."),
  133    141   
            InvalidHeaderName => write!(f, "invalid header name"),
  134    142   
            InvalidHeaderValue => write!(f, "invalid header value"),
         143  +
            InvalidMethod => write!(f, "invalid HTTP method"),
  135    144   
            InvalidStatusCode => write!(f, "invalid HTTP status code"),
  136    145   
            InvalidUri => write!(f, "endpoint is not a valid URI"),
  137    146   
            InvalidUriParts => write!(f, "endpoint parts are not valid"),
  138    147   
            MissingAuthority => write!(f, "endpoint must contain authority"),
  139    148   
            MissingScheme => write!(f, "endpoint must contain scheme"),
  140    149   
            NonUtf8Header(hv) => {
  141    150   
                // In some cases, we won't know the key so we default to "<unknown>".
  142    151   
                let key = hv.name.as_deref().unwrap_or("<unknown>");
  143    152   
                let value = String::from_utf8_lossy(&hv.value);
  144    153   
                let index = hv.error.valid_up_to();

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime-api/src/http/request.rs

@@ -1,1 +60,60 @@
   20     20   
    pub headers: Headers,
   21     21   
    /// Request body.
   22     22   
    pub body: B,
   23     23   
}
   24     24   
   25     25   
#[derive(Debug)]
   26     26   
/// An HTTP Request Type
   27     27   
pub struct Request<B = SdkBody> {
   28     28   
    body: B,
   29     29   
    uri: Uri,
   30         -
    method: http_02x::Method,
          30  +
    method: http_1x::Method,
   31     31   
    extensions: Extensions,
   32     32   
    headers: Headers,
   33     33   
}
   34     34   
   35     35   
/// A Request URI
   36     36   
#[derive(Debug, Clone)]
   37     37   
pub struct Uri {
   38     38   
    as_string: String,
   39     39   
    parsed: ParsedUri,
   40     40   
}
@@ -184,184 +328,338 @@
  204    204   
  205    205   
impl<B> Request<B> {
  206    206   
    /// Converts this request into an http 0.x request.
  207    207   
    ///
  208    208   
    /// Depending on the internal storage type, this operation may be free or it may have an internal
  209    209   
    /// cost.
  210    210   
    #[cfg(feature = "http-02x")]
  211    211   
    pub fn try_into_http02x(self) -> Result<http_02x::Request<B>, HttpError> {
  212    212   
        let mut req = http_02x::Request::builder()
  213    213   
            .uri(self.uri.into_h0())
  214         -
            .method(self.method)
         214  +
            .method(
         215  +
                http_02x::Method::from_bytes(self.method.as_str().as_bytes())
         216  +
                    .expect("valid method"),
         217  +
            )
  215    218   
            .body(self.body)
  216    219   
            .expect("known valid");
  217    220   
        *req.headers_mut() = self.headers.http0_headermap();
  218    221   
        *req.extensions_mut() = self.extensions.try_into()?;
  219    222   
        Ok(req)
  220    223   
    }
  221    224   
  222    225   
    /// Converts this request into an http 1.x request.
  223    226   
    ///
  224    227   
    /// Depending on the internal storage type, this operation may be free or it may have an internal
  225    228   
    /// cost.
  226    229   
    #[cfg(feature = "http-1x")]
  227    230   
    pub fn try_into_http1x(self) -> Result<http_1x::Request<B>, HttpError> {
  228    231   
        let mut req = http_1x::Request::builder()
  229    232   
            .uri(self.uri.as_string)
  230         -
            .method(self.method.as_str())
         233  +
            .method(self.method)
  231    234   
            .body(self.body)
  232    235   
            .expect("known valid");
  233    236   
        *req.headers_mut() = self.headers.http1_headermap();
  234    237   
        *req.extensions_mut() = self.extensions.try_into()?;
  235    238   
        Ok(req)
  236    239   
    }
  237    240   
  238    241   
    /// Update the body of this request to be a new body.
  239    242   
    pub fn map<U>(self, f: impl Fn(B) -> U) -> Request<U> {
  240    243   
        Request {
  241    244   
            body: f(self.body),
  242    245   
            uri: self.uri,
  243    246   
            method: self.method,
  244    247   
            extensions: self.extensions,
  245    248   
            headers: self.headers,
  246    249   
        }
  247    250   
    }
  248    251   
  249    252   
    /// Returns a GET request with no URI
  250    253   
    pub fn new(body: B) -> Self {
  251    254   
        Self {
  252    255   
            body,
  253    256   
            uri: Uri::from_http0x_uri(http_02x::Uri::from_static("/")),
  254         -
            method: http_02x::Method::GET,
         257  +
            method: http_1x::Method::GET,
  255    258   
            extensions: Default::default(),
  256    259   
            headers: Default::default(),
  257    260   
        }
  258    261   
    }
  259    262   
  260    263   
    /// Convert this request into its parts.
  261    264   
    pub fn into_parts(self) -> RequestParts<B> {
  262    265   
        RequestParts {
  263    266   
            uri: self.uri,
  264    267   
            headers: self.headers,
  265    268   
            body: self.body,
  266    269   
        }
  267    270   
    }
  268    271   
  269    272   
    /// Returns a reference to the header map
  270    273   
    pub fn headers(&self) -> &Headers {
  271    274   
        &self.headers
  272    275   
    }
  273    276   
  274    277   
    /// Returns a mutable reference to the header map
  275    278   
    pub fn headers_mut(&mut self) -> &mut Headers {
  276    279   
        &mut self.headers
  277    280   
    }
  278    281   
  279    282   
    /// Returns the body associated with the request
  280    283   
    pub fn body(&self) -> &B {
  281    284   
        &self.body
  282    285   
    }
  283    286   
  284    287   
    /// Returns a mutable reference to the body
  285    288   
    pub fn body_mut(&mut self) -> &mut B {
  286    289   
        &mut self.body
  287    290   
    }
  288    291   
  289    292   
    /// Converts this request into the request body.
  290    293   
    pub fn into_body(self) -> B {
  291    294   
        self.body
  292    295   
    }
  293    296   
  294    297   
    /// Returns the method associated with this request
  295    298   
    pub fn method(&self) -> &str {
  296    299   
        self.method.as_str()
  297    300   
    }
  298    301   
         302  +
    /// Sets the HTTP method for this request
         303  +
    pub fn set_method(&mut self, method: &str) -> Result<(), HttpError> {
         304  +
        self.method =
         305  +
            http_1x::Method::from_bytes(method.as_bytes()).map_err(HttpError::invalid_method)?;
         306  +
        Ok(())
         307  +
    }
         308  +
  299    309   
    /// Returns the URI associated with this request
  300    310   
    pub fn uri(&self) -> &str {
  301    311   
        &self.uri.as_string
  302    312   
    }
  303    313   
  304    314   
    /// Returns a mutable reference the the URI of this http::Request
  305    315   
    pub fn uri_mut(&mut self) -> &mut Uri {
  306    316   
        &mut self.uri
  307    317   
    }
  308    318   
@@ -340,350 +417,428 @@
  360    370   
#[cfg(feature = "http-02x")]
  361    371   
impl<B> TryFrom<http_02x::Request<B>> for Request<B> {
  362    372   
    type Error = HttpError;
  363    373   
  364    374   
    fn try_from(value: http_02x::Request<B>) -> Result<Self, Self::Error> {
  365    375   
        let (parts, body) = value.into_parts();
  366    376   
        let headers = Headers::try_from(parts.headers)?;
  367    377   
        Ok(Self {
  368    378   
            body,
  369    379   
            uri: parts.uri.into(),
  370         -
            method: parts.method,
         380  +
            method: http_1x::Method::from_bytes(parts.method.as_str().as_bytes())
         381  +
                .expect("valid method"),
  371    382   
            extensions: parts.extensions.into(),
  372    383   
            headers,
  373    384   
        })
  374    385   
    }
  375    386   
}
  376    387   
  377    388   
#[cfg(feature = "http-1x")]
  378    389   
impl<B> TryFrom<http_1x::Request<B>> for Request<B> {
  379    390   
    type Error = HttpError;
  380    391   
  381    392   
    fn try_from(value: http_1x::Request<B>) -> Result<Self, Self::Error> {
  382    393   
        let (parts, body) = value.into_parts();
  383    394   
        let headers = Headers::try_from(parts.headers)?;
  384    395   
        Ok(Self {
  385    396   
            body,
  386    397   
            uri: Uri::from_http1x_uri(parts.uri),
  387         -
            method: http_02x::Method::from_bytes(parts.method.as_str().as_bytes()).expect("valid"),
         398  +
            method: parts.method,
  388    399   
            extensions: parts.extensions.into(),
  389    400   
            headers,
  390    401   
        })
  391    402   
    }
  392    403   
}
  393    404   
  394    405   
#[cfg(all(test, feature = "http-02x", feature = "http-1x"))]
  395    406   
mod test {
  396    407   
    use aws_smithy_types::body::SdkBody;
  397    408   
    use http_02x::header::{AUTHORIZATION, CONTENT_LENGTH};

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/Cargo.toml

@@ -1,1 +125,129 @@
    1      1   
# Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
    2      2   
[package]
    3      3   
name = "aws-smithy-runtime"
    4         -
version = "1.10.3"
           4  +
version = "1.10.4"
    5      5   
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>", "Zelda Hessler <zhessler@amazon.com>"]
    6      6   
description = "The new smithy runtime crate"
    7      7   
edition = "2021"
    8      8   
license = "Apache-2.0"
    9      9   
repository = "https://github.com/smithy-lang/smithy-rs"
   10     10   
rust-version = "1.91.1"
   11     11   
[package.metadata.docs.rs]
   12     12   
all-features = true
   13     13   
targets = ["x86_64-unknown-linux-gnu"]
   14     14   
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
   15     15   
rustdoc-args = ["--cfg", "docsrs"]
   16     16   
   17     17   
[package.metadata.smithy-rs-release-tooling]
   18     18   
stable = true
   19     19   
[package.metadata.cargo-udeps.ignore]
   20     20   
normal = ["aws-smithy-http"]
   21     21   
   22     22   
[features]
   23     23   
client = ["aws-smithy-runtime-api/client", "aws-smithy-types/http-body-1-x"]
   24     24   
http-auth = ["aws-smithy-runtime-api/http-auth"]
   25     25   
connector-hyper-0-14-x = ["dep:aws-smithy-http-client", "aws-smithy-http-client?/hyper-014"]
   26     26   
tls-rustls = ["dep:aws-smithy-http-client", "aws-smithy-http-client?/legacy-rustls-ring", "connector-hyper-0-14-x"]
   27     27   
default-https-client = ["dep:aws-smithy-http-client", "aws-smithy-http-client?/rustls-aws-lc"]
   28     28   
rt-tokio = ["tokio/rt"]
   29     29   
test-util = ["aws-smithy-runtime-api/test-util", "dep:tracing-subscriber", "aws-smithy-http-client/test-util", "legacy-test-util"]
   30     30   
legacy-test-util = ["aws-smithy-runtime-api/test-util", "dep:tracing-subscriber", "aws-smithy-http-client/test-util", "connector-hyper-0-14-x", "aws-smithy-http-client/legacy-test-util"]
   31     31   
wire-mock = ["legacy-test-util", "aws-smithy-http-client/wire-mock"]
   32     32   
   33     33   
[dependencies]
   34     34   
bytes = "1.11.1"
   35     35   
fastrand = "2.3.0"
   36     36   
http-body-util = "0.1.3"
   37     37   
pin-project-lite = "0.2.14"
   38     38   
pin-utils = "0.1.0"
   39     39   
tracing = "0.1.44"
   40     40   
   41     41   
[dependencies.aws-smithy-async]
   42     42   
path = "../aws-smithy-async"
   43     43   
version = "1.2.14"
   44     44   
   45     45   
[dependencies.aws-smithy-http]
   46     46   
path = "../aws-smithy-http"
   47     47   
version = "0.63.6"
   48     48   
   49     49   
[dependencies.aws-smithy-observability]
   50     50   
path = "../aws-smithy-observability"
   51     51   
version = "0.2.6"
   52     52   
   53     53   
[dependencies.aws-smithy-runtime-api]
   54     54   
path = "../aws-smithy-runtime-api"
   55         -
version = "1.11.6"
          55  +
version = "1.11.7"
          56  +
          57  +
[dependencies.aws-smithy-schema]
          58  +
path = "../aws-smithy-schema"
          59  +
version = "1.0.0"
   56     60   
   57     61   
[dependencies.aws-smithy-types]
   58     62   
path = "../aws-smithy-types"
   59     63   
features = ["http-body-0-4-x"]
   60     64   
version = "1.4.7"
   61     65   
   62     66   
[dependencies.aws-smithy-http-client]
   63     67   
path = "../aws-smithy-http-client"
   64     68   
optional = true
   65     69   
version = "1.1.12"
   66     70   
   67     71   
[dependencies.http-02x]
   68     72   
package = "http"
   69     73   
version = "0.2.12"
   70     74   
   71     75   
[dependencies.http-1x]
   72     76   
package = "http"
   73     77   
version = "1.3.1"
   74     78   
   75     79   
[dependencies.http-body-04x]
   76     80   
package = "http-body"
   77     81   
version = "0.4.6"
   78     82   
   79     83   
[dependencies.http-body-1x]
   80     84   
package = "http-body"
   81     85   
version = "1.0.1"
   82     86   
   83     87   
[dependencies.tokio]
   84     88   
version = "1.49.0"
   85     89   
features = []
   86     90   
   87     91   
[dependencies.tracing-subscriber]
   88     92   
version = "0.3.22"
   89     93   
optional = true
   90     94   
features = ["env-filter", "fmt", "json"]
   91     95   
   92     96   
[dev-dependencies]
   93     97   
approx = "0.5.1"
   94     98   
fastrand = "2.3.0"
   95     99   
futures-util = "0.3.29"
   96    100   
pretty_assertions = "1.4.0"
   97    101   
tracing-test = "0.2.1"
   98    102   
   99    103   
[dev-dependencies.aws-smithy-async]
  100    104   
path = "../aws-smithy-async"
  101    105   
features = ["rt-tokio", "test-util"]
  102    106   
version = "1.2.14"
  103    107   
  104    108   
[dev-dependencies.aws-smithy-runtime-api]
  105    109   
path = "../aws-smithy-runtime-api"
  106    110   
features = ["test-util"]
  107         -
version = "1.11.6"
         111  +
version = "1.11.7"
  108    112   
  109    113   
[dev-dependencies.aws-smithy-types]
  110    114   
path = "../aws-smithy-types"
  111    115   
features = ["test-util"]
  112    116   
version = "1.4.7"
  113    117   
  114    118   
[dev-dependencies.tokio]
  115    119   
version = "1.49.0"
  116    120   
features = ["macros", "rt", "rt-multi-thread", "test-util", "full"]
  117    121   

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/src/client/orchestrator.rs

@@ -409,409 +480,480 @@
  429    429   
    });
  430    430   
  431    431   
    ctx.enter_deserialization_phase();
  432    432   
    let output_or_error = async {
  433    433   
        let response = ctx.response_mut().expect("set during transmit");
  434    434   
        let response_deserializer = cfg
  435    435   
            .load::<SharedResponseDeserializer>()
  436    436   
            .expect("a request deserializer must be in the config bag");
  437    437   
        let maybe_deserialized = {
  438    438   
            let _span = debug_span!("deserialize_streaming").entered();
  439         -
            response_deserializer.deserialize_streaming(response)
         439  +
            response_deserializer.deserialize_streaming_with_config(response, cfg)
  440    440   
        };
  441    441   
        match maybe_deserialized {
  442    442   
            Some(output_or_error) => output_or_error,
  443    443   
            None => read_body(response)
  444    444   
                .instrument(debug_span!("read_body"))
  445    445   
                .await
  446    446   
                .map_err(OrchestratorError::response)
  447    447   
                .and_then(|_| {
  448    448   
                    let _span = debug_span!("deserialize_nonstreaming").entered();
  449    449   
                    log_response_body(response, cfg);
  450         -
                    response_deserializer.deserialize_nonstreaming(response)
         450  +
                    response_deserializer.deserialize_nonstreaming_with_config(response, cfg)
  451    451   
                }),
  452    452   
        }
  453    453   
    }
  454    454   
    .instrument(debug_span!("deserialization"))
  455    455   
    .await;
  456    456   
    trace!(output_or_error = ?output_or_error);
  457    457   
    ctx.set_output_or_error(output_or_error);
  458    458   
  459    459   
    ctx.enter_after_deserialization_phase();
  460    460   
    run_interceptors!(halt_on_err: read_after_deserialization(ctx, runtime_components, cfg));

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/src/client/orchestrator/endpoints.rs

@@ -77,77 +137,146 @@
   97     97   
   98     98   
pub(super) fn apply_endpoint(
   99     99   
    endpoint: &Endpoint,
  100    100   
    ctx: &mut InterceptorContext,
  101    101   
    cfg: &ConfigBag,
  102    102   
) -> Result<(), BoxError> {
  103    103   
    let endpoint_prefix = cfg.load::<EndpointPrefix>();
  104    104   
    tracing::debug!(endpoint_prefix = ?endpoint_prefix, "will apply endpoint {:?}", endpoint);
  105    105   
    let request = ctx.request_mut().expect("set during serialization");
  106    106   
  107         -
    apply_endpoint_to_request(request, endpoint, endpoint_prefix)
         107  +
    // If a schema-driven protocol is in use, delegate endpoint application to it.
         108  +
    if let Some(protocol) = cfg.load::<aws_smithy_schema::protocol::SharedClientProtocol>() {
         109  +
        protocol
         110  +
            .update_endpoint(request, endpoint, cfg)
         111  +
            .map_err(BoxError::from)?;
         112  +
    } else {
         113  +
        apply_endpoint_to_request(request, endpoint, endpoint_prefix)?;
         114  +
    }
         115  +
         116  +
    Ok(())
  108    117   
}
  109    118   
  110    119   
fn apply_endpoint_to_request(
  111    120   
    request: &mut HttpRequest,
  112    121   
    endpoint: &Endpoint,
  113    122   
    endpoint_prefix: Option<&EndpointPrefix>,
  114    123   
) -> Result<(), BoxError> {
  115    124   
    let endpoint_url = match endpoint_prefix {
  116    125   
        None => Cow::Borrowed(endpoint.url()),
  117    126   
        Some(prefix) => {