1use crate::{Error, Limits, Method};
11
12const HTTPS_SCHEME: &[u8] = b"https";
13const REQUEST_MODE: u64 = 0;
14const RESPONSE_MODE: u64 = 1;
15const ENCODING_CAPACITY_ALLOWANCE: usize = 128;
17const FORBIDDEN_HEADERS: &[&[u8]] = &[
18 b"connection",
19 b"expect",
20 b"host",
21 b"keep-alive",
22 b"proxy-authenticate",
23 b"proxy-authentication-info",
24 b"proxy-authorization",
25 b"proxy-connection",
26 b"te",
27 b"trailer",
28 b"transfer-encoding",
29 b"upgrade",
30];
31
32#[derive(Clone, Debug, Eq, PartialEq)]
34pub struct HeaderField {
35 pub name: Vec<u8>,
37 pub value: Vec<u8>,
39}
40
41#[derive(Clone, Debug, Eq, PartialEq)]
43pub struct Request {
44 pub method: Method,
46 pub authority: Vec<u8>,
48 pub path: Vec<u8>,
50 pub headers: Vec<HeaderField>,
52 pub body: Vec<u8>,
54}
55
56#[derive(Clone, Debug, Eq, PartialEq)]
58pub struct Response {
59 pub status: u16,
61 pub headers: Vec<HeaderField>,
63 pub body: Vec<u8>,
65}
66
67pub(crate) fn encode_request(request: &Request, limits: Limits) -> Result<Vec<u8>, Error> {
68 encode_request_with_body(request, &request.body, limits)
69}
70
71pub(crate) fn encode_request_with_body(
74 request: &Request,
75 wire_body: &[u8],
76 limits: Limits,
77) -> Result<Vec<u8>, Error> {
78 validate_request(request, limits)?;
79 if wire_body.len() > limits.max_body_len {
80 return Err(Error::LimitExceeded);
81 }
82 let fields = encode_fields(&request.headers)?;
83 let mut output = Vec::with_capacity(
84 wire_body.len()
85 + fields.len()
86 + request.authority.len()
87 + request.path.len()
88 + ENCODING_CAPACITY_ALLOWANCE,
89 );
90 write_varint(&mut output, REQUEST_MODE)?;
91 write_vector(&mut output, request.method.as_bytes())?;
92 write_vector(&mut output, HTTPS_SCHEME)?;
93 write_vector(&mut output, &request.authority)?;
94 write_vector(&mut output, &request.path)?;
95 write_vector(&mut output, &fields)?;
96 write_vector(&mut output, wire_body)?;
97 write_vector(&mut output, &[])?;
98 Ok(output)
99}
100
101pub(crate) fn decode_request(input: &[u8], limits: Limits) -> Result<Request, Error> {
102 decode_request_inner(input, limits, false)
103}
104
105pub(crate) fn decode_coded_request(input: &[u8], limits: Limits) -> Result<Request, Error> {
106 decode_request_inner(input, limits, true)
107}
108
109fn decode_request_inner(input: &[u8], limits: Limits, coded_body: bool) -> Result<Request, Error> {
110 validate_encoded_length(input, limits)?;
111 let mut reader = SliceReader::new(input);
112 if reader.read_varint()? != REQUEST_MODE {
113 return Err(Error::MalformedEnvelope);
114 }
115 let method = Method::from_bytes(reader.read_vector()?)?;
116 if reader.read_vector()? != HTTPS_SCHEME {
117 return Err(Error::MalformedEnvelope);
118 }
119 let authority = reader.read_vector()?;
120 let path = reader.read_vector()?;
121 validate_target(method, authority, path, limits).map_err(decode_validation_error)?;
122 let headers = decode_fields(reader.read_vector()?, limits).map_err(decode_validation_error)?;
123 let body = reader.read_vector()?;
124 if body.len() > limits.max_body_len {
125 return Err(Error::LimitExceeded);
126 }
127 if !reader.read_vector()?.is_empty() || !reader.is_finished() {
128 return Err(Error::MalformedEnvelope);
129 }
130 let request = Request {
131 method,
132 authority: authority.to_vec(),
133 path: path.to_vec(),
134 headers,
135 body: body.to_vec(),
136 };
137 if !coded_body {
138 validate_decoded_request_body(&request)?;
139 }
140 Ok(request)
141}
142
143pub(crate) fn validate_decoded_request_body(request: &Request) -> Result<(), Error> {
144 validate_content_length(
145 &request.headers,
146 request.body.len(),
147 ContentLengthRule::Exact,
148 )
149 .map_err(decode_validation_error)
150}
151
152pub(crate) fn encode_response(
153 response: &Response,
154 method: Method,
155 limits: Limits,
156) -> Result<Vec<u8>, Error> {
157 encode_response_with_body(response, &response.body, method, limits)
158}
159
160pub(crate) fn encode_response_with_body(
161 response: &Response,
162 wire_body: &[u8],
163 method: Method,
164 limits: Limits,
165) -> Result<Vec<u8>, Error> {
166 validate_response(response, method, limits)?;
167 if wire_body.len() > limits.max_body_len {
168 return Err(Error::LimitExceeded);
169 }
170 let fields = encode_fields(&response.headers)?;
171 let mut output =
172 Vec::with_capacity(wire_body.len() + fields.len() + ENCODING_CAPACITY_ALLOWANCE);
173 write_varint(&mut output, RESPONSE_MODE)?;
174 write_varint(&mut output, u64::from(response.status))?;
175 write_vector(&mut output, &fields)?;
176 write_vector(&mut output, wire_body)?;
177 write_vector(&mut output, &[])?;
178 Ok(output)
179}
180
181pub(crate) fn decode_response(
182 input: &[u8],
183 method: Method,
184 limits: Limits,
185) -> Result<Response, Error> {
186 decode_response_inner(input, method, limits, false)
187}
188
189pub(crate) fn decode_coded_response(
190 input: &[u8],
191 method: Method,
192 limits: Limits,
193) -> Result<Response, Error> {
194 decode_response_inner(input, method, limits, true)
195}
196
197fn decode_response_inner(
198 input: &[u8],
199 method: Method,
200 limits: Limits,
201 coded_body: bool,
202) -> Result<Response, Error> {
203 validate_encoded_length(input, limits)?;
204 let mut reader = SliceReader::new(input);
205 if reader.read_varint()? != RESPONSE_MODE {
206 return Err(Error::MalformedEnvelope);
207 }
208 let status = u16::try_from(reader.read_varint()?).map_err(|_| Error::MalformedEnvelope)?;
209 if !(200..=599).contains(&status) {
210 return Err(Error::MalformedEnvelope);
211 }
212 let headers = decode_fields(reader.read_vector()?, limits).map_err(decode_validation_error)?;
213 let body = reader.read_vector()?;
214 if body.len() > limits.max_body_len {
215 return Err(Error::LimitExceeded);
216 }
217 if !reader.read_vector()?.is_empty() || !reader.is_finished() {
218 return Err(Error::MalformedEnvelope);
219 }
220 let response = Response {
221 status,
222 headers,
223 body: body.to_vec(),
224 };
225 if !coded_body {
226 validate_decoded_response_body(&response, method)?;
227 }
228 Ok(response)
229}
230
231pub(crate) fn validate_decoded_response_body(
232 response: &Response,
233 method: Method,
234) -> Result<(), Error> {
235 validate_content_length(
236 &response.headers,
237 response.body.len(),
238 response_content_length_rule(method, response.status),
239 )
240 .map_err(decode_validation_error)
241}
242
243const fn decode_validation_error(error: Error) -> Error {
244 match error {
245 Error::InvalidConfiguration => Error::MalformedEnvelope,
246 other => other,
247 }
248}
249
250fn encode_fields(headers: &[HeaderField]) -> Result<Vec<u8>, Error> {
251 let mut output = Vec::new();
252 for field in headers {
253 write_vector(&mut output, &field.name)?;
254 write_vector(&mut output, &field.value)?;
255 }
256 Ok(output)
257}
258
259fn decode_fields(input: &[u8], limits: Limits) -> Result<Vec<HeaderField>, Error> {
260 let mut reader = SliceReader::new(input);
261 let mut headers: Vec<HeaderField> = Vec::new();
262 let mut header_bytes = 0_usize;
263 while !reader.is_finished() {
264 if headers.len() >= limits.max_header_count {
265 return Err(Error::LimitExceeded);
266 }
267 let name = reader.read_vector()?;
268 let value = reader.read_vector()?;
269 header_bytes = header_bytes
270 .checked_add(name.len())
271 .and_then(|length| length.checked_add(value.len()))
272 .ok_or(Error::LimitExceeded)?;
273 if header_bytes > limits.max_header_bytes {
274 return Err(Error::LimitExceeded);
275 }
276 validate_header_parts(name, value)?;
277 headers.push(HeaderField {
278 name: name.to_vec(),
279 value: value.to_vec(),
280 });
281 }
282 Ok(headers)
283}
284
285fn validate_encoded_length(input: &[u8], limits: Limits) -> Result<(), Error> {
286 if input.len() > limits.max_encoded_message_len() {
287 return Err(Error::LimitExceeded);
288 }
289 Ok(())
290}
291
292fn validate_request(request: &Request, limits: Limits) -> Result<(), Error> {
293 validate_target(request.method, &request.authority, &request.path, limits)?;
294 validate_payload(&request.headers, &request.body, limits)?;
295 validate_content_length(
296 &request.headers,
297 request.body.len(),
298 ContentLengthRule::Exact,
299 )
300}
301
302fn validate_response(response: &Response, method: Method, limits: Limits) -> Result<(), Error> {
303 if !(200..=599).contains(&response.status) {
304 return Err(Error::InvalidConfiguration);
305 }
306 validate_payload(&response.headers, &response.body, limits)?;
307 validate_content_length(
308 &response.headers,
309 response.body.len(),
310 response_content_length_rule(method, response.status),
311 )
312}
313
314fn validate_target(
315 method: Method,
316 authority: &[u8],
317 path: &[u8],
318 limits: Limits,
319) -> Result<(), Error> {
320 let target_len = authority
321 .len()
322 .checked_add(path.len())
323 .ok_or(Error::LimitExceeded)?;
324 if target_len > limits.max_target_len {
325 return Err(Error::LimitExceeded);
326 }
327 if !valid_authority(authority) || !valid_request_target(method, path) {
328 return Err(Error::InvalidConfiguration);
329 }
330 Ok(())
331}
332
333fn valid_authority(authority: &[u8]) -> bool {
334 if authority.is_empty() || !authority.iter().all(u8::is_ascii_graphic) {
335 return false;
336 }
337 if authority[0] == b'[' {
338 return valid_ip_literal_authority(authority);
339 }
340
341 let (host, port) = authority
342 .iter()
343 .rposition(|byte| *byte == b':')
344 .map_or((authority, None), |separator| {
345 (&authority[..separator], Some(&authority[separator + 1..]))
346 });
347 if host.contains(&b':') || !valid_reg_name(host) || !port.is_none_or(valid_port) {
348 return false;
349 }
350 let numeric_ipv4_candidate = host.split(|byte| *byte == b'.').count() == 4
351 && host
352 .iter()
353 .all(|byte| byte.is_ascii_digit() || *byte == b'.');
354 !numeric_ipv4_candidate
355 || std::str::from_utf8(host)
356 .ok()
357 .and_then(|value| value.parse::<std::net::Ipv4Addr>().ok())
358 .is_some()
359}
360
361fn valid_ip_literal_authority(authority: &[u8]) -> bool {
362 let Some(close) = authority.iter().position(|byte| *byte == b']') else {
363 return false;
364 };
365 let literal = &authority[1..close];
366 let suffix = &authority[close + 1..];
367 let valid_suffix = suffix.is_empty() || suffix.strip_prefix(b":").is_some_and(valid_port);
368 if literal.is_empty() || !valid_suffix {
369 return false;
370 }
371 let Ok(value) = std::str::from_utf8(literal) else {
372 return false;
373 };
374 value.parse::<std::net::Ipv6Addr>().is_ok() || valid_ipv_future(literal)
375}
376
377fn valid_ipv_future(value: &[u8]) -> bool {
378 let Some(version_and_address) = value
379 .strip_prefix(b"v")
380 .or_else(|| value.strip_prefix(b"V"))
381 else {
382 return false;
383 };
384 let Some(separator) = version_and_address.iter().position(|byte| *byte == b'.') else {
385 return false;
386 };
387 let version = &version_and_address[..separator];
388 let address = &version_and_address[separator + 1..];
389 !version.is_empty()
390 && version.iter().all(u8::is_ascii_hexdigit)
391 && !address.is_empty()
392 && address
393 .iter()
394 .copied()
395 .all(|byte| is_unreserved(byte) || is_sub_delim(byte) || byte == b':')
396}
397
398fn valid_reg_name(value: &[u8]) -> bool {
399 if value.is_empty() {
400 return false;
401 }
402 let mut position = 0;
403 while position < value.len() {
404 let byte = value[position];
405 if is_unreserved(byte) || is_sub_delim(byte) {
406 position += 1;
407 } else if byte == b'%'
408 && value
409 .get(position + 1..position + 3)
410 .is_some_and(|encoded| encoded.iter().all(u8::is_ascii_hexdigit))
411 {
412 position += 3;
413 } else {
414 return false;
415 }
416 }
417 true
418}
419
420fn valid_port(value: &[u8]) -> bool {
421 if value.is_empty() || !value.iter().all(u8::is_ascii_digit) {
422 return false;
423 }
424 let significant = value
425 .iter()
426 .position(|byte| *byte != b'0')
427 .map_or(&[][..], |position| &value[position..]);
428 significant.is_empty()
429 || (significant.len() <= 5
430 && std::str::from_utf8(significant)
431 .ok()
432 .and_then(|port| port.parse::<u16>().ok())
433 .is_some())
434}
435
436const fn is_unreserved(byte: u8) -> bool {
437 byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'.' | b'_' | b'~')
438}
439
440const fn is_sub_delim(byte: u8) -> bool {
441 matches!(
442 byte,
443 b'!' | b'$' | b'&' | b'\'' | b'(' | b')' | b'*' | b'+' | b',' | b';' | b'='
444 )
445}
446
447fn validate_payload(headers: &[HeaderField], body: &[u8], limits: Limits) -> Result<(), Error> {
448 if headers.len() > limits.max_header_count || body.len() > limits.max_body_len {
449 return Err(Error::LimitExceeded);
450 }
451 let mut header_bytes = 0_usize;
452 for field in headers {
453 validate_header_parts(&field.name, &field.value)?;
454 header_bytes = header_bytes
455 .checked_add(field.name.len())
456 .and_then(|length| length.checked_add(field.value.len()))
457 .ok_or(Error::LimitExceeded)?;
458 }
459 if header_bytes > limits.max_header_bytes {
460 return Err(Error::LimitExceeded);
461 }
462 Ok(())
463}
464
465#[derive(Clone, Copy)]
466enum ContentLengthRule {
467 Exact,
468 Metadata,
469 Forbidden,
470}
471
472fn response_content_length_rule(method: Method, status: u16) -> ContentLengthRule {
473 if status == 204 {
474 ContentLengthRule::Forbidden
475 } else if method == Method::Head || status == 304 {
476 ContentLengthRule::Metadata
477 } else {
478 ContentLengthRule::Exact
479 }
480}
481
482fn validate_content_length(
483 headers: &[HeaderField],
484 body_len: usize,
485 rule: ContentLengthRule,
486) -> Result<(), Error> {
487 let mut values = headers
488 .iter()
489 .filter(|field| field.name == b"content-length")
490 .map(|field| field.value.as_slice());
491 let Some(value) = values.next() else {
492 return Ok(());
493 };
494 if values.next().is_some() || value.is_empty() || !value.iter().all(u8::is_ascii_digit) {
495 return Err(Error::InvalidConfiguration);
496 }
497 match rule {
498 ContentLengthRule::Forbidden => Err(Error::InvalidConfiguration),
499 ContentLengthRule::Metadata => Ok(()),
500 ContentLengthRule::Exact => {
501 let significant = value
502 .iter()
503 .position(|byte| *byte != b'0')
504 .map_or(&[][..], |position| &value[position..]);
505 let expected = body_len.to_string();
506 let matches = if significant.is_empty() {
507 body_len == 0
508 } else {
509 significant == expected.as_bytes()
510 };
511 if matches {
512 Ok(())
513 } else {
514 Err(Error::InvalidConfiguration)
515 }
516 }
517 }
518}
519
520fn validate_header_parts(name: &[u8], value: &[u8]) -> Result<(), Error> {
521 if name.is_empty()
522 || !name.iter().copied().all(is_lower_tchar)
523 || FORBIDDEN_HEADERS.contains(&name)
524 || !value
525 .iter()
526 .all(|byte| *byte == b'\t' || (b' '..=b'~').contains(byte))
527 || value.first().is_some_and(|byte| is_ows(*byte))
528 || value.last().is_some_and(|byte| is_ows(*byte))
529 {
530 return Err(Error::InvalidConfiguration);
531 }
532 Ok(())
533}
534
535fn valid_request_target(method: Method, path: &[u8]) -> bool {
536 if path == b"*" {
537 return method == Method::Options;
538 }
539 if !path.starts_with(b"/")
540 || path.contains(&b'#')
541 || path.contains(&b'\\')
542 || !path.iter().all(u8::is_ascii_graphic)
543 || !valid_percent_encoding(path)
544 {
545 return false;
546 }
547 let path_only = path.split(|byte| *byte == b'?').next().unwrap_or_default();
548 let Some(decoded_path) = decode_path(path_only) else {
549 return false;
550 };
551 std::str::from_utf8(&decoded_path).is_ok()
552 && !decoded_path
553 .iter()
554 .any(|byte| byte.is_ascii_control() || *byte == b'\\')
555 && !decoded_path.split(|byte| *byte == b'/').any(is_dot_segment)
556}
557
558fn decode_path(path: &[u8]) -> Option<Vec<u8>> {
559 let mut decoded = Vec::with_capacity(path.len());
560 let mut position = 0;
561 while position < path.len() {
562 if path[position] == b'%' {
563 let high = hex_value(*path.get(position + 1)?)?;
564 let low = hex_value(*path.get(position + 2)?)?;
565 let byte = high.checked_mul(16)?.checked_add(low)?;
566 if byte == b'/' {
567 return None;
568 }
569 decoded.push(byte);
570 position += 3;
571 } else {
572 decoded.push(path[position]);
573 position += 1;
574 }
575 }
576 Some(decoded)
577}
578
579const fn hex_value(byte: u8) -> Option<u8> {
580 match byte {
581 b'0'..=b'9' => Some(byte - b'0'),
582 b'a'..=b'f' => Some(byte - b'a' + 10),
583 b'A'..=b'F' => Some(byte - b'A' + 10),
584 _ => None,
585 }
586}
587
588fn valid_percent_encoding(value: &[u8]) -> bool {
589 let mut position = 0;
590 while position < value.len() {
591 if value[position] == b'%' {
592 let Some(encoded) = value.get(position + 1..position + 3) else {
593 return false;
594 };
595 if !encoded.iter().all(u8::is_ascii_hexdigit) {
596 return false;
597 }
598 position += 3;
599 } else {
600 position += 1;
601 }
602 }
603 true
604}
605
606fn is_dot_segment(segment: &[u8]) -> bool {
607 segment == b"." || segment == b".."
608}
609
610const fn is_ows(byte: u8) -> bool {
611 matches!(byte, b' ' | b'\t')
612}
613
614const fn is_lower_tchar(byte: u8) -> bool {
615 byte.is_ascii_lowercase()
616 || byte.is_ascii_digit()
617 || matches!(
618 byte,
619 b'!' | b'#'
620 | b'$'
621 | b'%'
622 | b'&'
623 | b'\''
624 | b'*'
625 | b'+'
626 | b'-'
627 | b'.'
628 | b'^'
629 | b'_'
630 | b'`'
631 | b'|'
632 | b'~'
633 )
634}
635
636fn write_vector(output: &mut Vec<u8>, value: &[u8]) -> Result<(), Error> {
637 let length = u64::try_from(value.len()).map_err(|_| Error::LimitExceeded)?;
638 write_varint(output, length)?;
639 output.extend_from_slice(value);
640 Ok(())
641}
642
643fn write_varint(output: &mut Vec<u8>, value: u64) -> Result<(), Error> {
644 match value {
645 0..=0x3f => output.push(u8::try_from(value).map_err(|_| Error::LimitExceeded)?),
646 0x40..=0x3fff => {
647 let encoded = u16::try_from(value).map_err(|_| Error::LimitExceeded)? | 0x4000;
648 output.extend_from_slice(&encoded.to_be_bytes());
649 }
650 0x4000..=0x3fff_ffff => {
651 let encoded = u32::try_from(value).map_err(|_| Error::LimitExceeded)? | 0x8000_0000;
652 output.extend_from_slice(&encoded.to_be_bytes());
653 }
654 0x4000_0000..=0x3fff_ffff_ffff_ffff => {
655 output.extend_from_slice(&(value | 0xc000_0000_0000_0000).to_be_bytes());
656 }
657 _ => return Err(Error::LimitExceeded),
658 }
659 Ok(())
660}
661
662struct SliceReader<'a> {
663 input: &'a [u8],
664 position: usize,
665}
666
667impl<'a> SliceReader<'a> {
668 const fn new(input: &'a [u8]) -> Self {
669 Self { input, position: 0 }
670 }
671
672 fn read_varint(&mut self) -> Result<u64, Error> {
673 let first = *self
674 .input
675 .get(self.position)
676 .ok_or(Error::MalformedEnvelope)?;
677 let length = 1_usize << (first >> 6);
678 let end = self
679 .position
680 .checked_add(length)
681 .ok_or(Error::MalformedEnvelope)?;
682 let encoded = self
683 .input
684 .get(self.position..end)
685 .ok_or(Error::MalformedEnvelope)?;
686 let mut value = u64::from(first & 0x3f);
687 for byte in &encoded[1..] {
688 value = (value << 8) | u64::from(*byte);
689 }
690 if varint_length(value) != length {
691 return Err(Error::MalformedEnvelope);
692 }
693 self.position = end;
694 Ok(value)
695 }
696
697 fn read_vector(&mut self) -> Result<&'a [u8], Error> {
698 let length = usize::try_from(self.read_varint()?).map_err(|_| Error::MalformedEnvelope)?;
699 let end = self
700 .position
701 .checked_add(length)
702 .ok_or(Error::MalformedEnvelope)?;
703 let value = self
704 .input
705 .get(self.position..end)
706 .ok_or(Error::MalformedEnvelope)?;
707 self.position = end;
708 Ok(value)
709 }
710
711 const fn is_finished(&self) -> bool {
712 self.position == self.input.len()
713 }
714}
715
716const fn varint_length(value: u64) -> usize {
717 match value {
718 0..=0x3f => 1,
719 0x40..=0x3fff => 2,
720 0x4000..=0x3fff_ffff => 4,
721 _ => 8,
722 }
723}
724
725#[cfg(test)]
726mod tests {
727 use super::{SliceReader, decode_fields, decode_request, encode_request, write_varint};
728 use crate::{Error, HeaderField, Limits, Method, Request};
729
730 #[test]
731 fn field_decoder_stops_at_the_configured_count() {
732 let limits = Limits {
733 max_header_count: 2,
734 ..Limits::default()
735 };
736 let encoded = [1, b'a', 0, 1, b'b', 0, 1, b'c', 0];
737 assert_eq!(decode_fields(&encoded, limits), Err(Error::LimitExceeded));
738 }
739
740 #[test]
741 fn varint_round_trips_boundaries_and_rejects_non_minimal_values() -> Result<(), Error> {
742 let cases: &[(u64, &[u8])] = &[
743 (0, &[0x00]),
744 (63, &[0x3f]),
745 (64, &[0x40, 0x40]),
746 (16_383, &[0x7f, 0xff]),
747 (16_384, &[0x80, 0x00, 0x40, 0x00]),
748 (0x3fff_ffff, &[0xbf, 0xff, 0xff, 0xff]),
749 (
750 0x4000_0000,
751 &[0xc0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00],
752 ),
753 ];
754 for (value, expected) in cases {
755 let mut encoded = Vec::new();
756 write_varint(&mut encoded, *value)?;
757 assert_eq!(&encoded, expected);
758 let mut reader = SliceReader::new(expected);
759 assert_eq!(reader.read_varint()?, *value);
760 assert!(reader.is_finished());
761 }
762 let mut non_minimal = SliceReader::new(&[0x40, 0x01]);
763 assert_eq!(non_minimal.read_varint(), Err(Error::MalformedEnvelope));
764 Ok(())
765 }
766
767 #[test]
768 fn request_decoder_rechecks_authenticated_content_length() -> Result<(), Error> {
769 let request = Request {
770 method: Method::Post,
771 authority: b"api.example.test".to_vec(),
772 path: b"/items".to_vec(),
773 headers: vec![HeaderField {
774 name: b"content-length".to_vec(),
775 value: b"4".to_vec(),
776 }],
777 body: b"body".to_vec(),
778 };
779 let mut encoded = encode_request(&request, Limits::default())?;
780 let name_offset = encoded
781 .windows(b"content-length".len())
782 .position(|window| window == b"content-length")
783 .ok_or(Error::MalformedEnvelope)?;
784 let value_offset = name_offset + b"content-length".len() + 1;
785 encoded[value_offset] = b'5';
786 assert_eq!(
787 decode_request(&encoded, Limits::default()).err(),
788 Some(Error::MalformedEnvelope)
789 );
790 Ok(())
791 }
792
793 #[test]
794 fn request_decoder_rechecks_authenticated_authority_syntax() -> Result<(), Error> {
795 let request = Request {
796 method: Method::Get,
797 authority: b"api.example".to_vec(),
798 path: b"/items".to_vec(),
799 headers: Vec::new(),
800 body: Vec::new(),
801 };
802 let mut encoded = encode_request(&request, Limits::default())?;
803 let authority_offset = encoded
804 .windows(b"api.example".len())
805 .position(|window| window == b"api.example")
806 .ok_or(Error::MalformedEnvelope)?;
807 encoded[authority_offset] = b'[';
808 assert_eq!(
809 decode_request(&encoded, Limits::default()).err(),
810 Some(Error::MalformedEnvelope)
811 );
812 Ok(())
813 }
814}