AWS SDK

AWS SDK

rev. 1b1387ee4f8d9c5ea59164e42414701487f510f1 (ignoring whitespace)

Files changed:

tmp-codegen-diff/aws-sdk/Cargo.lock

@@ -1394,1394 +1454,1454 @@
 1414   1414   
 "serial_test",
 1415   1415   
 "socket2 0.6.5",
 1416   1416   
 "tokio",
 1417   1417   
 "tokio-rustls 0.26.5",
 1418   1418   
 "tower",
 1419   1419   
 "tracing",
 1420   1420   
]
 1421   1421   
 1422   1422   
[[package]]
 1423   1423   
name = "aws-smithy-json"
 1424         -
version = "0.63.0"
        1424  +
version = "0.63.1"
 1425   1425   
dependencies = [
 1426   1426   
 "aws-smithy-runtime-api",
 1427   1427   
 "aws-smithy-schema",
 1428   1428   
 "aws-smithy-types",
 1429   1429   
 "proptest",
 1430   1430   
 "serde_json",
 1431   1431   
]
 1432   1432   
 1433   1433   
[[package]]
 1434   1434   
name = "aws-smithy-legacy-http"

tmp-codegen-diff/aws-sdk/sdk/aws-config/Cargo.toml

@@ -37,37 +97,97 @@
   57     57   
[dependencies.aws-smithy-async]
   58     58   
path = "../aws-smithy-async"
   59     59   
version = "1.3.0"
   60     60   
   61     61   
[dependencies.aws-smithy-http]
   62     62   
path = "../aws-smithy-http"
   63     63   
version = "0.64.0"
   64     64   
   65     65   
[dependencies.aws-smithy-json]
   66     66   
path = "../aws-smithy-json"
   67         -
version = "0.63.0"
          67  +
version = "0.63.1"
   68     68   
   69     69   
[dependencies.aws-smithy-runtime]
   70     70   
path = "../aws-smithy-runtime"
   71     71   
features = ["client"]
   72     72   
version = "1.14.0"
   73     73   
   74     74   
[dependencies.aws-smithy-runtime-api]
   75     75   
path = "../aws-smithy-runtime-api"
   76     76   
features = ["client"]
   77     77   
version = "1.16.0"

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

@@ -1,1 +31,31 @@
    1      1   
# Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT.
    2      2   
[package]
    3      3   
name = "aws-smithy-json"
    4         -
version = "0.63.0"
           4  +
version = "0.63.1"
    5      5   
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>", "John DiSanti <jdisanti@amazon.com>"]
    6      6   
description = "Token streaming JSON parser 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.94.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-json/fuzz/Cargo.toml

@@ -17,17 +66,66 @@
   37     37   
edition = "2021"
   38     38   
   39     39   
[package.metadata]
   40     40   
cargo-fuzz = true
   41     41   
   42     42   
[dependencies]
   43     43   
libfuzzer-sys = "=0.4.7"
   44     44   
   45     45   
[dependencies.aws-smithy-json]
   46     46   
path = ".."
   47         -
version = "0.63.0"
          47  +
version = "0.63.1"
   48     48   
   49     49   
[dependencies.aws-smithy-schema]
   50     50   
path = "../../aws-smithy-schema"
   51     51   
version = "0.2.0"
   52     52   
   53     53   
[dependencies.aws-smithy-types]
   54     54   
path = "../../aws-smithy-types"
   55     55   
version = "1.6.3"
   56     56   
   57     57   
[dependencies.arbitrary]

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

@@ -102,102 +301,276 @@
  122    122   
            self.depth -= 1;
  123    123   
            return Ok(());
  124    124   
        }
  125    125   
        if self.remaining().first() != Some(&b'{') {
  126    126   
            return Err(SerdeError::TypeMismatch {
  127    127   
                message: "expected object".into(),
  128    128   
            });
  129    129   
        }
  130    130   
        self.advance_by(1);
  131    131   
         132  +
        let mut first = true;
  132    133   
        loop {
  133         -
            self.skip_whitespace();
  134         -
  135         -
            // Check for end of object, error on end of input, otherwise
  136         -
            // fall through to parse the next key/value pair.
  137         -
            match self.remaining().first() {
  138         -
                Some(&b'}') => {
  139         -
                    self.advance_by(1);
         134  +
            // Stop at the end of the object; otherwise the next key/value pair starts here.
         135  +
            if self.next_element(first, b'}', "object")? {
  140    136   
                break;
  141    137   
            }
  142         -
                None => {
  143         -
                    return Err(SerdeError::InvalidInput {
  144         -
                        message: "unexpected end of input in object".into(),
  145         -
                    });
  146         -
                }
  147         -
                Some(&b'"') => {}
  148         -
                Some(_) => {
         138  +
            first = false;
         139  +
            if self.remaining().first() != Some(&b'"') {
  149    140   
                return Err(SerdeError::InvalidInput {
  150    141   
                    message: "expected object key".into(),
  151    142   
                });
  152    143   
            }
  153         -
            }
  154    144   
  155    145   
            // Parse the key directly from bytes
  156    146   
            let key_str = self.parse_key()?;
  157    147   
  158    148   
            // Skip whitespace and expect colon
  159    149   
            self.skip_whitespace();
  160    150   
            if self.remaining().first() != Some(&b':') {
  161    151   
                return Err(SerdeError::InvalidInput {
  162    152   
                    message: "expected colon after key".into(),
  163    153   
                });
  164    154   
            }
  165    155   
            self.advance_by(1);
  166    156   
            self.skip_whitespace();
  167    157   
  168    158   
            // Process the value — skip nulls (they represent absent optional members)
  169    159   
            let rem = self.remaining();
  170    160   
            if rem.starts_with(b"null") && !rem.get(4).is_some_and(|b| b.is_ascii_alphanumeric()) {
  171    161   
                self.advance_by(4);
  172    162   
            } else if let Some(member_schema) = self.resolve_member(schema, &key_str) {
  173    163   
                consumer(member_schema, self)?;
  174    164   
            } else {
  175    165   
                self.skip_value()?;
  176    166   
            }
  177    167   
        }
  178    168   
  179         -
        self.depth -= 1;
         169  +
        self.leave_container()?;
  180    170   
        Ok(())
  181    171   
    }
  182    172   
  183    173   
    fn read_list(
  184    174   
        &mut self,
  185    175   
        _schema: &Schema,
  186    176   
        consumer: &mut dyn FnMut(&mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
  187    177   
    ) -> Result<(), SerdeError> {
  188    178   
        self.depth += 1;
  189    179   
        if self.depth > self.settings.max_depth() {
  190    180   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  191    181   
        }
  192    182   
        self.skip_whitespace();
  193    183   
        if self.remaining().first() != Some(&b'[') {
  194    184   
            return Err(SerdeError::TypeMismatch {
  195    185   
                message: "expected array".into(),
  196    186   
            });
  197    187   
        }
  198    188   
        self.advance_by(1);
  199    189   
         190  +
        let mut first = true;
  200    191   
        loop {
  201         -
            self.skip_whitespace();
  202         -
            match self.remaining().first() {
  203         -
                Some(&b']') => {
  204         -
                    self.advance_by(1);
         192  +
            if self.next_element(first, b']', "array")? {
  205    193   
                break;
  206    194   
            }
  207         -
                None => {
  208         -
                    return Err(SerdeError::InvalidInput {
  209         -
                        message: "unexpected end of input in array".into(),
  210         -
                    });
  211         -
                }
  212         -
                _ => consumer(self)?,
  213         -
            }
         195  +
            first = false;
         196  +
            consumer(self)?;
  214    197   
        }
  215    198   
  216         -
        self.depth -= 1;
         199  +
        self.leave_container()?;
  217    200   
        Ok(())
  218    201   
    }
  219    202   
  220    203   
    fn read_map(
  221    204   
        &mut self,
  222    205   
        _schema: &Schema,
  223    206   
        consumer: &mut dyn FnMut(String, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
  224    207   
    ) -> Result<(), SerdeError> {
  225    208   
        self.depth += 1;
  226    209   
        if self.depth > self.settings.max_depth() {
  227    210   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  228    211   
        }
  229    212   
        self.skip_whitespace();
  230    213   
        if self.remaining().first() != Some(&b'{') {
  231    214   
            return Err(SerdeError::TypeMismatch {
  232    215   
                message: "expected object".into(),
  233    216   
            });
  234    217   
        }
  235    218   
        self.advance_by(1);
  236    219   
         220  +
        let mut first = true;
  237    221   
        loop {
  238         -
            self.skip_whitespace();
  239         -
            match self.remaining().first() {
  240         -
                Some(&b'}') => {
  241         -
                    self.advance_by(1);
         222  +
            if self.next_element(first, b'}', "object")? {
  242    223   
                break;
  243    224   
            }
  244         -
                None => {
  245         -
                    return Err(SerdeError::InvalidInput {
  246         -
                        message: "unexpected end of input in object".into(),
  247         -
                    });
  248         -
                }
  249         -
                Some(&b'"') => {}
  250         -
                Some(_) => {
         225  +
            first = false;
         226  +
            if self.remaining().first() != Some(&b'"') {
  251    227   
                return Err(SerdeError::InvalidInput {
  252    228   
                    message: "expected key".into(),
  253    229   
                });
  254    230   
            }
  255         -
            }
  256    231   
  257    232   
            let key = self.parse_key()?;
  258    233   
  259    234   
            self.skip_whitespace();
  260    235   
            if self.remaining().first() != Some(&b':') {
  261    236   
                return Err(SerdeError::InvalidInput {
  262    237   
                    message: "expected colon".into(),
  263    238   
                });
  264    239   
            }
  265    240   
            self.advance_by(1);
  266    241   
            self.skip_whitespace();
  267    242   
  268    243   
            consumer(key.into_owned(), self)?;
  269    244   
        }
  270    245   
  271         -
        self.depth -= 1;
         246  +
        self.leave_container()?;
  272    247   
        Ok(())
  273    248   
    }
  274    249   
  275    250   
    fn read_boolean(&mut self, _schema: &Schema) -> Result<bool, SerdeError> {
  276    251   
        self.skip_whitespace();
  277    252   
        let rem = self.remaining();
  278    253   
        if rem.starts_with(b"true") {
  279    254   
            self.advance_by(4);
  280    255   
            Ok(true)
  281    256   
        } else if rem.starts_with(b"false") {
@@ -410,385 +624,571 @@
  430    405   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  431    406   
        }
  432    407   
        self.skip_whitespace();
  433    408   
        if self.remaining().first() != Some(&b'[') {
  434    409   
            return Err(SerdeError::TypeMismatch {
  435    410   
                message: "expected array".into(),
  436    411   
            });
  437    412   
        }
  438    413   
        self.advance_by(1);
  439    414   
        let mut out = Vec::new();
         415  +
        let mut first = true;
  440    416   
        loop {
  441         -
            self.skip_whitespace();
  442         -
            match self.remaining().first() {
  443         -
                Some(&b']') => {
  444         -
                    self.advance_by(1);
         417  +
            if self.next_element(first, b']', "array")? {
  445    418   
                break;
  446    419   
            }
  447         -
                None => {
  448         -
                    return Err(SerdeError::InvalidInput {
  449         -
                        message: "unexpected end of input in array".into(),
  450         -
                    })
  451         -
                }
  452         -
                _ => out.push(self.read_string(_schema)?),
  453         -
            }
         420  +
            first = false;
         421  +
            out.push(self.read_string(_schema)?);
  454    422   
        }
  455         -
        self.depth -= 1;
         423  +
        self.leave_container()?;
  456    424   
        Ok(out)
  457    425   
    }
  458    426   
  459    427   
    fn read_blob_list(&mut self, _schema: &Schema) -> Result<Vec<Blob>, SerdeError> {
  460    428   
        self.depth += 1;
  461    429   
        if self.depth > self.settings.max_depth() {
  462    430   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  463    431   
        }
  464    432   
        self.skip_whitespace();
  465    433   
        if self.remaining().first() != Some(&b'[') {
  466    434   
            return Err(SerdeError::TypeMismatch {
  467    435   
                message: "expected array".into(),
  468    436   
            });
  469    437   
        }
  470    438   
        self.advance_by(1);
  471    439   
        let mut out = Vec::new();
         440  +
        let mut first = true;
  472    441   
        loop {
  473         -
            self.skip_whitespace();
  474         -
            match self.remaining().first() {
  475         -
                Some(&b']') => {
  476         -
                    self.advance_by(1);
         442  +
            if self.next_element(first, b']', "array")? {
  477    443   
                break;
  478    444   
            }
  479         -
                None => {
  480         -
                    return Err(SerdeError::InvalidInput {
  481         -
                        message: "unexpected end of input in array".into(),
  482         -
                    })
  483         -
                }
  484         -
                _ => out.push(self.read_blob(_schema)?),
  485         -
            }
         445  +
            first = false;
         446  +
            out.push(self.read_blob(_schema)?);
  486    447   
        }
  487         -
        self.depth -= 1;
         448  +
        self.leave_container()?;
  488    449   
        Ok(out)
  489    450   
    }
  490    451   
  491    452   
    fn read_integer_list(&mut self, _schema: &Schema) -> Result<Vec<i32>, SerdeError> {
  492    453   
        self.depth += 1;
  493    454   
        if self.depth > self.settings.max_depth() {
  494    455   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  495    456   
        }
  496    457   
        self.skip_whitespace();
  497    458   
        if self.remaining().first() != Some(&b'[') {
  498    459   
            return Err(SerdeError::TypeMismatch {
  499    460   
                message: "expected array".into(),
  500    461   
            });
  501    462   
        }
  502    463   
        self.advance_by(1);
  503    464   
        let mut out = Vec::new();
         465  +
        let mut first = true;
  504    466   
        loop {
  505         -
            self.skip_whitespace();
  506         -
            match self.remaining().first() {
  507         -
                Some(&b']') => {
  508         -
                    self.advance_by(1);
         467  +
            if self.next_element(first, b']', "array")? {
  509    468   
                break;
  510    469   
            }
  511         -
                None => {
  512         -
                    return Err(SerdeError::InvalidInput {
  513         -
                        message: "unexpected end of input in array".into(),
  514         -
                    })
  515         -
                }
  516         -
                _ => out.push(self.read_integer(_schema)?),
         470  +
            first = false;
         471  +
            out.push(self.read_integer(_schema)?);
  517    472   
        }
  518         -
        }
  519         -
        self.depth -= 1;
         473  +
        self.leave_container()?;
  520    474   
        Ok(out)
  521    475   
    }
  522    476   
  523    477   
    fn read_long_list(&mut self, _schema: &Schema) -> Result<Vec<i64>, SerdeError> {
  524    478   
        self.depth += 1;
  525    479   
        if self.depth > self.settings.max_depth() {
  526    480   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  527    481   
        }
  528    482   
        self.skip_whitespace();
  529    483   
        if self.remaining().first() != Some(&b'[') {
  530    484   
            return Err(SerdeError::TypeMismatch {
  531    485   
                message: "expected array".into(),
  532    486   
            });
  533    487   
        }
  534    488   
        self.advance_by(1);
  535    489   
        let mut out = Vec::new();
         490  +
        let mut first = true;
  536    491   
        loop {
  537         -
            self.skip_whitespace();
  538         -
            match self.remaining().first() {
  539         -
                Some(&b']') => {
  540         -
                    self.advance_by(1);
         492  +
            if self.next_element(first, b']', "array")? {
  541    493   
                break;
  542    494   
            }
  543         -
                None => {
  544         -
                    return Err(SerdeError::InvalidInput {
  545         -
                        message: "unexpected end of input in array".into(),
  546         -
                    })
  547         -
                }
  548         -
                _ => out.push(self.read_long(_schema)?),
  549         -
            }
         495  +
            first = false;
         496  +
            out.push(self.read_long(_schema)?);
  550    497   
        }
  551         -
        self.depth -= 1;
         498  +
        self.leave_container()?;
  552    499   
        Ok(out)
  553    500   
    }
  554    501   
  555    502   
    fn read_string_string_map(
  556    503   
        &mut self,
  557    504   
        _schema: &Schema,
  558    505   
    ) -> Result<std::collections::HashMap<String, String>, SerdeError> {
  559    506   
        self.depth += 1;
  560    507   
        if self.depth > self.settings.max_depth() {
  561    508   
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  562    509   
        }
  563    510   
        self.skip_whitespace();
  564    511   
        if self.remaining().first() != Some(&b'{') {
  565    512   
            return Err(SerdeError::TypeMismatch {
  566    513   
                message: "expected object".into(),
  567    514   
            });
  568    515   
        }
  569    516   
        self.advance_by(1);
  570    517   
        let mut out = std::collections::HashMap::new();
         518  +
        let mut first = true;
  571    519   
        loop {
  572         -
            self.skip_whitespace();
  573         -
            if self.remaining().first() == Some(&b'}') {
  574         -
                self.advance_by(1);
         520  +
            if self.next_element(first, b'}', "object")? {
  575    521   
                break;
  576    522   
            }
         523  +
            first = false;
  577    524   
            if self.remaining().first() != Some(&b'"') {
  578    525   
                return Err(SerdeError::InvalidInput {
  579    526   
                    message: "expected key".into(),
  580    527   
                });
  581    528   
            }
  582    529   
            let key = self.parse_key()?;
  583    530   
            self.skip_whitespace();
  584    531   
            if self.remaining().first() != Some(&b':') {
  585    532   
                return Err(SerdeError::InvalidInput {
  586    533   
                    message: "expected colon".into(),
  587    534   
                });
  588    535   
            }
  589    536   
            self.advance_by(1);
  590    537   
            self.skip_whitespace();
  591    538   
            let val = self.read_string(_schema)?;
  592    539   
            out.insert(key.into_owned(), val);
  593    540   
        }
  594         -
        self.depth -= 1;
         541  +
        self.leave_container()?;
  595    542   
        Ok(out)
  596    543   
    }
  597    544   
  598    545   
    fn read_timestamp(&mut self, schema: &Schema) -> Result<DateTime, SerdeError> {
  599    546   
        self.skip_whitespace();
  600    547   
        let rem = self.remaining();
  601    548   
        match rem.first() {
  602    549   
            Some(b'"') => {
  603    550   
                let s = self.read_string(schema)?;
  604    551   
                // Determine parse format from @timestampFormat trait or default
@@ -655,602 +807,747 @@
  675    622   
                    Ok(Document::Null)
  676    623   
                } else {
  677    624   
                    Err(SerdeError::InvalidInput {
  678    625   
                        message: "unexpected token in document".into(),
  679    626   
                    })
  680    627   
                }
  681    628   
            }
  682    629   
            Some(b'{') => {
  683    630   
                self.advance_by(1);
  684    631   
                let mut map = std::collections::HashMap::new();
         632  +
                let mut first = true;
  685    633   
                loop {
  686         -
                    self.skip_whitespace();
  687         -
                    if self.remaining().first() == Some(&b'}') {
  688         -
                        self.advance_by(1);
         634  +
                    if self.next_element(first, b'}', "document object")? {
  689    635   
                        break;
  690    636   
                    }
         637  +
                    first = false;
  691    638   
                    if self.remaining().first() != Some(&b'"') {
  692    639   
                        return Err(SerdeError::InvalidInput {
  693    640   
                            message: "expected object key in document".into(),
  694    641   
                        });
  695    642   
                    }
  696    643   
                    let key = self.parse_key()?.into_owned();
  697    644   
                    self.skip_whitespace();
  698    645   
                    if self.remaining().first() != Some(&b':') {
  699    646   
                        return Err(SerdeError::InvalidInput {
  700    647   
                            message: "expected colon in document object".into(),
  701    648   
                        });
  702    649   
                    }
  703    650   
                    self.advance_by(1);
  704    651   
                    let value = self.read_document(_schema)?;
  705    652   
                    map.insert(key, value);
  706    653   
                }
  707    654   
                Ok(Document::Object(map))
  708    655   
            }
  709    656   
            Some(b'[') => {
  710    657   
                self.advance_by(1);
  711    658   
                let mut arr = Vec::new();
         659  +
                let mut first = true;
  712    660   
                loop {
  713         -
                    self.skip_whitespace();
  714         -
                    match self.remaining().first() {
  715         -
                        Some(&b']') => {
  716         -
                            self.advance_by(1);
         661  +
                    if self.next_element(first, b']', "document array")? {
  717    662   
                        break;
  718    663   
                    }
  719         -
                        None => {
  720         -
                            return Err(SerdeError::InvalidInput {
  721         -
                                message: "unexpected end of input in document array".into(),
  722         -
                            })
  723         -
                        }
  724         -
                        _ => arr.push(self.read_document(_schema)?),
  725         -
                    }
         664  +
                    first = false;
         665  +
                    arr.push(self.read_document(_schema)?);
  726    666   
                }
  727    667   
                Ok(Document::Array(arr))
  728    668   
            }
  729    669   
            Some(c) if *c == b'-' || c.is_ascii_digit() => {
  730    670   
                // Parse number — determine if integer or float
  731    671   
                let rem = self.remaining();
  732    672   
                let mut len = 0;
  733    673   
                let mut is_float = false;
  734    674   
                let mut is_negative = false;
  735    675   
                for (i, &b) in rem.iter().enumerate() {
  736    676   
                    if b == b'-' && i == 0 {
  737    677   
                        is_negative = true;
  738    678   
                        len += 1;
  739    679   
                    } else if b.is_ascii_digit() || b == b'+' {
  740    680   
                        len += 1;
  741    681   
                    } else if b == b'.' || b == b'e' || b == b'E' {
  742    682   
                        is_float = true;
  743    683   
                        len += 1;
  744    684   
                    } else {
  745    685   
                        break;
  746    686   
                    }
  747    687   
                }
  748    688   
                let pos = self.position;
  749    689   
                self.advance_by(len);
  750    690   
                let s = std::str::from_utf8(&self.input[pos..pos + len]).map_err(|e| {
  751    691   
                    SerdeError::InvalidInput {
  752    692   
                        message: e.to_string(),
  753    693   
                    }
  754    694   
                })?;
  755    695   
                if is_float {
  756    696   
                    let f = s.parse::<f64>().map_err(|e| SerdeError::InvalidInput {
  757    697   
                        message: e.to_string(),
  758    698   
                    })?;
  759    699   
                    Ok(Document::Number(aws_smithy_types::Number::Float(f)))
  760    700   
                } else if is_negative {
  761    701   
                    let n = s.parse::<i64>().map_err(|e| SerdeError::InvalidInput {
  762    702   
                        message: e.to_string(),
  763    703   
                    })?;
  764    704   
                    Ok(Document::Number(aws_smithy_types::Number::NegInt(n)))
  765    705   
                } else {
  766    706   
                    let n = s.parse::<u64>().map_err(|e| SerdeError::InvalidInput {
  767    707   
                        message: e.to_string(),
  768    708   
                    })?;
  769    709   
                    Ok(Document::Number(aws_smithy_types::Number::PosInt(n)))
  770    710   
                }
  771    711   
            }
  772    712   
            _ => Err(SerdeError::InvalidInput {
  773    713   
                message: "unexpected token in document".into(),
  774    714   
            }),
  775    715   
        };
  776    716   
        if result.is_ok() {
  777         -
            self.depth -= 1;
         717  +
            self.leave_container()?;
  778    718   
        }
  779    719   
        result
  780    720   
    }
  781    721   
  782    722   
    fn is_null(&self) -> bool {
  783    723   
        let remaining = self.remaining();
  784    724   
        remaining.len() >= 4
  785    725   
            && &remaining[..4] == b"null"
  786    726   
            && !remaining.get(4).is_some_and(|b| b.is_ascii_alphanumeric())
  787    727   
    }
@@ -827,767 +1004,1067 @@
  847    787   
            }
  848    788   
            _ => None,
  849    789   
        }
  850    790   
    }
  851    791   
}
  852    792   
  853    793   
impl<'a> JsonDeserializer<'a> {
  854    794   
    fn skip_whitespace(&mut self) {
  855    795   
        while self.position < self.input.len() {
  856    796   
            match self.input[self.position] {
  857         -
                b' ' | b'\t' | b'\n' | b'\r' | b',' => self.position += 1,
         797  +
                b' ' | b'\t' | b'\n' | b'\r' => self.position += 1,
  858    798   
                _ => break,
  859    799   
            }
  860    800   
        }
  861    801   
    }
  862    802   
  863         -
    fn consume_number(&mut self) {
  864         -
        let mut len = 0;
  865         -
        for &b in self.remaining() {
  866         -
            if b.is_ascii_digit() || b == b'-' || b == b'.' || b == b'e' || b == b'E' || b == b'+' {
  867         -
                len += 1;
  868         -
            } else {
  869         -
                break;
         803  +
    /// Positions the deserializer at the next element of a container whose closing
         804  +
    /// delimiter is `close`, enforcing JSON's separator rules: elements are separated by
         805  +
    /// exactly one comma, and no comma may precede the closing delimiter.
         806  +
    ///
         807  +
    /// Returns `true` when the closing delimiter was reached and consumed, `false` when the
         808  +
    /// next element starts at the current position. `first` is whether no element has been
         809  +
    /// read from this container yet.
         810  +
    fn next_element(&mut self, first: bool, close: u8, what: &str) -> Result<bool, SerdeError> {
         811  +
        self.skip_whitespace();
         812  +
        match self.remaining().first().copied() {
         813  +
            Some(b) if b == close => {
         814  +
                self.advance_by(1);
         815  +
                Ok(true)
         816  +
            }
         817  +
            None => Err(SerdeError::InvalidInput {
         818  +
                message: format!("unexpected end of input in {what}"),
         819  +
            }),
         820  +
            Some(b',') if first => Err(SerdeError::InvalidInput {
         821  +
                message: format!("unexpected `,` before the first element of {what}"),
         822  +
            }),
         823  +
            Some(b',') => {
         824  +
                self.advance_by(1);
         825  +
                self.skip_whitespace();
         826  +
                match self.remaining().first().copied() {
         827  +
                    Some(b) if b == close => Err(SerdeError::InvalidInput {
         828  +
                        message: format!("trailing `,` in {what}"),
         829  +
                    }),
         830  +
                    Some(b',') => Err(SerdeError::InvalidInput {
         831  +
                        message: format!("repeated `,` in {what}"),
         832  +
                    }),
         833  +
                    None => Err(SerdeError::InvalidInput {
         834  +
                        message: format!("unexpected end of input in {what}"),
         835  +
                    }),
         836  +
                    Some(_) => Ok(false),
  870    837   
                }
  871    838   
            }
  872         -
        self.advance_by(len);
         839  +
            Some(_) if first => Ok(false),
         840  +
            Some(_) => Err(SerdeError::InvalidInput {
         841  +
                message: format!("expected `,` between elements of {what}"),
         842  +
            }),
         843  +
        }
  873    844   
    }
  874    845   
  875         -
    fn skip_value(&mut self) -> Result<(), SerdeError> {
  876         -
        self.skip_whitespace();
  877         -
        let mut depth: usize = 0;
  878         -
        loop {
  879         -
            self.skip_whitespace();
  880         -
            match self.remaining().first().copied() {
  881         -
                Some(b'{') | Some(b'[') => {
  882         -
                    self.advance_by(1);
  883         -
                    depth += 1;
         846  +
    fn enter_container(&mut self) -> Result<(), SerdeError> {
         847  +
        self.depth += 1;
         848  +
        if self.depth > self.settings.max_depth() {
         849  +
            return Err(SerdeError::custom("maximum nesting depth exceeded"));
  884    850   
        }
  885         -
                Some(b'}') | Some(b']') => {
  886         -
                    if depth == 0 {
         851  +
        Ok(())
         852  +
    }
         853  +
         854  +
    /// Leaves a container. When it was the outermost value of the input, nothing but
         855  +
    /// whitespace may follow it: a body such as `{"a": 1}abc` is malformed JSON and is
         856  +
    /// rejected here, matching the token-based parser's "found more JSON tokens after
         857  +
    /// completing parsing" check.
         858  +
    fn leave_container(&mut self) -> Result<(), SerdeError> {
         859  +
        self.depth -= 1;
         860  +
        if self.depth == 0 {
         861  +
            self.skip_whitespace();
         862  +
            if !self.remaining().is_empty() {
  887    863   
                return Err(SerdeError::InvalidInput {
  888         -
                            message: "unexpected end token".into(),
         864  +
                    message: "unexpected trailing characters after the JSON value".into(),
  889    865   
                });
  890    866   
            }
  891         -
                    self.advance_by(1);
  892         -
                    depth -= 1;
  893         -
                    if depth == 0 {
  894         -
                        return Ok(());
  895    867   
        }
         868  +
        Ok(())
  896    869   
    }
  897         -
                Some(b'"') => {
  898         -
                    // Skip quoted string (handles escapes)
  899         -
                    let mut i = 1;
         870  +
         871  +
    /// Skips a JSON number, validating it against the RFC 8259 grammar
         872  +
    /// `-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?`. Whatever follows is left for the
         873  +
    /// enclosing container's separator check, so `01` fails there as "expected `,`".
         874  +
    fn skip_number(&mut self) -> Result<(), SerdeError> {
  900    875   
        let rem = self.remaining();
  901         -
                    while i < rem.len() {
  902         -
                        if rem[i] == b'\\' {
  903         -
                            i += 2; // skip escape sequence
  904         -
                        } else if rem[i] == b'"' {
         876  +
        let invalid = || SerdeError::InvalidInput {
         877  +
            message: "invalid number".into(),
         878  +
        };
         879  +
        let mut i = 0;
         880  +
        if rem.get(i) == Some(&b'-') {
  905    881   
            i += 1;
  906         -
                            break;
  907         -
                        } else {
         882  +
        }
         883  +
        match rem.get(i) {
         884  +
            Some(b'0') => i += 1,
         885  +
            Some(b'1'..=b'9') => {
         886  +
                while rem.get(i).is_some_and(|b| b.is_ascii_digit()) {
  908    887   
                    i += 1;
  909    888   
                }
  910    889   
            }
  911         -
                    self.advance_by(i);
  912         -
                    // After a string inside an object, skip optional ':'
  913         -
                    if depth > 0 {
  914         -
                        self.skip_whitespace();
  915         -
                        if self.remaining().first() == Some(&b':') {
  916         -
                            self.advance_by(1);
  917         -
                            continue; // read the value after the colon
         890  +
            _ => return Err(invalid()),
  918    891   
        }
         892  +
        if rem.get(i) == Some(&b'.') {
         893  +
            i += 1;
         894  +
            let start = i;
         895  +
            while rem.get(i).is_some_and(|b| b.is_ascii_digit()) {
         896  +
                i += 1;
  919    897   
            }
  920         -
                    if depth == 0 {
  921         -
                        return Ok(());
         898  +
            if i == start {
         899  +
                return Err(invalid());
  922    900   
            }
  923    901   
        }
  924         -
                Some(b't') => {
  925         -
                    if !self.remaining().starts_with(b"true") {
  926         -
                        return Err(SerdeError::InvalidInput {
  927         -
                            message: "expected `true`".into(),
  928         -
                        });
         902  +
        if matches!(rem.get(i), Some(b'e') | Some(b'E')) {
         903  +
            i += 1;
         904  +
            if matches!(rem.get(i), Some(b'+') | Some(b'-')) {
         905  +
                i += 1;
         906  +
            }
         907  +
            let start = i;
         908  +
            while rem.get(i).is_some_and(|b| b.is_ascii_digit()) {
         909  +
                i += 1;
         910  +
            }
         911  +
            if i == start {
         912  +
                return Err(invalid());
  929    913   
            }
  930         -
                    self.advance_by(4);
  931         -
                    if depth == 0 {
  932         -
                        return Ok(());
  933    914   
        }
         915  +
        self.advance_by(i);
         916  +
        Ok(())
  934    917   
    }
  935         -
                Some(b'f') => {
  936         -
                    if !self.remaining().starts_with(b"false") {
         918  +
         919  +
    /// Skips a JSON string, accepting exactly the escape sequences `read_string` accepts.
         920  +
    fn skip_string(&mut self) -> Result<(), SerdeError> {
         921  +
        let rem = self.remaining();
         922  +
        debug_assert_eq!(rem.first(), Some(&b'"'));
         923  +
        let mut i = 1;
         924  +
        loop {
         925  +
            match rem.get(i) {
         926  +
                None => {
  937    927   
                    return Err(SerdeError::InvalidInput {
  938         -
                            message: "expected `false`".into(),
  939         -
                        });
         928  +
                        message: "unterminated string".into(),
         929  +
                    })
  940    930   
                }
  941         -
                    self.advance_by(5);
  942         -
                    if depth == 0 {
  943         -
                        return Ok(());
         931  +
                Some(b'"') => {
         932  +
                    i += 1;
         933  +
                    break;
  944    934   
                }
         935  +
                Some(b'\\') => match rem.get(i + 1) {
         936  +
                    Some(b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't') => i += 2,
         937  +
                    Some(b'u')
         938  +
                        if rem
         939  +
                            .get(i + 2..i + 6)
         940  +
                            .is_some_and(|hex| hex.iter().all(u8::is_ascii_hexdigit)) =>
         941  +
                    {
         942  +
                        i += 6
  945    943   
                    }
  946         -
                Some(b'n') => {
  947         -
                    if !self.remaining().starts_with(b"null") {
         944  +
                    _ => {
  948    945   
                        return Err(SerdeError::InvalidInput {
  949         -
                            message: "expected `null`".into(),
  950         -
                        });
         946  +
                            message: "invalid escape sequence in string".into(),
         947  +
                        })
  951    948   
                    }
  952         -
                    self.advance_by(4);
  953         -
                    if depth == 0 {
  954         -
                        return Ok(());
         949  +
                },
         950  +
                Some(_) => i += 1,
  955    951   
            }
  956    952   
        }
  957         -
                Some(c) if c == b'-' || c.is_ascii_digit() => {
  958         -
                    self.consume_number();
  959         -
                    if depth == 0 {
  960         -
                        return Ok(());
         953  +
        self.advance_by(i);
         954  +
        Ok(())
         955  +
    }
         956  +
         957  +
    fn consume_number(&mut self) {
         958  +
        let mut len = 0;
         959  +
        for &b in self.remaining() {
         960  +
            if b.is_ascii_digit() || b == b'-' || b == b'.' || b == b'e' || b == b'E' || b == b'+' {
         961  +
                len += 1;
         962  +
            } else {
         963  +
                break;
  961    964   
            }
  962    965   
        }
  963         -
                Some(_) => {
         966  +
        self.advance_by(len);
         967  +
    }
         968  +
         969  +
    /// Skips one JSON value, validating its syntax as it goes so that an unknown member
         970  +
    /// cannot smuggle malformed JSON past the deserializer. Like `read_string`, raw control
         971  +
    /// characters inside strings are not rejected.
         972  +
    fn skip_value(&mut self) -> Result<(), SerdeError> {
         973  +
        self.skip_whitespace();
         974  +
        match self.remaining().first().copied() {
         975  +
            Some(b'{') => {
         976  +
                self.enter_container()?;
         977  +
                self.advance_by(1);
         978  +
                let mut first = true;
         979  +
                loop {
         980  +
                    if self.next_element(first, b'}', "object")? {
         981  +
                        break;
         982  +
                    }
         983  +
                    first = false;
         984  +
                    if self.remaining().first() != Some(&b'"') {
  964    985   
                        return Err(SerdeError::InvalidInput {
  965         -
                        message: "unexpected token in skip_value".into(),
  966         -
                    })
         986  +
                            message: "expected object key".into(),
         987  +
                        });
  967    988   
                    }
  968         -
                None => {
         989  +
                    self.parse_key()?;
         990  +
                    self.skip_whitespace();
         991  +
                    if self.remaining().first() != Some(&b':') {
  969    992   
                        return Err(SerdeError::InvalidInput {
         993  +
                            message: "expected colon after key".into(),
         994  +
                        });
         995  +
                    }
         996  +
                    self.advance_by(1);
         997  +
                    self.skip_value()?;
         998  +
                }
         999  +
                self.depth -= 1;
        1000  +
                Ok(())
        1001  +
            }
        1002  +
            Some(b'[') => {
        1003  +
                self.enter_container()?;
        1004  +
                self.advance_by(1);
        1005  +
                let mut first = true;
        1006  +
                loop {
        1007  +
                    if self.next_element(first, b']', "array")? {
        1008  +
                        break;
        1009  +
                    }
        1010  +
                    first = false;
        1011  +
                    self.skip_value()?;
        1012  +
                }
        1013  +
                self.depth -= 1;
        1014  +
                Ok(())
        1015  +
            }
        1016  +
            Some(b'"') => self.skip_string(),
        1017  +
            Some(b't') => self.skip_literal(b"true"),
        1018  +
            Some(b'f') => self.skip_literal(b"false"),
        1019  +
            Some(b'n') => self.skip_literal(b"null"),
        1020  +
            Some(c) if c == b'-' || c.is_ascii_digit() => self.skip_number(),
        1021  +
            Some(_) => Err(SerdeError::InvalidInput {
        1022  +
                message: "unexpected token in skip_value".into(),
        1023  +
            }),
        1024  +
            None => Err(SerdeError::InvalidInput {
  970   1025   
                message: "unexpected end of input".into(),
  971         -
                    })
        1026  +
            }),
  972   1027   
        }
  973   1028   
    }
        1029  +
        1030  +
    fn skip_literal(&mut self, literal: &'static [u8]) -> Result<(), SerdeError> {
        1031  +
        if !self.remaining().starts_with(literal) {
        1032  +
            return Err(SerdeError::InvalidInput {
        1033  +
                message: format!("expected `{}`", String::from_utf8_lossy(literal)),
        1034  +
            });
  974   1035   
        }
        1036  +
        self.advance_by(literal.len());
        1037  +
        Ok(())
  975   1038   
    }
  976   1039   
  977   1040   
    fn read_integer_value(&mut self) -> Result<i64, SerdeError> {
  978   1041   
        self.skip_whitespace();
  979   1042   
        let rem = self.remaining();
  980   1043   
        let mut len = 0;
  981   1044   
        for &b in rem {
  982   1045   
            if b.is_ascii_digit() || b == b'-' || b == b'+' {
  983   1046   
                len += 1;
  984   1047   
            } else {
@@ -2144,2207 +2174,2454 @@
 2164   2227   
        assert_depth_error(err);
 2165   2228   
 2166   2229   
        // 10 levels fits inside the custom limit.
 2167   2230   
        let settings_ok = JsonCodecSettings::builder().max_depth(16).build();
 2168   2231   
        let payload_ok = build_nested("[", "]", 10);
 2169   2232   
        let mut deser_ok = JsonDeserializer::new(&payload_ok, Arc::new(settings_ok));
 2170   2233   
        deser_ok
 2171   2234   
            .read_list(dummy_schema(), &mut recursive_list_consumer)
 2172   2235   
            .expect("10-level nesting should succeed under custom limit");
 2173   2236   
    }
        2237  +
        2238  +
    mod separators {
        2239  +
        //! JSON syntax the deserializer must reject: separators (exactly one `,` between
        2240  +
        //! elements, none before a closing delimiter), bytes after the top-level value, and
        2241  +
        //! malformed values inside skipped unknown members. Smithy protocol tests
        2242  +
        //! `RestJsonInvalidJsonBody_case7` (`{"int": 10,}`) and `RestJsonInvalidJsonBody_case1`
        2243  +
        //! (`{ "int": 10 }abc`) require the first two.
        2244  +
        use super::*;
        2245  +
        use aws_smithy_schema::{shape_id, ShapeType};
        2246  +
        2247  +
        static INT: Schema = Schema::new_member(
        2248  +
            shape_id!("test", "Input", "int"),
        2249  +
            ShapeType::Integer,
        2250  +
            "int",
        2251  +
            0,
        2252  +
        );
        2253  +
        static LIST: Schema = Schema::new_member(
        2254  +
            shape_id!("test", "Input", "list"),
        2255  +
            ShapeType::List,
        2256  +
            "list",
        2257  +
            1,
        2258  +
        );
        2259  +
        static INPUT: Schema = Schema::new_struct(
        2260  +
            shape_id!("test", "Input"),
        2261  +
            ShapeType::Structure,
        2262  +
            &[&INT, &LIST],
        2263  +
        );
        2264  +
        2265  +
        fn deser(input: &[u8]) -> JsonDeserializer<'_> {
        2266  +
            JsonDeserializer::new(input, Arc::new(JsonCodecSettings::default()))
        2267  +
        }
        2268  +
        2269  +
        /// Reads `INPUT` and returns `(int, list)`; unknown members are skipped.
        2270  +
        fn read_input(body: &[u8]) -> Result<(Option<i32>, Vec<i32>), SerdeError> {
        2271  +
            let mut d = deser(body);
        2272  +
            let mut int = None;
        2273  +
            let mut list = Vec::new();
        2274  +
            d.read_struct(&INPUT, &mut |member, d| {
        2275  +
                match member.member_index() {
        2276  +
                    Some(0) => int = Some(d.read_integer(member)?),
        2277  +
                    Some(1) => d.read_list(member, &mut |d| {
        2278  +
                        list.push(d.read_integer(member)?);
        2279  +
                        Ok(())
        2280  +
                    })?,
        2281  +
                    _ => {}
        2282  +
                }
        2283  +
                Ok(())
        2284  +
            })?;
        2285  +
            Ok((int, list))
        2286  +
        }
        2287  +
        2288  +
        #[test]
        2289  +
        fn well_formed_input_is_read() {
        2290  +
            assert_eq!(
        2291  +
                read_input(br#"{ "int": 10 , "list": [ 1 , 2 ] }"#).unwrap(),
        2292  +
                (Some(10), vec![1, 2])
        2293  +
            );
        2294  +
            assert_eq!(read_input(br#"{}"#).unwrap(), (None, vec![]));
        2295  +
            assert_eq!(read_input(br#"{"list":[]}"#).unwrap(), (None, vec![]));
        2296  +
            assert_eq!(
        2297  +
                read_input(b"  { \"int\": 1 }  \n").unwrap(),
        2298  +
                (Some(1), vec![])
        2299  +
            );
        2300  +
        }
        2301  +
        2302  +
        #[test]
        2303  +
        fn trailing_comma_in_object_is_rejected() {
        2304  +
            assert!(read_input(br#"{"int": 10,}"#).is_err());
        2305  +
        }
        2306  +
        2307  +
        #[test]
        2308  +
        fn leading_and_repeated_commas_in_object_are_rejected() {
        2309  +
            assert!(read_input(br#"{,"int": 10}"#).is_err());
        2310  +
            assert!(read_input(br#"{"int": 10,,"list": []}"#).is_err());
        2311  +
            assert!(read_input(br#"{"int": 10,,}"#).is_err());
        2312  +
        }
        2313  +
        2314  +
        #[test]
        2315  +
        fn missing_comma_in_object_is_rejected() {
        2316  +
            assert!(read_input(br#"{"int": 10 "list": []}"#).is_err());
        2317  +
        }
        2318  +
        2319  +
        #[test]
        2320  +
        fn commas_in_array_are_checked() {
        2321  +
            assert!(read_input(br#"{"list": [1,]}"#).is_err());
        2322  +
            assert!(read_input(br#"{"list": [,1]}"#).is_err());
        2323  +
            assert!(read_input(br#"{"list": [1,,2]}"#).is_err());
        2324  +
            assert!(read_input(br#"{"list": [1 2]}"#).is_err());
        2325  +
        }
        2326  +
        2327  +
        #[test]
        2328  +
        fn skipped_unknown_members_are_still_validated() {
        2329  +
            assert_eq!(
        2330  +
                read_input(br#"{"unknown": {"a": [1, {"b": null}], "c": "x"}, "int": 1}"#).unwrap(),
        2331  +
                (Some(1), vec![])
        2332  +
            );
        2333  +
            assert!(read_input(br#"{"unknown": [1,,2], "int": 1}"#).is_err());
        2334  +
            assert!(read_input(br#"{"unknown": {"a": 1,}, "int": 1}"#).is_err());
        2335  +
            assert!(read_input(br#"{"unknown": "unterminated, "int": 1}"#).is_err());
        2336  +
            assert!(read_input(br#"{"unknown": tru, "int": 1}"#).is_err());
        2337  +
        }
        2338  +
        2339  +
        #[test]
        2340  +
        fn trailing_characters_after_the_top_level_value_are_rejected() {
        2341  +
            assert!(read_input(br#"{ "int": 10 }abc"#).is_err());
        2342  +
            assert!(read_input(br#"{ "int": 10 },"#).is_err());
        2343  +
            assert!(read_input(br#"{ "int": 10 }{}"#).is_err());
        2344  +
            assert!(deser(br#"[1]x"#).read_integer_list(&LIST).is_err());
        2345  +
            assert!(deser(br#"{"k":"v"} {}"#)
        2346  +
                .read_string_string_map(&LIST)
        2347  +
                .is_err());
        2348  +
            assert!(deser(br#"{"a":1}]"#).read_document(&INT).is_err());
        2349  +
            assert!(deser(br#"[1,2]"#).read_document(&INT).is_ok());
        2350  +
        }
        2351  +
        2352  +
        #[test]
        2353  +
        fn skipped_numbers_must_match_the_json_grammar() {
        2354  +
            for ok in [
        2355  +
                b"0" as &[u8],
        2356  +
                b"-0",
        2357  +
                b"10",
        2358  +
                b"-1.5",
        2359  +
                b"1e3",
        2360  +
                b"1E+3",
        2361  +
                b"2.5e-7",
        2362  +
            ] {
        2363  +
                let body = [b"{\"unknown\": " as &[u8], ok, b", \"int\": 1}"].concat();
        2364  +
                assert_eq!(
        2365  +
                    read_input(&body).unwrap(),
        2366  +
                    (Some(1), vec![]),
        2367  +
                    "{}",
        2368  +
                    String::from_utf8_lossy(ok)
        2369  +
                );
        2370  +
            }
        2371  +
            for bad in [
        2372  +
                b"01" as &[u8],
        2373  +
                b"1.",
        2374  +
                b"--1",
        2375  +
                b"+1",
        2376  +
                b".5",
        2377  +
                b"1e",
        2378  +
                b"1e+",
        2379  +
                b"-",
        2380  +
                b"0x1",
        2381  +
            ] {
        2382  +
                let body = [b"{\"unknown\": " as &[u8], bad, b", \"int\": 1}"].concat();
        2383  +
                assert!(
        2384  +
                    read_input(&body).is_err(),
        2385  +
                    "{}",
        2386  +
                    String::from_utf8_lossy(bad)
        2387  +
                );
        2388  +
            }
        2389  +
        }
        2390  +
        2391  +
        #[test]
        2392  +
        fn skipped_strings_must_use_valid_escapes() {
        2393  +
            assert_eq!(
        2394  +
                read_input(br#"{"unknown": "a\"b\\c\/\b\f\n\r\t\u00e9", "int": 1}"#).unwrap(),
        2395  +
                (Some(1), vec![])
        2396  +
            );
        2397  +
            assert!(read_input(br#"{"unknown": "\q", "int": 1}"#).is_err());
        2398  +
            assert!(read_input(br#"{"unknown": "\u12", "int": 1}"#).is_err());
        2399  +
            assert!(read_input(br#"{"unknown": "\uZZZZ", "int": 1}"#).is_err());
        2400  +
            assert!(read_input(br#"{"unknown": "abc\", "int": 1}"#).is_err());
        2401  +
        }
        2402  +
        2403  +
        #[test]
        2404  +
        fn fast_path_collections_check_separators() {
        2405  +
            assert_eq!(
        2406  +
                deser(br#"["a","b"]"#).read_string_list(&LIST).unwrap(),
        2407  +
                vec!["a", "b"]
        2408  +
            );
        2409  +
            assert!(deser(br#"["a",]"#).read_string_list(&LIST).is_err());
        2410  +
            assert!(deser(br#"[,"a"]"#).read_string_list(&LIST).is_err());
        2411  +
            assert!(deser(br#"[1,,2]"#).read_integer_list(&LIST).is_err());
        2412  +
            assert!(deser(br#"[1,]"#).read_long_list(&LIST).is_err());
        2413  +
            assert!(deser(br#"["YQ==",]"#).read_blob_list(&LIST).is_err());
        2414  +
            assert_eq!(
        2415  +
                deser(br#"{"k":"v"}"#)
        2416  +
                    .read_string_string_map(&LIST)
        2417  +
                    .unwrap()
        2418  +
                    .len(),
        2419  +
                1
        2420  +
            );
        2421  +
            assert!(deser(br#"{"k":"v",}"#)
        2422  +
                .read_string_string_map(&LIST)
        2423  +
                .is_err());
        2424  +
            assert!(deser(br#"{"k":"v" "j":"w"}"#)
        2425  +
                .read_string_string_map(&LIST)
        2426  +
                .is_err());
        2427  +
        }
        2428  +
        2429  +
        #[test]
        2430  +
        fn generic_map_checks_separators() {
        2431  +
            let mut count = 0;
        2432  +
            assert!(deser(br#"{"a":1,"b":2}"#)
        2433  +
                .read_map(&LIST, &mut |_, d| {
        2434  +
                    count += 1;
        2435  +
                    d.read_integer(&INT).map(|_| ())
        2436  +
                })
        2437  +
                .is_ok());
        2438  +
            assert_eq!(count, 2);
        2439  +
            assert!(deser(br#"{"a":1,}"#)
        2440  +
                .read_map(&LIST, &mut |_, d| d.read_integer(&INT).map(|_| ()))
        2441  +
                .is_err());
        2442  +
        }
        2443  +
        2444  +
        #[test]
        2445  +
        fn documents_check_separators() {
        2446  +
            assert!(deser(br#"{"a":[1,2],"b":{"c":true}}"#)
        2447  +
                .read_document(&INT)
        2448  +
                .is_ok());
        2449  +
            assert!(deser(br#"{"a":1,}"#).read_document(&INT).is_err());
        2450  +
            assert!(deser(br#"[1,,2]"#).read_document(&INT).is_err());
        2451  +
            assert!(deser(br#"{,"a":1}"#).read_document(&INT).is_err());
        2452  +
        }
        2453  +
    }
 2174   2454   
}

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

@@ -165,165 +214,243 @@
  185    185   
        let cfg = cfg_with_metadata("MyService", "DoThing");
  186    186   
        let request = AwsJsonRpcProtocol::aws_json_1_0("MyService")
  187    187   
            .serialize_request(&EmptyStruct, &TEST_SCHEMA, "https://example.com", &cfg)
  188    188   
            .unwrap();
  189    189   
        assert_eq!(
  190    190   
            request.headers().get("X-Amz-Target").unwrap(),
  191    191   
            "MyService.DoThing"
  192    192   
        );
  193    193   
    }
  194    194   
         195  +
    /// The body deserializer handed out by `deserialize_response` must reject malformed JSON
         196  +
    /// bodies end to end, not only inside containers. These are the bodies of Smithy protocol
         197  +
    /// tests `RestJsonInvalidJsonBody_case1` and `RestJsonInvalidJsonBody_case7`.
         198  +
    #[test]
         199  +
    fn malformed_response_bodies_are_rejected() {
         200  +
        use aws_smithy_runtime_api::http::Response;
         201  +
        use aws_smithy_types::body::SdkBody;
         202  +
         203  +
        for body in [r#"{ "int": 10 }abc"#, r#"{"int": 10,}"#] {
         204  +
            let response = Response::new(200u16.try_into().unwrap(), SdkBody::from(body));
         205  +
            let mut deser = AwsJsonRpcProtocol::aws_json_1_0("TestService")
         206  +
                .deserialize_response(&response, &TEST_SCHEMA, &ConfigBag::base())
         207  +
                .unwrap();
         208  +
            let result = deser.read_struct(&TEST_SCHEMA, &mut |_, _| Ok(()));
         209  +
            assert!(result.is_err(), "body {body:?} must be rejected");
         210  +
        }
         211  +
         212  +
        let response = Response::new(
         213  +
            200u16.try_into().unwrap(),
         214  +
            SdkBody::from(r#"{ "int": 10 }"#),
         215  +
        );
         216  +
        let mut deser = AwsJsonRpcProtocol::aws_json_1_0("TestService")
         217  +
            .deserialize_response(&response, &TEST_SCHEMA, &ConfigBag::base())
         218  +
            .unwrap();
         219  +
        deser
         220  +
            .read_struct(&TEST_SCHEMA, &mut |_, _| Ok(()))
         221  +
            .expect("well-formed body is accepted");
         222  +
    }
         223  +
  195    224   
    #[test]
  196    225   
    fn json_1_0_protocol_id() {
  197    226   
        assert_eq!(
  198    227   
            AwsJsonRpcProtocol::aws_json_1_0("Svc")
  199    228   
                .protocol_id()
  200    229   
                .as_str(),
  201    230   
            "aws.protocols#awsJson1_0"
  202    231   
        );
  203    232   
    }
  204    233   

tmp-codegen-diff/aws-sdk/sdk/bedrockruntime/Cargo.toml

@@ -19,19 +79,79 @@
   39     39   
path = "../aws-smithy-eventstream"
   40     40   
version = "0.61.2"
   41     41   
   42     42   
[dependencies.aws-smithy-http]
   43     43   
path = "../aws-smithy-http"
   44     44   
features = ["event-stream"]
   45     45   
version = "0.64.0"
   46     46   
   47     47   
[dependencies.aws-smithy-json]
   48     48   
path = "../aws-smithy-json"
   49         -
version = "0.63.0"
          49  +
version = "0.63.1"
   50     50   
   51     51   
[dependencies.aws-smithy-observability]
   52     52   
path = "../aws-smithy-observability"
   53     53   
version = "0.3.0"
   54     54   
   55     55   
[dependencies.aws-smithy-runtime]
   56     56   
path = "../aws-smithy-runtime"
   57     57   
features = ["client", "http-auth"]
   58     58   
version = "1.14.0"
   59     59   

tmp-codegen-diff/aws-sdk/sdk/cloudwatchlogs/Cargo.toml

@@ -15,15 +75,75 @@
   35     35   
path = "../aws-smithy-eventstream"
   36     36   
version = "0.61.2"
   37     37   
   38     38   
[dependencies.aws-smithy-http]
   39     39   
path = "../aws-smithy-http"
   40     40   
features = ["event-stream"]
   41     41   
version = "0.64.0"
   42     42   
   43     43   
[dependencies.aws-smithy-json]
   44     44   
path = "../aws-smithy-json"
   45         -
version = "0.63.0"
          45  +
version = "0.63.1"
   46     46   
   47     47   
[dependencies.aws-smithy-observability]
   48     48   
path = "../aws-smithy-observability"
   49     49   
version = "0.3.0"
   50     50   
   51     51   
[dependencies.aws-smithy-runtime]
   52     52   
path = "../aws-smithy-runtime"
   53     53   
features = ["client"]
   54     54   
version = "1.14.0"
   55     55   

tmp-codegen-diff/aws-sdk/sdk/codecatalyst/Cargo.toml

@@ -9,9 +69,69 @@
   29     29   
[dependencies.aws-smithy-async]
   30     30   
path = "../aws-smithy-async"
   31     31   
version = "1.3.0"
   32     32   
   33     33   
[dependencies.aws-smithy-http]
   34     34   
path = "../aws-smithy-http"
   35     35   
version = "0.64.0"
   36     36   
   37     37   
[dependencies.aws-smithy-json]
   38     38   
path = "../aws-smithy-json"
   39         -
version = "0.63.0"
          39  +
version = "0.63.1"
   40     40   
   41     41   
[dependencies.aws-smithy-observability]
   42     42   
path = "../aws-smithy-observability"
   43     43   
version = "0.3.0"
   44     44   
   45     45   
[dependencies.aws-smithy-runtime]
   46     46   
path = "../aws-smithy-runtime"
   47     47   
features = ["client", "http-auth"]
   48     48   
version = "1.14.0"
   49     49   

tmp-codegen-diff/aws-sdk/sdk/config/Cargo.toml

@@ -9,9 +69,69 @@
   29     29   
[dependencies.aws-smithy-async]
   30     30   
path = "../aws-smithy-async"
   31     31   
version = "1.3.0"
   32     32   
   33     33   
[dependencies.aws-smithy-http]
   34     34   
path = "../aws-smithy-http"
   35     35   
version = "0.64.0"
   36     36   
   37     37   
[dependencies.aws-smithy-json]
   38     38   
path = "../aws-smithy-json"
   39         -
version = "0.63.0"
          39  +
version = "0.63.1"
   40     40   
   41     41   
[dependencies.aws-smithy-observability]
   42     42   
path = "../aws-smithy-observability"
   43     43   
version = "0.3.0"
   44     44   
   45     45   
[dependencies.aws-smithy-runtime]
   46     46   
path = "../aws-smithy-runtime"
   47     47   
features = ["client"]
   48     48   
version = "1.14.0"
   49     49   

tmp-codegen-diff/aws-sdk/sdk/dynamodb/Cargo.toml

@@ -9,9 +69,69 @@
   29     29   
[dependencies.aws-smithy-async]
   30     30   
path = "../aws-smithy-async"
   31     31   
version = "1.3.0"
   32     32   
   33     33   
[dependencies.aws-smithy-http]
   34     34   
path = "../aws-smithy-http"
   35     35   
version = "0.64.0"
   36     36   
   37     37   
[dependencies.aws-smithy-json]
   38     38   
path = "../aws-smithy-json"
   39         -
version = "0.63.0"
          39  +
version = "0.63.1"
   40     40   
   41     41   
[dependencies.aws-smithy-observability]
   42     42   
path = "../aws-smithy-observability"
   43     43   
version = "0.3.0"
   44     44   
   45     45   
[dependencies.aws-smithy-runtime]
   46     46   
path = "../aws-smithy-runtime"
   47     47   
features = ["client"]
   48     48   
version = "1.14.0"
   49     49   

tmp-codegen-diff/aws-sdk/sdk/ec2/Cargo.toml

@@ -9,9 +69,69 @@
   29     29   
[dependencies.aws-smithy-async]
   30     30   
path = "../aws-smithy-async"
   31     31   
version = "1.3.0"
   32     32   
   33     33   
[dependencies.aws-smithy-http]
   34     34   
path = "../aws-smithy-http"
   35     35   
version = "0.64.0"
   36     36   
   37     37   
[dependencies.aws-smithy-json]
   38     38   
path = "../aws-smithy-json"
   39         -
version = "0.63.0"
          39  +
version = "0.63.1"
   40     40   
   41     41   
[dependencies.aws-smithy-observability]
   42     42   
path = "../aws-smithy-observability"
   43     43   
version = "0.3.0"
   44     44   
   45     45   
[dependencies.aws-smithy-query]
   46     46   
path = "../aws-smithy-query"
   47     47   
version = "0.62.0"
   48     48   
   49     49   
[dependencies.aws-smithy-runtime]

tmp-codegen-diff/aws-sdk/sdk/ecs/Cargo.toml

@@ -9,9 +69,69 @@
   29     29   
[dependencies.aws-smithy-async]
   30     30   
path = "../aws-smithy-async"
   31     31   
version = "1.3.0"
   32     32   
   33     33   
[dependencies.aws-smithy-http]
   34     34   
path = "../aws-smithy-http"
   35     35   
version = "0.64.0"
   36     36   
   37     37   
[dependencies.aws-smithy-json]
   38     38   
path = "../aws-smithy-json"
   39         -
version = "0.63.0"
          39  +
version = "0.63.1"
   40     40   
   41     41   
[dependencies.aws-smithy-observability]
   42     42   
path = "../aws-smithy-observability"
   43     43   
version = "0.3.0"
   44     44   
   45     45   
[dependencies.aws-smithy-runtime]
   46     46   
path = "../aws-smithy-runtime"
   47     47   
features = ["client"]
   48     48   
version = "1.14.0"
   49     49   

tmp-codegen-diff/aws-sdk/sdk/glacier/Cargo.toml

@@ -13,13 +73,73 @@
   33     33   
[dependencies.aws-smithy-async]
   34     34   
path = "../aws-smithy-async"
   35     35   
version = "1.3.0"
   36     36   
   37     37   
[dependencies.aws-smithy-http]
   38     38   
path = "../aws-smithy-http"
   39     39   
version = "0.64.0"
   40     40   
   41     41   
[dependencies.aws-smithy-json]
   42     42   
path = "../aws-smithy-json"
   43         -
version = "0.63.0"
          43  +
version = "0.63.1"
   44     44   
   45     45   
[dependencies.aws-smithy-observability]
   46     46   
path = "../aws-smithy-observability"
   47     47   
version = "0.3.0"
   48     48   
   49     49   
[dependencies.aws-smithy-runtime]
   50     50   
path = "../aws-smithy-runtime"
   51     51   
features = ["client"]
   52     52   
version = "1.14.0"
   53     53   

tmp-codegen-diff/aws-sdk/sdk/iam/Cargo.toml

@@ -9,9 +69,69 @@
   29     29   
[dependencies.aws-smithy-async]
   30     30   
path = "../aws-smithy-async"
   31     31   
version = "1.3.0"
   32     32   
   33     33   
[dependencies.aws-smithy-http]
   34     34   
path = "../aws-smithy-http"
   35     35   
version = "0.64.0"
   36     36   
   37     37   
[dependencies.aws-smithy-json]
   38     38   
path = "../aws-smithy-json"
   39         -
version = "0.63.0"
          39  +
version = "0.63.1"
   40     40   
   41     41   
[dependencies.aws-smithy-observability]
   42     42   
path = "../aws-smithy-observability"
   43     43   
version = "0.3.0"
   44     44   
   45     45   
[dependencies.aws-smithy-query]
   46     46   
path = "../aws-smithy-query"
   47     47   
version = "0.62.0"
   48     48   
   49     49   
[dependencies.aws-smithy-runtime]