1use flate2::{Compress, Compression, Decompress, FlushCompress, FlushDecompress};
24use std::io;
25use std::pin::Pin;
26use std::task::{Context, Poll};
27use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
28
29pub const EXTENSION: &str = "permessage-deflate";
31
32pub const CLIENT_OFFER: &str = "permessage-deflate; client_max_window_bits";
35
36const TAIL: [u8; 4] = [0x00, 0x00, 0xff, 0xff];
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub struct DeflateParams {
42 pub server_no_context_takeover: bool,
44 pub client_no_context_takeover: bool,
46 pub server_max_window_bits: u8,
48 pub client_max_window_bits: u8,
50}
51
52impl Default for DeflateParams {
53 fn default() -> Self {
54 Self {
55 server_no_context_takeover: false,
56 client_no_context_takeover: false,
57 server_max_window_bits: 15,
58 client_max_window_bits: 15,
59 }
60 }
61}
62
63impl DeflateParams {
64 pub fn header_value(&self) -> String {
66 let mut out = EXTENSION.to_string();
67 if self.server_no_context_takeover {
68 out.push_str("; server_no_context_takeover");
69 }
70 if self.client_no_context_takeover {
71 out.push_str("; client_no_context_takeover");
72 }
73 if self.server_max_window_bits < 15 {
74 out.push_str(&format!(
75 "; server_max_window_bits={}",
76 self.server_max_window_bits
77 ));
78 }
79 if self.client_max_window_bits < 15 {
80 out.push_str(&format!(
81 "; client_max_window_bits={}",
82 self.client_max_window_bits
83 ));
84 }
85 out
86 }
87
88 pub fn to_json(&self) -> serde_json::Value {
90 serde_json::json!({
91 "extension": EXTENSION,
92 "server_no_context_takeover": self.server_no_context_takeover,
93 "client_no_context_takeover": self.client_no_context_takeover,
94 "server_max_window_bits": self.server_max_window_bits,
95 "client_max_window_bits": self.client_max_window_bits,
96 })
97 }
98}
99
100fn parse_element(element: &str) -> Option<(String, Vec<(String, Option<String>)>)> {
102 let mut parts = element.split(';').map(str::trim);
103 let name = parts.next()?.to_ascii_lowercase();
104 if name.is_empty() {
105 return None;
106 }
107 let mut params = Vec::new();
108 for p in parts {
109 if p.is_empty() {
110 continue;
111 }
112 let (k, v) = match p.split_once('=') {
113 Some((k, v)) => (k.trim(), Some(v.trim().trim_matches('"').to_string())),
114 None => (p, None),
115 };
116 params.push((k.to_ascii_lowercase(), v));
117 }
118 Some((name, params))
119}
120
121fn elements<'a>(values: impl IntoIterator<Item = &'a str>) -> Vec<String> {
123 values
124 .into_iter()
125 .flat_map(|v| v.split(','))
126 .map(|e| e.trim().to_string())
127 .filter(|e| !e.is_empty())
128 .collect()
129}
130
131fn window_bits(value: &Option<String>) -> Result<Option<u8>, ()> {
134 match value {
135 None => Ok(None),
136 Some(v) => match v.parse::<u8>() {
137 Ok(n) if (9..=15).contains(&n) => Ok(Some(n)),
138 _ => Err(()),
139 },
140 }
141}
142
143pub fn negotiate<'a>(offers: impl IntoIterator<Item = &'a str>) -> Option<(DeflateParams, String)> {
147 'offer: for element in elements(offers) {
148 let Some((name, params)) = parse_element(&element) else {
149 continue;
150 };
151 if name != EXTENSION {
152 continue;
153 }
154 let mut accepted = DeflateParams::default();
155 let mut seen: Vec<&str> = Vec::new();
156 for (k, v) in ¶ms {
157 if seen.contains(&k.as_str()) {
159 continue 'offer;
160 }
161 seen.push(k.as_str());
162 match k.as_str() {
163 "server_no_context_takeover" if v.is_none() => {
164 accepted.server_no_context_takeover = true
165 }
166 "client_no_context_takeover" if v.is_none() => {
167 accepted.client_no_context_takeover = true
168 }
169 "server_max_window_bits" => match window_bits(v) {
170 Ok(Some(n)) => accepted.server_max_window_bits = n,
171 _ => continue 'offer,
172 },
173 "client_max_window_bits" => match window_bits(v) {
176 Ok(Some(n)) => accepted.client_max_window_bits = n,
177 Ok(None) => {}
178 Err(()) => continue 'offer,
179 },
180 _ => continue 'offer,
181 }
182 }
183 let value = accepted.header_value();
184 return Some((accepted, value));
185 }
186 None
187}
188
189pub fn accept_response<'a>(
192 values: impl IntoIterator<Item = &'a str>,
193) -> Result<Option<DeflateParams>, String> {
194 let all = elements(values);
195 let mut result = None;
196 for element in all {
197 let Some((name, params)) = parse_element(&element) else {
198 return Err(format!("malformed extension {element:?}"));
199 };
200 if name != EXTENSION {
201 return Err(format!(
202 "the server accepted an extension that was not offered: {name}"
203 ));
204 }
205 if result.is_some() {
206 return Err("the server accepted permessage-deflate twice".into());
207 }
208 let mut p = DeflateParams::default();
209 for (k, v) in ¶ms {
210 match k.as_str() {
211 "server_no_context_takeover" if v.is_none() => p.server_no_context_takeover = true,
212 "client_no_context_takeover" if v.is_none() => p.client_no_context_takeover = true,
213 "server_max_window_bits" => {
214 p.server_max_window_bits = window_bits(v)
215 .ok()
216 .flatten()
217 .ok_or_else(|| format!("bad server_max_window_bits {v:?}"))?
218 }
219 "client_max_window_bits" => {
220 p.client_max_window_bits = window_bits(v)
221 .ok()
222 .flatten()
223 .ok_or_else(|| format!("bad client_max_window_bits {v:?}"))?
224 }
225 other => return Err(format!("unknown permessage-deflate parameter {other:?}")),
226 }
227 }
228 result = Some(p);
229 }
230 Ok(result)
231}
232
233#[derive(Debug, Clone, Copy, PartialEq, Eq)]
235pub enum Side {
236 Server,
237 Client,
238}
239
240pub struct Codec {
242 side: Side,
243 params: DeflateParams,
244 inflate: Decompress,
245 deflate: Compress,
246 max_message: usize,
247}
248
249impl Codec {
250 pub fn new(side: Side, params: DeflateParams, max_message: usize) -> Self {
251 let (ours, theirs) = match side {
252 Side::Server => (params.server_max_window_bits, params.client_max_window_bits),
253 Side::Client => (params.client_max_window_bits, params.server_max_window_bits),
254 };
255 Self {
256 side,
257 params,
258 inflate: Decompress::new_with_window_bits(false, theirs.max(9)),
260 deflate: Compress::new_with_window_bits(Compression::default(), false, ours.max(9)),
261 max_message,
262 }
263 }
264
265 fn peer_resets(&self) -> bool {
266 match self.side {
267 Side::Server => self.params.client_no_context_takeover,
268 Side::Client => self.params.server_no_context_takeover,
269 }
270 }
271
272 fn we_reset(&self) -> bool {
273 match self.side {
274 Side::Server => self.params.server_no_context_takeover,
275 Side::Client => self.params.client_no_context_takeover,
276 }
277 }
278
279 pub fn inflate(&mut self, compressed: &[u8]) -> io::Result<Vec<u8>> {
282 let mut input = Vec::with_capacity(compressed.len() + TAIL.len());
283 input.extend_from_slice(compressed);
284 input.extend_from_slice(&TAIL);
285 let limit = self.max_message.saturating_add(1);
286 let start = self.inflate.total_in();
287 let mut out: Vec<u8> = Vec::new();
288 loop {
289 let room = (out.len() + 32 * 1024).min(limit) - out.len();
290 out.reserve_exact(room);
291 let (in_before, out_before) = (self.inflate.total_in(), out.len());
292 let consumed = (in_before - start) as usize;
293 self.inflate
294 .decompress_vec(&input[consumed..], &mut out, FlushDecompress::Sync)
295 .map_err(|e| protocol(&format!("inflate: {e}")))?;
296 if out.len() > self.max_message {
297 return Err(io::Error::new(
298 io::ErrorKind::InvalidData,
299 format!(
300 "permessage-deflate: message inflates past {} bytes",
301 self.max_message
302 ),
303 ));
304 }
305 let consumed = (self.inflate.total_in() - start) as usize;
306 if consumed >= input.len() && out.len() < out.capacity() {
307 break;
308 }
309 if self.inflate.total_in() == in_before && out.len() == out_before {
310 return Err(protocol("inflate made no progress"));
311 }
312 }
313 if self.peer_resets() {
314 self.inflate.reset(false);
315 }
316 Ok(out)
317 }
318
319 pub fn deflate(&mut self, payload: &[u8]) -> io::Result<Vec<u8>> {
321 let start = self.deflate.total_in();
322 let mut out: Vec<u8> = Vec::with_capacity(payload.len() / 2 + 64);
323 loop {
324 if out.capacity() - out.len() < 64 {
325 out.reserve(out.capacity().max(256));
326 }
327 let consumed = (self.deflate.total_in() - start) as usize;
328 self.deflate
329 .compress_vec(&payload[consumed..], &mut out, FlushCompress::Sync)
330 .map_err(|e| io::Error::other(format!("deflate: {e}")))?;
331 let consumed = (self.deflate.total_in() - start) as usize;
332 if consumed >= payload.len() && out.capacity() - out.len() >= 64 {
334 break;
335 }
336 }
337 if out.ends_with(&TAIL) {
338 out.truncate(out.len() - TAIL.len());
339 }
340 if self.we_reset() {
341 self.deflate.reset();
342 }
343 Ok(out)
344 }
345}
346
347#[derive(Debug, Clone, PartialEq, Eq)]
349pub struct Frame {
350 pub fin: bool,
351 pub rsv1: bool,
352 pub rsv23: u8,
354 pub opcode: u8,
355 pub mask: Option<[u8; 4]>,
356 pub payload: Vec<u8>,
357}
358
359impl Frame {
360 fn is_control_frame(&self) -> bool {
361 self.opcode >= 0x8
362 }
363
364 pub fn parse(buf: &[u8], max: usize) -> io::Result<Option<(Frame, usize)>> {
367 if buf.len() < 2 {
368 return Ok(None);
369 }
370 let b0 = buf[0];
371 let b1 = buf[1];
372 let masked = b1 & 0x80 != 0;
373 let (len, mut at) = match b1 & 0x7f {
374 126 => {
375 if buf.len() < 4 {
376 return Ok(None);
377 }
378 (u64::from(u16::from_be_bytes([buf[2], buf[3]])), 4usize)
379 }
380 127 => {
381 if buf.len() < 10 {
382 return Ok(None);
383 }
384 let mut b = [0u8; 8];
385 b.copy_from_slice(&buf[2..10]);
386 (u64::from_be_bytes(b), 10usize)
387 }
388 n => (u64::from(n), 2usize),
389 };
390 if len > max as u64 {
391 return Err(io::Error::new(
392 io::ErrorKind::InvalidData,
393 format!("frame of {len} bytes exceeds the {max}-byte limit"),
394 ));
395 }
396 let len = len as usize;
397 let mask = if masked {
398 if buf.len() < at + 4 {
399 return Ok(None);
400 }
401 let m = [buf[at], buf[at + 1], buf[at + 2], buf[at + 3]];
402 at += 4;
403 Some(m)
404 } else {
405 None
406 };
407 if buf.len() < at + len {
408 return Ok(None);
409 }
410 let mut payload = buf[at..at + len].to_vec();
411 if let Some(m) = mask {
412 for (i, b) in payload.iter_mut().enumerate() {
413 *b ^= m[i % 4];
414 }
415 }
416 Ok(Some((
417 Frame {
418 fin: b0 & 0x80 != 0,
419 rsv1: b0 & 0x40 != 0,
420 rsv23: b0 & 0x30,
421 opcode: b0 & 0x0f,
422 mask,
423 payload,
424 },
425 at + len,
426 )))
427 }
428
429 pub fn encode(&self, out: &mut Vec<u8>) {
430 out.push(
431 (if self.fin { 0x80 } else { 0 })
432 | (if self.rsv1 { 0x40 } else { 0 })
433 | self.rsv23
434 | self.opcode,
435 );
436 let mask_bit = if self.mask.is_some() { 0x80 } else { 0 };
437 let len = self.payload.len();
438 if len < 126 {
439 out.push(mask_bit | len as u8);
440 } else if len <= u16::MAX as usize {
441 out.push(mask_bit | 126);
442 out.extend_from_slice(&(len as u16).to_be_bytes());
443 } else {
444 out.push(mask_bit | 127);
445 out.extend_from_slice(&(len as u64).to_be_bytes());
446 }
447 match self.mask {
448 Some(m) => {
449 out.extend_from_slice(&m);
450 out.extend(self.payload.iter().enumerate().map(|(i, b)| b ^ m[i % 4]));
451 }
452 None => out.extend_from_slice(&self.payload),
453 }
454 }
455}
456
457struct Partial {
459 opcode: u8,
460 mask: Option<[u8; 4]>,
461 payload: Vec<u8>,
462}
463
464#[derive(Default)]
466struct Direction {
467 raw: Vec<u8>,
468 partial: Option<Partial>,
470 passing: bool,
472}
473
474enum Mode {
475 Plain,
477 AwaitResponse {
480 max_message: usize,
481 },
482 Active(Box<Codec>),
483}
484
485pub struct DeflateStream<S> {
487 inner: S,
488 mode: Mode,
489 max_message: usize,
490 max_frame: usize,
492 read: Direction,
493 write: Direction,
494 ready: Vec<u8>,
496 pending: Vec<u8>,
498 negotiated: Option<Result<Option<DeflateParams>, String>>,
500}
501
502impl<S> DeflateStream<S> {
503 pub fn server(
506 inner: S,
507 params: Option<DeflateParams>,
508 max_message: usize,
509 max_frame: usize,
510 leftover: Vec<u8>,
511 ) -> Self {
512 let mut s = Self::new(inner, max_message, max_frame);
513 if let Some(p) = params {
514 s.mode = Mode::Active(Box::new(Codec::new(Side::Server, p, max_message)));
515 }
516 s.read.raw = leftover;
517 s
518 }
519
520 pub fn client(inner: S, max_message: usize, max_frame: usize) -> Self {
522 let mut s = Self::new(inner, max_message, max_frame);
523 s.mode = Mode::AwaitResponse { max_message };
524 s
525 }
526
527 fn new(inner: S, max_message: usize, max_frame: usize) -> Self {
528 Self {
529 inner,
530 mode: Mode::Plain,
531 max_message,
532 max_frame: max_frame.max(1),
533 read: Direction::default(),
534 write: Direction::default(),
535 ready: Vec::new(),
536 pending: Vec::new(),
537 negotiated: None,
538 }
539 }
540
541 pub fn get_ref(&self) -> &S {
542 &self.inner
543 }
544
545 pub fn negotiated(&self) -> Option<&Result<Option<DeflateParams>, String>> {
547 self.negotiated.as_ref()
548 }
549
550 pub fn active(&self) -> Option<DeflateParams> {
552 match &self.mode {
553 Mode::Active(c) => Some(c.params),
554 _ => None,
555 }
556 }
557
558 fn process_read(&mut self) -> io::Result<()> {
560 if let Mode::AwaitResponse { max_message } = self.mode {
561 let Some(end) = self.read.raw.windows(4).position(|w| w == b"\r\n\r\n") else {
562 if self.read.raw.len() > 64 * 1024 {
563 return Err(io::Error::new(
564 io::ErrorKind::InvalidData,
565 "handshake response head exceeds 64 KiB",
566 ));
567 }
568 return Ok(());
569 };
570 let head: Vec<u8> = self.read.raw.drain(..end + 4).collect();
571 let text = String::from_utf8_lossy(&head).to_string();
572 let values: Vec<&str> = text
573 .split("\r\n")
574 .filter_map(|l| l.split_once(':'))
575 .filter(|(k, _)| k.trim().eq_ignore_ascii_case("sec-websocket-extensions"))
576 .map(|(_, v)| v.trim())
577 .collect();
578 let switching = text.starts_with("HTTP/1.1 101");
579 let result = if switching {
580 accept_response(values)
581 } else {
582 Ok(None)
583 };
584 self.mode = match &result {
585 Ok(Some(p)) => Mode::Active(Box::new(Codec::new(Side::Client, *p, max_message))),
586 _ => Mode::Plain,
587 };
588 self.negotiated = Some(result.clone());
589 self.ready.extend_from_slice(&head);
590 if let Err(e) = result {
591 return Err(io::Error::new(io::ErrorKind::InvalidData, e));
592 }
593 }
594 let Mode::Active(codec) = &mut self.mode else {
595 self.ready.append(&mut self.read.raw);
596 return Ok(());
597 };
598 let max = self.max_message;
599 loop {
600 let Some((frame, used)) = Frame::parse(&self.read.raw, max)? else {
601 return Ok(());
602 };
603 self.read.raw.drain(..used);
604 if frame.is_control_frame() {
605 frame.encode(&mut self.ready);
606 continue;
607 }
608 let starts = frame.opcode != 0;
609 if starts && frame.rsv1 {
610 if self.read.partial.is_some() || self.read.passing {
611 return Err(protocol("a new message began inside another"));
612 }
613 if frame.fin {
614 let payload = codec.inflate(&frame.payload)?;
615 emit_message(
616 &mut self.ready,
617 frame.opcode,
618 frame.rsv23,
619 frame.mask,
620 payload,
621 self.max_frame,
622 );
623 } else {
624 self.read.partial = Some(Partial {
625 opcode: frame.opcode,
626 mask: frame.mask,
627 payload: frame.payload,
628 });
629 }
630 continue;
631 }
632 if frame.opcode == 0 {
633 if let Some(partial) = self.read.partial.as_mut() {
634 if frame.rsv1 {
635 return Err(protocol("RSV1 on a continuation frame"));
636 }
637 if partial.payload.len() + frame.payload.len() > max {
638 return Err(io::Error::new(
639 io::ErrorKind::InvalidData,
640 format!("compressed message exceeds {max} bytes"),
641 ));
642 }
643 partial.payload.extend_from_slice(&frame.payload);
644 if frame.fin {
645 let partial = self.read.partial.take().expect("checked above");
646 let payload = codec.inflate(&partial.payload)?;
647 emit_message(
648 &mut self.ready,
649 partial.opcode,
650 frame.rsv23,
651 partial.mask,
652 payload,
653 self.max_frame,
654 );
655 }
656 continue;
657 }
658 }
659 if starts {
661 self.read.passing = !frame.fin;
662 } else if frame.fin {
663 self.read.passing = false;
664 }
665 frame.encode(&mut self.ready);
666 }
667 }
668
669 fn process_write(&mut self) -> io::Result<()> {
671 let Mode::Active(codec) = &mut self.mode else {
672 self.pending.append(&mut self.write.raw);
673 return Ok(());
674 };
675 loop {
676 let Some((frame, used)) = Frame::parse(&self.write.raw, usize::MAX / 2)? else {
679 return Ok(());
680 };
681 self.write.raw.drain(..used);
682 if frame.is_control_frame() {
683 frame.encode(&mut self.pending);
684 continue;
685 }
686 let partial = match (frame.opcode, self.write.partial.take()) {
687 (0, Some(mut p)) => {
688 p.payload.extend_from_slice(&frame.payload);
689 p
690 }
691 (0, None) => {
692 frame.encode(&mut self.pending);
693 continue;
694 }
695 (op, _) => Partial {
696 opcode: op,
697 mask: frame.mask,
698 payload: frame.payload,
699 },
700 };
701 if !frame.fin {
702 self.write.partial = Some(partial);
703 continue;
704 }
705 let payload = codec.deflate(&partial.payload)?;
706 Frame {
707 fin: true,
708 rsv1: true,
709 rsv23: 0,
710 opcode: partial.opcode,
711 mask: partial.mask,
712 payload,
713 }
714 .encode(&mut self.pending);
715 }
716 }
717}
718
719fn emit_message(
722 out: &mut Vec<u8>,
723 opcode: u8,
724 rsv23: u8,
725 mask: Option<[u8; 4]>,
726 payload: Vec<u8>,
727 max_frame: usize,
728) {
729 if payload.len() <= max_frame {
730 Frame {
731 fin: true,
732 rsv1: false,
733 rsv23,
734 opcode,
735 mask,
736 payload,
737 }
738 .encode(out);
739 return;
740 }
741 let chunks: Vec<&[u8]> = payload.chunks(max_frame).collect();
742 let last = chunks.len() - 1;
743 for (i, chunk) in chunks.into_iter().enumerate() {
744 Frame {
745 fin: i == last,
746 rsv1: false,
747 rsv23,
748 opcode: if i == 0 { opcode } else { 0 },
749 mask,
750 payload: chunk.to_vec(),
751 }
752 .encode(out);
753 }
754}
755
756fn protocol(msg: &str) -> io::Error {
757 io::Error::new(
758 io::ErrorKind::InvalidData,
759 format!("permessage-deflate: {msg}"),
760 )
761}
762
763impl<S: AsyncRead + AsyncWrite + Unpin> DeflateStream<S> {
764 fn poll_drain(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
766 while !self.pending.is_empty() {
767 let n = match Pin::new(&mut self.inner).poll_write(cx, &self.pending) {
768 Poll::Ready(Ok(0)) => {
769 return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
770 }
771 Poll::Ready(Ok(n)) => n,
772 Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
773 Poll::Pending => return Poll::Pending,
774 };
775 self.pending.drain(..n);
776 }
777 Poll::Ready(Ok(()))
778 }
779}
780
781impl<S: AsyncRead + AsyncWrite + Unpin> AsyncRead for DeflateStream<S> {
782 fn poll_read(
783 self: Pin<&mut Self>,
784 cx: &mut Context<'_>,
785 buf: &mut ReadBuf<'_>,
786 ) -> Poll<io::Result<()>> {
787 let this = self.get_mut();
788 loop {
789 if !this.ready.is_empty() {
790 let n = this.ready.len().min(buf.remaining());
791 buf.put_slice(&this.ready[..n]);
792 this.ready.drain(..n);
793 return Poll::Ready(Ok(()));
794 }
795 if !this.read.raw.is_empty() {
797 let before = this.read.raw.len();
798 this.process_read()?;
799 if !this.ready.is_empty() {
800 continue;
801 }
802 if this.read.raw.len() != before {
803 continue;
804 }
805 }
806 let mut chunk = [0u8; 16 * 1024];
807 let mut rb = ReadBuf::new(&mut chunk);
808 match Pin::new(&mut this.inner).poll_read(cx, &mut rb) {
809 Poll::Ready(Ok(())) => {
810 let got = rb.filled();
811 if got.is_empty() {
812 return Poll::Ready(Ok(()));
815 }
816 this.read.raw.extend_from_slice(got);
817 this.process_read()?;
818 }
819 Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
820 Poll::Pending => return Poll::Pending,
821 }
822 }
823 }
824}
825
826impl<S: AsyncRead + AsyncWrite + Unpin> AsyncWrite for DeflateStream<S> {
827 fn poll_write(
828 self: Pin<&mut Self>,
829 cx: &mut Context<'_>,
830 buf: &[u8],
831 ) -> Poll<io::Result<usize>> {
832 let this = self.get_mut();
833 if this.pending.len() > this.max_message {
835 match this.poll_drain(cx) {
836 Poll::Ready(Ok(())) => {}
837 Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
838 Poll::Pending => return Poll::Pending,
839 }
840 }
841 this.write.raw.extend_from_slice(buf);
842 this.process_write()?;
843 if let Poll::Ready(Err(e)) = this.poll_drain(cx) {
845 return Poll::Ready(Err(e));
846 }
847 Poll::Ready(Ok(buf.len()))
848 }
849
850 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
851 let this = self.get_mut();
852 match this.poll_drain(cx) {
853 Poll::Ready(Ok(())) => Pin::new(&mut this.inner).poll_flush(cx),
854 other => other,
855 }
856 }
857
858 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
859 let this = self.get_mut();
860 match this.poll_drain(cx) {
861 Poll::Ready(Ok(())) => Pin::new(&mut this.inner).poll_shutdown(cx),
862 other => other,
863 }
864 }
865}