Skip to main content

netget/server/websocket/
deflate.rs

1//! RFC 7692 permessage-deflate, as a byte stream beneath tungstenite.
2//!
3//! tungstenite 0.21 — every published version, in fact — has no extension hook and refuses
4//! any frame with RSV1 set, so the extension lives one layer down: [`DeflateStream`] wraps
5//! the socket, reads and writes WebSocket frames itself, and shows tungstenite only
6//! uncompressed ones.
7//!
8//! - **Inbound**, a message whose first frame has RSV1 set is collected across its
9//!   continuation frames, inflated as one (§7.2.2: append `00 00 ff ff`, then inflate) and
10//!   handed up as a single unfragmented frame with RSV1 clear, keeping the peer's masking key
11//!   so a server-role tungstenite still sees a masked client frame. Uncompressed messages and
12//!   every control frame pass through untouched.
13//! - **Outbound**, every data message tungstenite writes is deflated (§7.2.1: compress, sync
14//!   flush, drop the trailing `00 00 ff ff`) and sent as one frame with RSV1 set, re-masked
15//!   with tungstenite's own key on the client side.
16//!
17//! Context takeover is kept unless the negotiation said otherwise, and a negotiated
18//! `*_max_window_bits` is honoured in both directions (flate2's zlib backend). Inflation is
19//! bounded by the connection's maximum message size, checked while inflating, so a small
20//! compressed frame cannot expand past it (a decompression bomb is an error, not an
21//! allocation).
22
23use 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
29/// The extension token (§7).
30pub const EXTENSION: &str = "permessage-deflate";
31
32/// What the offer the client sends looks like: no constraints of its own, and it accepts any
33/// window the server picks for client-to-server messages.
34pub const CLIENT_OFFER: &str = "permessage-deflate; client_max_window_bits";
35
36/// The tail a sync flush ends with, which §7.2.1 removes and §7.2.2 puts back.
37const TAIL: [u8; 4] = [0x00, 0x00, 0xff, 0xff];
38
39/// One side's negotiated parameters.
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub struct DeflateParams {
42    /// The server resets its compression context after every message.
43    pub server_no_context_takeover: bool,
44    /// The client resets its compression context after every message.
45    pub client_no_context_takeover: bool,
46    /// LZ77 window the server compresses with (9..=15).
47    pub server_max_window_bits: u8,
48    /// LZ77 window the client compresses with (9..=15).
49    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    /// The `Sec-WebSocket-Extensions` value that states these parameters.
65    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    /// As the event payloads report it.
89    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
100/// `name; p1; p2=v` as (name, [(param, value)]). Quoted values are unquoted (§9.1 allows them).
101fn 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
121/// Every element of every `Sec-WebSocket-Extensions` value, in order.
122fn 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
131/// A window size parameter: 9..=15. zlib cannot make a raw-deflate stream with an 8-bit window
132/// (it silently uses 9), so an offer demanding 8 is one this side cannot honour.
133fn 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
143/// Server side (§5, §7.1): accept the first `permessage-deflate` offer this server can honour,
144/// and say what was accepted. `None` when there is no such offer — the connection then runs
145/// uncompressed, which is always allowed.
146pub 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 &params {
157            // §7.1: a parameter twice, or one with a bad value, invalidates the offer.
158            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                // A hint that the client can take a smaller window; this server keeps 15 for
174                // the client's direction unless the client names a value it wants.
175                "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
189/// Client side (§7.1): what the server's response says, checked against what was offered.
190/// `Ok(None)` is a server that declined, `Err` one that answered with something not offered.
191pub 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 &params {
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/// Which end of the connection this stream is.
234#[derive(Debug, Clone, Copy, PartialEq, Eq)]
235pub enum Side {
236    Server,
237    Client,
238}
239
240/// The compression state of one negotiated connection.
241pub 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            // Inflating with a window at least as large as the sender's is always correct.
259            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    /// Inflate one message's payload, refusing to produce more than `max_message` bytes. The
280    /// output buffer never grows past `max_message + 1`, so the check happens while inflating.
281    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    /// Deflate one message's payload with a sync flush and the tail removed.
320    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            // Done once the input is consumed and the flush fitted with room to spare.
333            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/// One WebSocket frame as it crossed the wire, payload unmasked.
348#[derive(Debug, Clone, PartialEq, Eq)]
349pub struct Frame {
350    pub fin: bool,
351    pub rsv1: bool,
352    /// RSV2 and RSV3, carried through untouched so tungstenite still refuses them.
353    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    /// Parse one frame from the front of `buf`; `Ok(None)` when more bytes are needed. A
365    /// declared length past `max` is refused before anything is buffered for it.
366    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
457/// A data message being reassembled.
458struct Partial {
459    opcode: u8,
460    mask: Option<[u8; 4]>,
461    payload: Vec<u8>,
462}
463
464/// The frame transform for one direction.
465#[derive(Default)]
466struct Direction {
467    raw: Vec<u8>,
468    /// A compressed (inbound) or to-be-compressed (outbound) message in progress.
469    partial: Option<Partial>,
470    /// An uncompressed inbound message is being passed through frame by frame.
471    passing: bool,
472}
473
474enum Mode {
475    /// No extension: bytes pass straight through.
476    Plain,
477    /// Client side before the 101: pass bytes through until the response head is complete,
478    /// then read `Sec-WebSocket-Extensions` from it.
479    AwaitResponse {
480        max_message: usize,
481    },
482    Active(Box<Codec>),
483}
484
485/// The socket beneath tungstenite. See the module docs.
486pub struct DeflateStream<S> {
487    inner: S,
488    mode: Mode,
489    max_message: usize,
490    /// Largest frame handed up to tungstenite; an inflated message is re-fragmented to fit.
491    max_frame: usize,
492    read: Direction,
493    write: Direction,
494    /// Bytes ready for tungstenite to read.
495    ready: Vec<u8>,
496    /// Bytes ready for the socket.
497    pending: Vec<u8>,
498    /// What the 101 response negotiated (client side), once read.
499    negotiated: Option<Result<Option<DeflateParams>, String>>,
500}
501
502impl<S> DeflateStream<S> {
503    /// A server connection whose handshake already happened: `leftover` is whatever the
504    /// handshake read beyond the request head, which belongs to the frame stream.
505    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    /// A client connection about to send its handshake. The response decides the mode.
521    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    /// Client side: what the server accepted, once its response has been read.
546    pub fn negotiated(&self) -> Option<&Result<Option<DeflateParams>, String>> {
547        self.negotiated.as_ref()
548    }
549
550    /// The parameters in force, if the extension is active.
551    pub fn active(&self) -> Option<DeflateParams> {
552        match &self.mode {
553            Mode::Active(c) => Some(c.params),
554            _ => None,
555        }
556    }
557
558    /// Turn raw inbound bytes into what tungstenite should read.
559    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            // An uncompressed message, or a stray continuation tungstenite will judge.
660            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    /// Turn what tungstenite wrote into what goes on the wire.
670    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            // Our own writer's frames: bounded by what tungstenite was configured to send, so
677            // the limit here only guards against a frame we could not represent.
678            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
719/// An inflated message as frames of at most `max_frame` bytes each, so tungstenite's own frame
720/// limit judges the frames the peer sent rather than the size the message inflated to.
721fn 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    /// Write `pending` to the socket; `Ready(Ok)` once it is empty.
765    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            // Anything already buffered (the server's handshake leftover) first.
796            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                        // EOF: a frame cut off mid-way is simply not delivered; tungstenite
813                        // sees the stream end.
814                        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        // Keep at most one message's worth queued for the socket: past that, wait for it.
834        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        // Push what is ready without waiting; flush finishes the job.
844        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}