1#![forbid(unsafe_code)]
2
3use crate::{ProtocolError, Result};
4
5pub const TNS_MAX_SHORT_LENGTH: usize = 252;
6pub const TNS_LONG_LENGTH_INDICATOR: u8 = 0xfe;
7pub const TNS_NULL_LENGTH_INDICATOR: u8 = 0xff;
8
9const MIB: usize = 1024 * 1024;
10
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub struct ProtocolLimits {
19 pub max_packet_bytes: usize,
21 pub max_frame_bytes: usize,
23 pub max_response_bytes: usize,
25 pub max_columns: usize,
27 pub max_binds: usize,
29 pub max_batch_rows: usize,
31 pub max_object_depth: usize,
33 pub max_object_elements: usize,
35 pub max_vector_dimensions: usize,
37 pub max_lob_chunks: usize,
39 pub max_length_prefixed_elements: usize,
41}
42
43impl Default for ProtocolLimits {
44 fn default() -> Self {
45 Self::DEFAULT
46 }
47}
48
49impl ProtocolLimits {
50 pub const DEFAULT: Self = Self {
51 max_packet_bytes: 16 * MIB,
52 max_frame_bytes: 16 * MIB,
53 max_response_bytes: 256 * MIB,
54 max_columns: 4096,
55 max_binds: 65_535,
56 max_batch_rows: 1_000_000,
57 max_object_depth: 256,
58 max_object_elements: 1_000_000,
59 max_vector_dimensions: 1_000_000,
60 max_lob_chunks: 1_000_000,
61 max_length_prefixed_elements: 1_000_000,
62 };
63
64 pub fn validate(self) -> Result<Self> {
66 for (name, value) in self.named_limits() {
67 if value == 0 {
68 return Err(ProtocolError::ResourceLimit {
69 limit: name,
70 observed: 0,
71 maximum: 1,
72 });
73 }
74 }
75 if self.max_packet_bytes > self.max_frame_bytes {
76 return Err(ProtocolError::ResourceLimit {
77 limit: "packet_bytes",
78 observed: self.max_packet_bytes,
79 maximum: self.max_frame_bytes,
80 });
81 }
82 if self.max_frame_bytes > self.max_response_bytes {
83 return Err(ProtocolError::ResourceLimit {
84 limit: "frame_bytes",
85 observed: self.max_frame_bytes,
86 maximum: self.max_response_bytes,
87 });
88 }
89 Ok(self)
90 }
91
92 pub fn check_packet_bytes(&self, observed: usize) -> Result<()> {
93 self.check("packet_bytes", observed, self.max_packet_bytes)
94 }
95
96 pub fn check_frame_bytes(&self, observed: usize) -> Result<()> {
97 self.check("frame_bytes", observed, self.max_frame_bytes)
98 }
99
100 pub fn check_response_bytes(&self, observed: usize) -> Result<()> {
101 self.check("response_bytes", observed, self.max_response_bytes)
102 }
103
104 pub fn check_columns(&self, observed: usize) -> Result<()> {
105 self.check("columns", observed, self.max_columns)
106 }
107
108 pub fn check_binds(&self, observed: usize) -> Result<()> {
109 self.check("binds", observed, self.max_binds)
110 }
111
112 pub fn check_batch_rows(&self, observed: usize) -> Result<()> {
113 self.check("batch_rows", observed, self.max_batch_rows)
114 }
115
116 pub fn check_object_depth(&self, observed: usize) -> Result<()> {
117 self.check("object_depth", observed, self.max_object_depth)
118 }
119
120 pub fn check_object_elements(&self, observed: usize) -> Result<()> {
121 self.check("object_elements", observed, self.max_object_elements)
122 }
123
124 pub fn check_vector_dimensions(&self, observed: usize) -> Result<()> {
125 self.check("vector_dimensions", observed, self.max_vector_dimensions)
126 }
127
128 pub fn check_lob_chunks(&self, observed: usize) -> Result<()> {
129 self.check("lob_chunks", observed, self.max_lob_chunks)
130 }
131
132 pub fn check_length_prefixed_elements(&self, observed: usize) -> Result<()> {
133 self.check(
134 "length_prefixed_elements",
135 observed,
136 self.max_length_prefixed_elements,
137 )
138 }
139
140 fn check(&self, limit: &'static str, observed: usize, maximum: usize) -> Result<()> {
141 if observed <= maximum {
142 Ok(())
143 } else {
144 Err(ProtocolError::ResourceLimit {
145 limit,
146 observed,
147 maximum,
148 })
149 }
150 }
151
152 fn named_limits(&self) -> [(&'static str, usize); 11] {
153 [
154 ("packet_bytes", self.max_packet_bytes),
155 ("frame_bytes", self.max_frame_bytes),
156 ("response_bytes", self.max_response_bytes),
157 ("columns", self.max_columns),
158 ("binds", self.max_binds),
159 ("batch_rows", self.max_batch_rows),
160 ("object_depth", self.max_object_depth),
161 ("object_elements", self.max_object_elements),
162 ("vector_dimensions", self.max_vector_dimensions),
163 ("lob_chunks", self.max_lob_chunks),
164 (
165 "length_prefixed_elements",
166 self.max_length_prefixed_elements,
167 ),
168 ]
169 }
170}
171
172#[derive(Clone, Copy, Debug, Eq, PartialEq)]
173pub enum PacketLengthWidth {
174 Legacy16,
175 Large32,
176}
177
178#[derive(Clone, Debug, Default, Eq, PartialEq)]
179pub struct TtcWriter {
180 bytes: Vec<u8>,
181 seq_num: u8,
182}
183
184impl TtcWriter {
185 pub fn new() -> Self {
186 Self::default()
187 }
188
189 pub fn with_capacity(capacity: usize) -> Self {
197 Self {
198 bytes: Vec::with_capacity(capacity),
199 seq_num: 0,
200 }
201 }
202
203 pub fn into_bytes(self) -> Vec<u8> {
204 self.bytes
205 }
206
207 pub fn write_u8(&mut self, value: u8) {
208 self.bytes.push(value);
209 }
210
211 pub fn write_u16be(&mut self, value: u16) {
212 self.bytes.extend_from_slice(&value.to_be_bytes());
213 }
214
215 pub fn write_u16le(&mut self, value: u16) {
216 self.bytes.extend_from_slice(&value.to_le_bytes());
217 }
218
219 pub fn write_u32be(&mut self, value: u32) {
220 self.bytes.extend_from_slice(&value.to_be_bytes());
221 }
222
223 pub fn write_u64be(&mut self, value: u64) {
224 self.bytes.extend_from_slice(&value.to_be_bytes());
225 }
226
227 pub fn write_ub2(&mut self, value: u16) {
228 if value == 0 {
229 self.write_u8(0);
230 } else if value <= u16::from(u8::MAX) {
231 self.write_u8(1);
232 self.write_u8(value as u8);
233 } else {
234 self.write_u8(2);
235 self.write_u16be(value);
236 }
237 }
238
239 pub fn write_ub4(&mut self, value: u32) {
240 if value == 0 {
241 self.write_u8(0);
242 } else if value <= u32::from(u8::MAX) {
243 self.write_u8(1);
244 self.write_u8(value as u8);
245 } else if value <= u32::from(u16::MAX) {
246 self.write_u8(2);
247 self.write_u16be(value as u16);
248 } else {
249 self.write_u8(4);
250 self.write_u32be(value);
251 }
252 }
253
254 pub fn write_ub8(&mut self, value: u64) {
255 if value == 0 {
256 self.write_u8(0);
257 } else if value <= u64::from(u8::MAX) {
258 self.write_u8(1);
259 self.write_u8(value as u8);
260 } else if value <= u64::from(u16::MAX) {
261 self.write_u8(2);
262 self.write_u16be(value as u16);
263 } else if value <= u64::from(u32::MAX) {
264 self.write_u8(4);
265 self.write_u32be(value as u32);
266 } else {
267 self.write_u8(8);
268 self.write_u64be(value);
269 }
270 }
271
272 pub fn write_seq_num(&mut self) {
273 self.seq_num = self.seq_num.wrapping_add(1);
274 if self.seq_num == 0 {
275 self.seq_num = 1;
276 }
277 self.write_u8(self.seq_num);
278 }
279
280 pub fn write_raw(&mut self, value: &[u8]) {
281 self.bytes.extend_from_slice(value);
282 }
283
284 pub fn write_bytes_with_length(&mut self, value: &[u8]) -> Result<()> {
285 if value.len() <= TNS_MAX_SHORT_LENGTH {
286 self.write_u8(value.len() as u8);
287 self.write_raw(value);
288 return Ok(());
289 }
290 self.write_u8(TNS_LONG_LENGTH_INDICATOR);
291 for chunk in value.chunks(32_767) {
292 self.write_ub4(u32::try_from(chunk.len()).map_err(|_| {
293 ProtocolError::InvalidPacketLength {
294 length: chunk.len(),
295 minimum: 0,
296 }
297 })?);
298 self.write_raw(chunk);
299 }
300 self.write_ub4(0);
301 Ok(())
302 }
303
304 pub fn write_bytes_with_two_lengths(&mut self, value: Option<&[u8]>) -> Result<()> {
305 match value {
306 Some(bytes) => {
307 self.write_ub4(u32::try_from(bytes.len()).map_err(|_| {
308 ProtocolError::InvalidPacketLength {
309 length: bytes.len(),
310 minimum: 0,
311 }
312 })?);
313 if !bytes.is_empty() {
314 self.write_bytes_with_length(bytes)?;
315 }
316 }
317 None => self.write_ub4(0),
318 }
319 Ok(())
320 }
321
322 pub fn write_str_two_lengths(&mut self, value: &str) -> Result<()> {
323 self.write_bytes_with_two_lengths(Some(value.as_bytes()))
324 }
325
326 pub fn write_sb4(&mut self, value: i32) {
331 let (sign, magnitude) = if value < 0 {
332 (0x80u8, value.unsigned_abs())
333 } else {
334 (0u8, value as u32)
335 };
336 if magnitude == 0 {
337 self.write_u8(0);
338 } else if magnitude <= u32::from(u8::MAX) {
339 self.write_u8(1 | sign);
340 self.write_u8(magnitude as u8);
341 } else if magnitude <= u32::from(u16::MAX) {
342 self.write_u8(2 | sign);
343 self.write_u16be(magnitude as u16);
344 } else {
345 self.write_u8(4 | sign);
346 self.write_u32be(magnitude);
347 }
348 }
349
350 pub fn write_keyword_value_pair(
354 &mut self,
355 text_value: Option<&[u8]>,
356 binary_value: Option<&[u8]>,
357 keyword: u16,
358 ) -> Result<()> {
359 self.write_bytes_with_two_lengths(text_value)?;
360 self.write_bytes_with_two_lengths(binary_value)?;
361 self.write_ub2(keyword);
362 Ok(())
363 }
364
365 pub fn write_function_code(&mut self, function_code: u8) {
366 self.write_u8(crate::thin::TNS_MSG_TYPE_FUNCTION);
367 self.write_u8(function_code);
368 self.write_seq_num();
369 }
370
371 pub fn write_function_code_with_seq(&mut self, function_code: u8, seq_num: u8) {
372 self.write_u8(crate::thin::TNS_MSG_TYPE_FUNCTION);
373 self.write_u8(function_code);
374 self.write_u8(seq_num);
375 }
376
377 pub fn write_function_header(&mut self, function_code: u8, seq_num: u8, ttc_field_version: u8) {
383 self.write_function_code_with_seq(function_code, seq_num);
384 if crate::thin::version_gates::writes_pipeline_token(ttc_field_version) {
385 self.write_ub8(0);
386 }
387 }
388
389 pub fn write_piggyback_header(
392 &mut self,
393 function_code: u8,
394 seq_num: u8,
395 ttc_field_version: u8,
396 ) {
397 self.write_u8(crate::thin::TNS_MSG_TYPE_PIGGYBACK);
398 self.write_u8(function_code);
399 self.write_u8(seq_num);
400 if crate::thin::version_gates::writes_pipeline_token(ttc_field_version) {
401 self.write_ub8(0);
402 }
403 }
404}
405
406pub trait BoundedReader {
433 fn remaining(&self) -> usize;
436
437 fn protocol_limits(&self) -> ProtocolLimits {
440 ProtocolLimits::DEFAULT
441 }
442
443 fn alloc_count_checked(&self, count: usize, min_bytes_per_elem: usize) -> Result<usize> {
453 self.protocol_limits()
454 .check_length_prefixed_elements(count)?;
455 let per_elem = min_bytes_per_elem.max(1);
456 match count.checked_mul(per_elem) {
457 Some(needed) if needed <= self.remaining() => Ok(count),
458 _ => Err(ProtocolError::TtcDecode(
459 "declared element count exceeds remaining buffer",
460 )),
461 }
462 }
463
464 fn with_capacity_bounded<T>(&self, count: usize, min_bytes_per_elem: usize) -> Vec<T> {
472 let per_elem = min_bytes_per_elem.max(1);
473 Vec::with_capacity(count.min(self.remaining() / per_elem))
474 }
475
476 fn with_capacity_limited<T, F>(
480 &self,
481 count: usize,
482 min_bytes_per_elem: usize,
483 check: F,
484 ) -> Result<Vec<T>>
485 where
486 F: FnOnce(&ProtocolLimits, usize) -> Result<()>,
487 {
488 check(&self.protocol_limits(), count)?;
489 Ok(self.with_capacity_bounded(count, min_bytes_per_elem))
490 }
491}
492
493#[derive(Clone, Debug)]
494pub struct TtcReader<'a> {
495 bytes: &'a [u8],
496 pos: usize,
497 limits: ProtocolLimits,
498}
499
500impl BoundedReader for TtcReader<'_> {
501 fn remaining(&self) -> usize {
502 TtcReader::remaining(self)
503 }
504
505 fn protocol_limits(&self) -> ProtocolLimits {
506 self.limits
507 }
508}
509
510#[derive(Clone, Debug, PartialEq, Eq)]
514pub enum BorrowedBytes<'a> {
515 Null,
517 Slice(&'a [u8]),
519 Chunked(Vec<u8>),
522}
523
524impl<'a> TtcReader<'a> {
525 pub fn new(bytes: &'a [u8]) -> Self {
526 Self {
527 bytes,
528 pos: 0,
529 limits: ProtocolLimits::DEFAULT,
530 }
531 }
532
533 pub fn with_limits(bytes: &'a [u8], limits: ProtocolLimits) -> Result<Self> {
534 let limits = limits.validate()?;
535 limits.check_frame_bytes(bytes.len())?;
536 limits.check_response_bytes(bytes.len())?;
537 Ok(Self {
538 bytes,
539 pos: 0,
540 limits,
541 })
542 }
543
544 pub fn limits(&self) -> ProtocolLimits {
545 self.limits
546 }
547
548 pub fn remaining(&self) -> usize {
549 self.bytes.len().saturating_sub(self.pos)
550 }
551
552 pub fn position(&self) -> usize {
553 self.pos
554 }
555
556 pub fn remaining_slice(&self) -> &[u8] {
557 &self.bytes[self.pos.min(self.bytes.len())..]
558 }
559
560 pub fn peek_u8(&self) -> Result<u8> {
561 self.bytes
562 .get(self.pos)
563 .copied()
564 .ok_or(ProtocolError::TtcDecode("missing u8"))
565 }
566
567 pub fn read_u8(&mut self) -> Result<u8> {
568 let value = *self
569 .bytes
570 .get(self.pos)
571 .ok_or(ProtocolError::TtcDecode("missing u8"))?;
572 self.pos += 1;
573 Ok(value)
574 }
575
576 pub fn read_i8(&mut self) -> Result<i8> {
577 Ok(self.read_u8()? as i8)
578 }
579
580 pub fn read_u16be(&mut self) -> Result<u16> {
581 let bytes = self.read_raw(2)?;
582 Ok(u16::from_be_bytes(
583 bytes
584 .try_into()
585 .map_err(|_| ProtocolError::TtcDecode("invalid u16"))?,
586 ))
587 }
588
589 pub fn read_u16le(&mut self) -> Result<u16> {
590 let bytes = self.read_raw(2)?;
591 Ok(u16::from_le_bytes(
592 bytes
593 .try_into()
594 .map_err(|_| ProtocolError::TtcDecode("invalid u16"))?,
595 ))
596 }
597
598 pub fn read_u32be(&mut self) -> Result<u32> {
599 let bytes = self.read_raw(4)?;
600 Ok(u32::from_be_bytes(
601 bytes
602 .try_into()
603 .map_err(|_| ProtocolError::TtcDecode("invalid u32"))?,
604 ))
605 }
606
607 pub fn read_raw(&mut self, len: usize) -> Result<&'a [u8]> {
608 self.limits.check_response_bytes(len)?;
609 let end = self
610 .pos
611 .checked_add(len)
612 .ok_or(ProtocolError::TtcDecode("read offset overflow"))?;
613 let bytes = self
614 .bytes
615 .get(self.pos..end)
616 .ok_or(ProtocolError::TtcDecode("truncated TTC payload"))?;
617 self.pos = end;
618 Ok(bytes)
619 }
620
621 pub fn skip(&mut self, len: usize) -> Result<()> {
622 self.read_raw(len).map(|_| ())
623 }
624
625 pub fn read_ub2(&mut self) -> Result<u16> {
626 let len = self.read_u8()?;
627 match len {
628 0 => Ok(0),
629 1 => Ok(u16::from(self.read_u8()?)),
630 2 => self.read_u16be(),
631 _ => Err(ProtocolError::TtcDecode("invalid ub2 length")),
632 }
633 }
634
635 pub fn read_ub4(&mut self) -> Result<u32> {
636 let len = self.read_u8()?;
637 if len == 0 {
638 return Ok(0);
639 }
640 if len > 4 {
641 return Err(ProtocolError::TtcDecode("invalid ub4 length"));
642 }
643 let mut value = 0u32;
644 for byte in self.read_raw(usize::from(len))? {
645 value = (value << 8) | u32::from(*byte);
646 }
647 Ok(value)
648 }
649
650 pub fn read_sb4(&mut self) -> Result<i32> {
651 let len = self.read_u8()?;
652 let is_negative = len & 0x80 != 0;
653 let len = len & 0x7f;
654 if len == 0 {
655 return Ok(0);
656 }
657 if len > 4 {
658 return Err(ProtocolError::TtcDecode("invalid sb4 length"));
659 }
660 let mut value = 0u32;
667 for byte in self.read_raw(usize::from(len))? {
668 value = (value << 8) | u32::from(*byte);
669 }
670 let value = value as i32;
671 Ok(if is_negative {
672 value.wrapping_neg()
673 } else {
674 value
675 })
676 }
677
678 pub fn read_sb8(&mut self) -> Result<i64> {
679 let len = self.read_u8()?;
680 let is_negative = len & 0x80 != 0;
681 let len = len & 0x7f;
682 if len == 0 {
683 return Ok(0);
684 }
685 if len > 8 {
686 return Err(ProtocolError::TtcDecode("invalid sb8 length"));
687 }
688 let mut value = 0u64;
691 for byte in self.read_raw(usize::from(len))? {
692 value = (value << 8) | u64::from(*byte);
693 }
694 let value = value as i64;
695 Ok(if is_negative {
696 value.wrapping_neg()
697 } else {
698 value
699 })
700 }
701
702 pub fn read_ub8(&mut self) -> Result<u64> {
703 let len = self.read_u8()?;
704 if len == 0 {
705 return Ok(0);
706 }
707 if len > 8 {
708 return Err(ProtocolError::TtcDecode("invalid ub8 length"));
709 }
710 let mut value = 0u64;
711 for byte in self.read_raw(usize::from(len))? {
712 value = (value << 8) | u64::from(*byte);
713 }
714 Ok(value)
715 }
716
717 pub fn read_bytes_borrowed(&mut self) -> Result<BorrowedBytes<'a>> {
728 let len = self.read_u8()?;
729 if len == TNS_LONG_LENGTH_INDICATOR {
730 let mut out = Vec::new();
731 let mut chunks = 0usize;
732 let mut total = 0usize;
733 loop {
734 let chunk_len = self.read_ub4()?;
735 if chunk_len == 0 {
736 break;
737 }
738 chunks = chunks.checked_add(1).ok_or(ProtocolError::ResourceLimit {
739 limit: "lob_chunks",
740 observed: usize::MAX,
741 maximum: self.limits.max_lob_chunks,
742 })?;
743 self.limits.check_lob_chunks(chunks)?;
744 let chunk_len =
745 usize::try_from(chunk_len).map_err(|_| ProtocolError::InvalidPacketLength {
746 length: usize::MAX,
747 minimum: 0,
748 })?;
749 total = total
750 .checked_add(chunk_len)
751 .ok_or(ProtocolError::ResourceLimit {
752 limit: "response_bytes",
753 observed: usize::MAX,
754 maximum: self.limits.max_response_bytes,
755 })?;
756 self.limits.check_response_bytes(total)?;
757 let chunk = self.read_raw(chunk_len)?;
758 out.extend_from_slice(chunk);
759 }
760 Ok(BorrowedBytes::Chunked(out))
761 } else if len == 0 || len == TNS_NULL_LENGTH_INDICATOR {
762 Ok(BorrowedBytes::Null)
763 } else {
764 self.limits.check_response_bytes(usize::from(len))?;
765 Ok(BorrowedBytes::Slice(self.read_raw(usize::from(len))?))
766 }
767 }
768
769 pub fn skip_bytes_field(&mut self) -> Result<()> {
774 let len = self.read_u8()?;
775 if len == TNS_LONG_LENGTH_INDICATOR {
776 let mut chunks = 0usize;
777 let mut total = 0usize;
778 loop {
779 let chunk_len = self.read_ub4()?;
780 if chunk_len == 0 {
781 break;
782 }
783 chunks = chunks.checked_add(1).ok_or(ProtocolError::ResourceLimit {
784 limit: "lob_chunks",
785 observed: usize::MAX,
786 maximum: self.limits.max_lob_chunks,
787 })?;
788 self.limits.check_lob_chunks(chunks)?;
789 let chunk_len =
790 usize::try_from(chunk_len).map_err(|_| ProtocolError::InvalidPacketLength {
791 length: usize::MAX,
792 minimum: 0,
793 })?;
794 total = total
795 .checked_add(chunk_len)
796 .ok_or(ProtocolError::ResourceLimit {
797 limit: "response_bytes",
798 observed: usize::MAX,
799 maximum: self.limits.max_response_bytes,
800 })?;
801 self.limits.check_response_bytes(total)?;
802 self.skip(chunk_len)?;
803 }
804 Ok(())
805 } else if len == 0 || len == TNS_NULL_LENGTH_INDICATOR {
806 Ok(())
807 } else {
808 self.limits.check_response_bytes(usize::from(len))?;
809 self.skip(usize::from(len))
810 }
811 }
812
813 pub fn read_bytes(&mut self) -> Result<Option<Vec<u8>>> {
814 let len = self.read_u8()?;
815 if len == TNS_LONG_LENGTH_INDICATOR {
816 let mut out = Vec::new();
817 let mut chunks = 0usize;
818 let mut total = 0usize;
819 loop {
820 let chunk_len = self.read_ub4()?;
821 if chunk_len == 0 {
822 break;
823 }
824 chunks = chunks.checked_add(1).ok_or(ProtocolError::ResourceLimit {
825 limit: "lob_chunks",
826 observed: usize::MAX,
827 maximum: self.limits.max_lob_chunks,
828 })?;
829 self.limits.check_lob_chunks(chunks)?;
830 let chunk_len =
831 usize::try_from(chunk_len).map_err(|_| ProtocolError::InvalidPacketLength {
832 length: usize::MAX,
833 minimum: 0,
834 })?;
835 total = total
836 .checked_add(chunk_len)
837 .ok_or(ProtocolError::ResourceLimit {
838 limit: "response_bytes",
839 observed: usize::MAX,
840 maximum: self.limits.max_response_bytes,
841 })?;
842 self.limits.check_response_bytes(total)?;
843 let chunk = self.read_raw(chunk_len)?;
844 out.extend_from_slice(chunk);
845 }
846 Ok(Some(out))
847 } else if len == 0 || len == TNS_NULL_LENGTH_INDICATOR {
848 Ok(None)
849 } else {
850 self.limits.check_response_bytes(usize::from(len))?;
851 Ok(Some(self.read_raw(usize::from(len))?.to_vec()))
852 }
853 }
854
855 pub fn read_bytes_with_length(&mut self) -> Result<Option<Vec<u8>>> {
856 let len =
857 usize::try_from(self.read_ub4()?).map_err(|_| ProtocolError::InvalidPacketLength {
858 length: usize::MAX,
859 minimum: 0,
860 })?;
861 self.limits.check_response_bytes(len)?;
862 if len == 0 {
863 return Ok(None);
864 }
865 let value_start = self.pos;
866 match self.read_bytes() {
867 Ok(Some(bytes)) if bytes.len() == len => Ok(Some(bytes)),
868 Ok(_) | Err(_) => {
869 self.pos = value_start;
870 Ok(Some(self.read_raw(len)?.to_vec()))
871 }
872 }
873 }
874
875 pub fn read_string_with_length(&mut self) -> Result<Option<String>> {
876 let Some(bytes) = self.read_bytes_with_length()? else {
877 return Ok(None);
878 };
879 String::from_utf8(bytes)
880 .map(Some)
881 .map_err(|_| ProtocolError::TtcDecode("server sent non-UTF8 string"))
882 }
883
884 pub fn read_string(&mut self) -> Result<Option<String>> {
885 let Some(bytes) = self.read_bytes()? else {
886 return Ok(None);
887 };
888 String::from_utf8(bytes)
889 .map(Some)
890 .map_err(|_| ProtocolError::TtcDecode("server sent non-UTF8 string"))
891 }
892}
893
894pub fn encode_packet(
895 packet_type: u8,
896 packet_flags: u8,
897 data_flags: Option<u16>,
898 payload: &[u8],
899 width: PacketLengthWidth,
900) -> Result<Vec<u8>> {
901 let data_flags_len = usize::from(data_flags.is_some()) * 2;
902 let length = crate::packet::TNS_HEADER_LEN + data_flags_len + payload.len();
903 let mut out = Vec::with_capacity(length);
904 match width {
905 PacketLengthWidth::Legacy16 => {
906 let wire_length =
907 u16::try_from(length).map_err(|_| ProtocolError::PacketTooLarge { length })?;
908 out.extend_from_slice(&wire_length.to_be_bytes());
909 out.extend_from_slice(&0u16.to_be_bytes());
910 }
911 PacketLengthWidth::Large32 => {
912 let wire_length =
913 u32::try_from(length).map_err(|_| ProtocolError::PacketTooLarge { length })?;
914 out.extend_from_slice(&wire_length.to_be_bytes());
915 }
916 }
917 out.push(packet_type);
918 out.push(packet_flags);
919 out.extend_from_slice(&0u16.to_be_bytes());
920 if let Some(flags) = data_flags {
921 out.extend_from_slice(&flags.to_be_bytes());
922 }
923 out.extend_from_slice(payload);
924 Ok(out)
925}
926
927#[cfg(test)]
928mod tests {
929 use super::*;
930
931 fn assert_resource_limit(
932 result: Result<()>,
933 expected_limit: &'static str,
934 expected_observed: usize,
935 expected_maximum: usize,
936 ) {
937 assert!(
938 matches!(
939 result,
940 Err(ProtocolError::ResourceLimit {
941 limit,
942 observed,
943 maximum,
944 }) if limit == expected_limit
945 && observed == expected_observed
946 && maximum == expected_maximum
947 ),
948 "expected ResourceLimit {{ limit: {expected_limit}, observed: {expected_observed}, maximum: {expected_maximum} }}"
949 );
950 }
951
952 #[test]
953 fn protocol_limits_default_names_every_resource_family() {
954 let limits = ProtocolLimits::default()
955 .validate()
956 .expect("valid defaults");
957 assert_eq!(limits, ProtocolLimits::DEFAULT);
958 let names: Vec<&'static str> = limits
959 .named_limits()
960 .into_iter()
961 .map(|(name, value)| {
962 assert!(value > 0, "{name} must be non-zero");
963 name
964 })
965 .collect();
966 assert_eq!(
967 names,
968 vec![
969 "packet_bytes",
970 "frame_bytes",
971 "response_bytes",
972 "columns",
973 "binds",
974 "batch_rows",
975 "object_depth",
976 "object_elements",
977 "vector_dimensions",
978 "lob_chunks",
979 "length_prefixed_elements",
980 ]
981 );
982 }
983
984 #[test]
985 fn protocol_limits_check_helpers_return_typed_resource_limit_errors() {
986 let limits = ProtocolLimits {
987 max_packet_bytes: 8,
988 max_frame_bytes: 16,
989 max_response_bytes: 32,
990 max_columns: 2,
991 max_binds: 3,
992 max_batch_rows: 4,
993 max_object_depth: 5,
994 max_object_elements: 6,
995 max_vector_dimensions: 7,
996 max_lob_chunks: 8,
997 max_length_prefixed_elements: 9,
998 }
999 .validate()
1000 .expect("valid test limits");
1001
1002 limits.check_packet_bytes(8).expect("boundary accepted");
1003 limits.check_frame_bytes(16).expect("boundary accepted");
1004 limits.check_response_bytes(32).expect("boundary accepted");
1005 limits.check_columns(2).expect("boundary accepted");
1006 limits.check_binds(3).expect("boundary accepted");
1007 limits.check_batch_rows(4).expect("boundary accepted");
1008 limits.check_object_depth(5).expect("boundary accepted");
1009 limits.check_object_elements(6).expect("boundary accepted");
1010 limits
1011 .check_vector_dimensions(7)
1012 .expect("boundary accepted");
1013 limits.check_lob_chunks(8).expect("boundary accepted");
1014 limits
1015 .check_length_prefixed_elements(9)
1016 .expect("boundary accepted");
1017
1018 assert_resource_limit(limits.check_packet_bytes(9), "packet_bytes", 9, 8);
1019 assert_resource_limit(limits.check_frame_bytes(17), "frame_bytes", 17, 16);
1020 assert_resource_limit(limits.check_response_bytes(33), "response_bytes", 33, 32);
1021 assert_resource_limit(limits.check_columns(3), "columns", 3, 2);
1022 assert_resource_limit(limits.check_binds(4), "binds", 4, 3);
1023 assert_resource_limit(limits.check_batch_rows(5), "batch_rows", 5, 4);
1024 assert_resource_limit(limits.check_object_depth(6), "object_depth", 6, 5);
1025 assert_resource_limit(limits.check_object_elements(7), "object_elements", 7, 6);
1026 assert_resource_limit(limits.check_vector_dimensions(8), "vector_dimensions", 8, 7);
1027 assert_resource_limit(limits.check_lob_chunks(9), "lob_chunks", 9, 8);
1028 assert_resource_limit(
1029 limits.check_length_prefixed_elements(10),
1030 "length_prefixed_elements",
1031 10,
1032 9,
1033 );
1034 }
1035
1036 #[test]
1037 fn protocol_limits_validate_rejects_zero_and_inverted_byte_hierarchy() {
1038 let zero_columns = ProtocolLimits {
1039 max_columns: 0,
1040 ..ProtocolLimits::DEFAULT
1041 };
1042 assert!(matches!(
1043 zero_columns.validate(),
1044 Err(ProtocolError::ResourceLimit {
1045 limit: "columns",
1046 observed: 0,
1047 maximum: 1,
1048 })
1049 ));
1050
1051 let packet_larger_than_frame = ProtocolLimits {
1052 max_packet_bytes: 17,
1053 max_frame_bytes: 16,
1054 ..ProtocolLimits::DEFAULT
1055 };
1056 assert!(matches!(
1057 packet_larger_than_frame.validate(),
1058 Err(ProtocolError::ResourceLimit {
1059 limit: "packet_bytes",
1060 observed: 17,
1061 maximum: 16,
1062 })
1063 ));
1064
1065 let frame_larger_than_response = ProtocolLimits {
1066 max_packet_bytes: 16,
1067 max_frame_bytes: 33,
1068 max_response_bytes: 32,
1069 ..ProtocolLimits::DEFAULT
1070 };
1071 assert!(matches!(
1072 frame_larger_than_response.validate(),
1073 Err(ProtocolError::ResourceLimit {
1074 limit: "frame_bytes",
1075 observed: 33,
1076 maximum: 32,
1077 })
1078 ));
1079 }
1080
1081 #[test]
1082 fn ttc_reader_with_limits_rejects_oversized_raw_reads() {
1083 let limits = ProtocolLimits {
1084 max_packet_bytes: 4,
1085 max_frame_bytes: 4,
1086 max_response_bytes: 4,
1087 ..ProtocolLimits::DEFAULT
1088 };
1089 let mut reader = TtcReader::with_limits(&[1, 2, 3, 4], limits).expect("valid limits");
1090 assert!(matches!(
1091 reader.read_raw(5),
1092 Err(ProtocolError::ResourceLimit {
1093 limit: "response_bytes",
1094 observed: 5,
1095 maximum: 4,
1096 })
1097 ));
1098 }
1099
1100 #[test]
1101 fn ttc_reader_with_limits_rejects_too_many_lob_chunks() {
1102 let limits = ProtocolLimits {
1103 max_lob_chunks: 1,
1104 ..ProtocolLimits::DEFAULT
1105 };
1106 let bytes = [TNS_LONG_LENGTH_INDICATOR, 1, 1, b'a', 1, 1, b'b', 0];
1107 let mut reader = TtcReader::with_limits(&bytes, limits).expect("valid limits");
1108 assert!(matches!(
1109 reader.read_bytes(),
1110 Err(ProtocolError::ResourceLimit {
1111 limit: "lob_chunks",
1112 observed: 2,
1113 maximum: 1,
1114 })
1115 ));
1116 }
1117
1118 #[test]
1125 fn alloc_count_checked_errs_when_count_exceeds_remaining() {
1126 let bytes = [0u8; 4];
1130 let reader = TtcReader::new(&bytes);
1131 assert!(reader.alloc_count_checked(u32::MAX as usize, 8).is_err());
1132 assert!(reader.alloc_count_checked(usize::MAX, 8).is_err());
1134 }
1135
1136 #[test]
1137 fn alloc_count_checked_ok_when_count_fits() {
1138 let bytes = [0u8; 16];
1140 let reader = TtcReader::new(&bytes);
1141 assert_eq!(
1142 reader.alloc_count_checked(2, 8).expect("fits"),
1143 2,
1144 "a count whose bytes fit must pass through unchanged"
1145 );
1146 assert_eq!(reader.alloc_count_checked(0, 0).expect("zero"), 0);
1149 }
1150
1151 #[test]
1152 fn with_capacity_bounded_caps_preallocation_but_still_grows() {
1153 let bytes = [0u8; 8];
1155 let reader = TtcReader::new(&bytes);
1156 let v: Vec<u32> = reader.with_capacity_bounded(u32::MAX as usize, 4);
1157 assert_eq!(
1159 v.capacity(),
1160 2,
1161 "pre-allocation must be capped by remaining"
1162 );
1163 let mut v = v;
1166 for i in 0..100u32 {
1167 v.push(i);
1168 }
1169 assert_eq!(v.len(), 100);
1170 }
1171
1172 #[test]
1173 fn with_capacity_bounded_uses_full_count_when_buffer_is_large() {
1174 let bytes = [0u8; 400];
1177 let reader = TtcReader::new(&bytes);
1178 let v: Vec<u32> = reader.with_capacity_bounded(10, 4);
1179 assert_eq!(v.capacity(), 10);
1180 }
1181
1182 #[test]
1187 fn sb4_sb8_negate_overflow_does_not_panic() {
1188 let bytes = [0x84u8, 0x80, 0x00, 0x00, 0x00];
1190 let mut reader = TtcReader::new(&bytes);
1191 assert_eq!(reader.read_sb4().expect("sb4 must not panic"), i32::MIN);
1192
1193 let bytes8 = [0x88u8, 0x80, 0, 0, 0, 0, 0, 0, 0];
1195 let mut reader8 = TtcReader::new(&bytes8);
1196 assert_eq!(reader8.read_sb8().expect("sb8 must not panic"), i64::MIN);
1197 }
1198
1199 #[test]
1202 fn sb4_decodes_representative_values() {
1203 let cases: [(&[u8], i32); 4] = [
1205 (&[0x00], 0),
1206 (&[0x01, 0x2a], 42),
1207 (&[0x81, 0x2a], -42),
1208 (&[0x02, 0x01, 0x00], 256),
1209 ];
1210 for (bytes, expected) in cases {
1211 let mut reader = TtcReader::new(bytes);
1212 assert_eq!(
1213 reader.read_sb4().expect("sb4 decode"),
1214 expected,
1215 "{bytes:?}"
1216 );
1217 }
1218 }
1219
1220 #[test]
1221 fn ub4_round_trips_representative_values() {
1222 for value in [0, 1, 255, 256, 65_535, 65_536, u32::MAX] {
1223 let mut writer = TtcWriter::new();
1224 writer.write_ub4(value);
1225 let bytes = writer.into_bytes();
1226 let mut reader = TtcReader::new(&bytes);
1227 assert_eq!(reader.read_ub4().expect("ub4 should decode"), value);
1228 assert_eq!(reader.remaining(), 0);
1229 }
1230 }
1231
1232 #[test]
1239 fn read_bytes_borrowed_borrows_short_values_and_owns_chunked() {
1240 let short = [0x03u8, b'a', b'b', b'c'];
1242 let mut reader = TtcReader::new(&short);
1243 let borrowed = reader.read_bytes_borrowed().expect("short decode");
1244 assert!(matches!(borrowed, BorrowedBytes::Slice(slice) if slice == b"abc"));
1245 assert_eq!(reader.remaining(), 0);
1246
1247 let null = [TNS_NULL_LENGTH_INDICATOR];
1249 let mut reader = TtcReader::new(&null);
1250 assert!(matches!(
1251 reader.read_bytes_borrowed().expect("null decode"),
1252 BorrowedBytes::Null
1253 ));
1254
1255 let zero = [0x00u8];
1257 let mut reader = TtcReader::new(&zero);
1258 assert!(matches!(
1259 reader.read_bytes_borrowed().expect("zero decode"),
1260 BorrowedBytes::Null
1261 ));
1262
1263 let mut writer = TtcWriter::new();
1265 writer
1266 .write_bytes_with_length(&vec![0x5au8; 600]) .expect("chunked encode");
1268 let long = writer.into_bytes();
1269 let mut reader = TtcReader::new(&long);
1270 let expected = vec![0x5au8; 600];
1271 let borrowed = reader.read_bytes_borrowed().expect("chunked decode");
1272 assert!(matches!(&borrowed, BorrowedBytes::Chunked(bytes) if bytes == &expected));
1273 assert_eq!(reader.remaining(), 0);
1274 }
1275
1276 #[test]
1277 fn bytes_with_length_accepts_nested_ttc_bytes() {
1278 let mut writer = TtcWriter::new();
1279 writer
1280 .write_bytes_with_two_lengths(Some(b"abc"))
1281 .expect("bytes should encode");
1282 let bytes = writer.into_bytes();
1283 let mut reader = TtcReader::new(&bytes);
1284 assert_eq!(
1285 reader
1286 .read_bytes_with_length()
1287 .expect("bytes should decode"),
1288 Some(b"abc".to_vec())
1289 );
1290 assert_eq!(reader.remaining(), 0);
1291 }
1292
1293 #[test]
1294 fn bytes_with_length_accepts_direct_payload_bytes() {
1295 let bytes = [1, 3, b'a', b'b', b'c'];
1296 let mut reader = TtcReader::new(&bytes);
1297 assert_eq!(
1298 reader
1299 .read_bytes_with_length()
1300 .expect("bytes should decode"),
1301 Some(b"abc".to_vec())
1302 );
1303 assert_eq!(reader.remaining(), 0);
1304 }
1305
1306 #[test]
1307 fn data_packet_uses_four_byte_length_when_negotiated() {
1308 let packet = encode_packet(
1309 6,
1310 0,
1311 Some(0),
1312 &[0x03, 0x93, 0x01],
1313 PacketLengthWidth::Large32,
1314 )
1315 .expect("packet should encode");
1316 assert_eq!(&packet[..10], &[0, 0, 0, 13, 6, 0, 0, 0, 0, 0]);
1317 }
1318
1319 #[test]
1326 fn packet_length_framing_switches_between_legacy16_and_large32() {
1327 let payload = [0x03, 0x93, 0x01];
1328 let legacy = encode_packet(6, 0, Some(0), &payload, PacketLengthWidth::Legacy16)
1329 .expect("legacy packet");
1330 let large = encode_packet(6, 0, Some(0), &payload, PacketLengthWidth::Large32)
1331 .expect("large packet");
1332
1333 assert_eq!(
1335 &legacy[..4],
1336 &[0, 13, 0, 0],
1337 "legacy: u16 length then u16 pad"
1338 );
1339 assert_eq!(&large[..4], &[0, 0, 0, 13], "large: u32 length");
1340 assert_ne!(legacy, large, "the length-width gate changes the wire");
1341 }
1342
1343 #[test]
1350 fn function_and_piggyback_headers_gate_pipeline_token_on_23_1_ext_1() {
1351 let lo = crate::thin::TNS_CCAP_FIELD_VERSION_23_1_EXT_1 - 1;
1352 let hi = crate::thin::TNS_CCAP_FIELD_VERSION_23_1_EXT_1;
1353
1354 let function_header = |fv| {
1355 let mut w = TtcWriter::new();
1356 w.write_function_header(3, 5, fv);
1357 w.into_bytes()
1358 };
1359 let f_lo = function_header(lo);
1360 let f_hi = function_header(hi);
1361 assert_eq!(f_hi.len(), f_lo.len() + 1, "function header gains ub8(0)");
1362 assert_eq!(&f_hi[..f_lo.len()], f_lo.as_slice(), "prefix unchanged");
1363 assert_eq!(f_hi[f_lo.len()], 0, "the token is ub8(0)");
1364
1365 let piggyback_header = |fv| {
1366 let mut w = TtcWriter::new();
1367 w.write_piggyback_header(3, 5, fv);
1368 w.into_bytes()
1369 };
1370 let p_lo = piggyback_header(lo);
1371 let p_hi = piggyback_header(hi);
1372 assert_eq!(p_hi.len(), p_lo.len() + 1, "piggyback header gains ub8(0)");
1373 assert_eq!(&p_hi[..p_lo.len()], p_lo.as_slice(), "prefix unchanged");
1374 assert_eq!(p_hi[p_lo.len()], 0, "the token is ub8(0)");
1375 }
1376}