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") {
|
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
|
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 | }
|
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 {
|
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 | }
|