Skip to main content

h2/proto/streams/
recv.rs

1use super::*;
2use crate::codec::UserError;
3use crate::frame::{PushPromiseHeaderError, Reason, DEFAULT_INITIAL_WINDOW_SIZE};
4use crate::proto;
5
6use http::{HeaderMap, Request, Response};
7
8use std::cmp::Ordering;
9use std::io;
10use std::task::{Context, Poll, Waker};
11use std::time::Instant;
12
13#[derive(Debug)]
14pub(super) struct Recv {
15    /// Initial window size of remote initiated streams
16    init_window_sz: WindowSize,
17
18    /// Connection level flow control governing received data
19    flow: FlowControl,
20
21    /// Amount of connection window capacity currently used by outstanding streams.
22    in_flight_data: WindowSize,
23
24    /// The lowest stream ID that is still idle
25    next_stream_id: Result<StreamId, StreamIdOverflow>,
26
27    /// The stream ID of the last processed stream
28    last_processed_id: StreamId,
29
30    /// Any streams with a higher ID are ignored.
31    ///
32    /// This starts as MAX, but is lowered when a GOAWAY is received.
33    ///
34    /// > After sending a GOAWAY frame, the sender can discard frames for
35    /// > streams initiated by the receiver with identifiers higher than
36    /// > the identified last stream.
37    max_stream_id: StreamId,
38
39    /// Streams that have pending window updates
40    pending_window_updates: store::Queue<stream::NextWindowUpdate>,
41
42    /// New streams to be accepted
43    pending_accept: store::Queue<stream::NextAccept>,
44
45    /// Locally reset streams that should be reaped when they expire
46    pending_reset_expired: store::Queue<stream::NextResetExpire>,
47
48    /// How long locally reset streams should ignore received frames
49    reset_duration: Duration,
50
51    /// Holds frames that are waiting to be read
52    buffer: Buffer<Event>,
53
54    /// Refused StreamId, this represents a frame that must be sent out.
55    refused: Option<StreamId>,
56
57    /// If push promises are allowed to be received.
58    is_push_enabled: bool,
59
60    /// If extended connect protocol is enabled.
61    is_extended_connect_protocol_enabled: bool,
62}
63
64#[derive(Debug)]
65pub(super) enum Event {
66    Headers(peer::PollMessage),
67    Data(DataEvent),
68    Trailers(HeaderMap),
69    InformationalHeaders(peer::PollMessage),
70}
71
72#[derive(Debug)]
73pub(super) struct DataEvent {
74    pub(super) payload: Bytes,
75    pub(super) is_budgeted: bool,
76}
77
78#[derive(Debug)]
79pub(super) enum RecvHeaderBlockError<T> {
80    Oversize(T),
81    State(Error),
82}
83
84#[derive(Debug)]
85pub(crate) enum Open {
86    PushPromise,
87    Headers,
88}
89
90impl Recv {
91    pub fn new(peer: peer::Dyn, config: &Config) -> Self {
92        let next_stream_id = if peer.is_server() { 1 } else { 2 };
93
94        let mut flow = FlowControl::new();
95
96        // connections always have the default window size, regardless of
97        // settings
98        flow.inc_window(DEFAULT_INITIAL_WINDOW_SIZE)
99            .expect("invalid initial remote window size");
100        flow.assign_capacity(DEFAULT_INITIAL_WINDOW_SIZE).unwrap();
101
102        Recv {
103            init_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
104            flow,
105            in_flight_data: 0 as WindowSize,
106            next_stream_id: Ok(next_stream_id.into()),
107            pending_window_updates: store::Queue::new(),
108            last_processed_id: StreamId::ZERO,
109            max_stream_id: StreamId::MAX,
110            pending_accept: store::Queue::new(),
111            pending_reset_expired: store::Queue::new(),
112            reset_duration: config.local_reset_duration,
113            buffer: Buffer::new(),
114            refused: None,
115            is_push_enabled: config.local_push_enabled,
116            is_extended_connect_protocol_enabled: config.extended_connect_protocol_enabled,
117        }
118    }
119
120    /// Returns the initial receive window size
121    pub fn init_window_sz(&self) -> WindowSize {
122        self.init_window_sz
123    }
124
125    /// Returns the ID of the last processed stream
126    pub fn last_processed_id(&self) -> StreamId {
127        self.last_processed_id
128    }
129
130    /// Update state reflecting a new, remotely opened stream
131    ///
132    /// Returns the stream state if successful. `None` if refused
133    pub fn open(
134        &mut self,
135        id: StreamId,
136        mode: Open,
137        counts: &mut Counts,
138    ) -> Result<Option<StreamId>, Error> {
139        assert!(self.refused.is_none());
140
141        counts.peer().ensure_can_open(id, mode)?;
142
143        let next_id = self.next_stream_id()?;
144        if id < next_id {
145            proto_err!(conn: "id ({:?}) < next_id ({:?})", id, next_id);
146            return Err(Error::library_go_away(Reason::PROTOCOL_ERROR));
147        }
148
149        self.next_stream_id = id.next_id();
150
151        if !counts.can_inc_num_recv_streams() {
152            self.refused = Some(id);
153            return Ok(None);
154        }
155
156        Ok(Some(id))
157    }
158
159    /// Transition the stream state based on receiving headers
160    ///
161    /// The caller ensures that the frame represents headers and not trailers.
162    pub fn recv_headers(
163        &mut self,
164        frame: frame::Headers,
165        stream: &mut store::Ptr,
166        counts: &mut Counts,
167    ) -> Result<(), RecvHeaderBlockError<Option<frame::Headers>>> {
168        tracing::trace!("opening stream; init_window={}", self.init_window_sz);
169        let is_initial = stream.state.recv_open(&frame)?;
170
171        // Informational responses do not transition a remotely reserved stream
172        // out of `ReservedRemote`. As a result, `recv_open` reports each of them
173        // as initial. Only account for the stream once.
174        if is_initial && !stream.is_counted {
175            // TODO: be smarter about this logic
176            if frame.stream_id() > self.last_processed_id {
177                self.last_processed_id = frame.stream_id();
178            }
179
180            // Increment the number of concurrent streams
181            counts.inc_num_recv_streams(stream);
182        }
183
184        if !stream.content_length.is_head() {
185            use super::stream::ContentLength;
186            use http::header;
187
188            if let Some(content_length) = frame.fields().get(header::CONTENT_LENGTH) {
189                let content_length = match frame::parse_u64(content_length.as_bytes()) {
190                    Ok(v) => v,
191                    Err(_) => {
192                        proto_err!(stream: "could not parse content-length; stream={:?}", stream.id);
193                        return Err(Error::library_reset(stream.id, Reason::PROTOCOL_ERROR).into());
194                    }
195                };
196
197                stream.content_length = ContentLength::Remaining(content_length);
198                // END_STREAM on headers frame with non-zero content-length is malformed.
199                // https://datatracker.ietf.org/doc/html/rfc9113#section-8.1.1
200                if frame.is_end_stream()
201                    && content_length > 0
202                    && frame
203                        .pseudo()
204                        .status
205                        .map_or(true, |status| status != 204 && status != 304)
206                {
207                    proto_err!(stream: "recv_headers with END_STREAM: content-length is not zero; stream={:?};", stream.id);
208                    return Err(Error::library_reset(stream.id, Reason::PROTOCOL_ERROR).into());
209                }
210            }
211        }
212
213        if frame.is_over_size() {
214            // A frame is over size if the decoded header block was bigger than
215            // SETTINGS_MAX_HEADER_LIST_SIZE.
216            //
217            // > A server that receives a larger header block than it is willing
218            // > to handle can send an HTTP 431 (Request Header Fields Too
219            // > Large) status code [RFC6585]. A client can discard responses
220            // > that it cannot process.
221            //
222            // So, if peer is a server, we'll send a 431. In either case,
223            // an error is recorded, which will send a REFUSED_STREAM,
224            // since we don't want any of the data frames either.
225            tracing::debug!(
226                "stream error REQUEST_HEADER_FIELDS_TOO_LARGE -- \
227                 recv_headers: frame is over size; stream={:?}",
228                stream.id
229            );
230            return if counts.peer().is_server() && is_initial {
231                let mut res = frame::Headers::new(
232                    stream.id,
233                    frame::Pseudo::response(::http::StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE),
234                    HeaderMap::new(),
235                );
236                res.set_end_stream();
237                Err(RecvHeaderBlockError::Oversize(Some(res)))
238            } else {
239                Err(RecvHeaderBlockError::Oversize(None))
240            };
241        }
242
243        let stream_id = frame.stream_id();
244        let (pseudo, fields) = frame.into_parts();
245
246        if pseudo.protocol.is_some()
247            && counts.peer().is_server()
248            && !self.is_extended_connect_protocol_enabled
249        {
250            proto_err!(stream: "cannot use :protocol if extended connect protocol is disabled; stream={:?}", stream.id);
251            return Err(Error::library_reset(stream.id, Reason::PROTOCOL_ERROR).into());
252        }
253
254        if pseudo.status.is_some() && counts.peer().is_server() {
255            proto_err!(stream: "cannot use :status header for requests; stream={:?}", stream.id);
256            return Err(Error::library_reset(stream.id, Reason::PROTOCOL_ERROR).into());
257        }
258
259        if !pseudo.is_informational() {
260            let message = counts
261                .peer()
262                .convert_poll_message(pseudo, fields, stream_id)?;
263
264            // Push the frame onto the stream's recv buffer
265            stream
266                .pending_recv
267                .push_back(&mut self.buffer, Event::Headers(message));
268            stream.notify_recv();
269
270            // Only servers can receive a headers frame that initiates the stream.
271            // This is verified in `Streams` before calling this function.
272            if counts.peer().is_server() {
273                // Correctness: never push a stream to `pending_accept` without having the
274                // corresponding headers frame pushed to `stream.pending_recv`.
275                self.pending_accept.push(stream);
276            }
277        } else {
278            // This is an informational response (1xx status code)
279            // Convert to response and store it for polling
280            let message = counts
281                .peer()
282                .convert_poll_message(pseudo, fields, stream_id)?;
283
284            tracing::trace!("Received informational response: stream_id={:?}", stream_id);
285
286            // Push the informational response onto the stream's recv buffer
287            // with a special event type so it can be polled separately
288            stream
289                .pending_recv
290                .push_back(&mut self.buffer, Event::InformationalHeaders(message));
291            stream.notify_recv();
292        }
293
294        Ok(())
295    }
296
297    /// Called by the server to get the request
298    ///
299    /// # Panics
300    ///
301    /// Panics if `stream.pending_recv` has no `Event::Headers` queued.
302    ///
303    pub fn take_request(&mut self, stream: &mut store::Ptr) -> Request<()> {
304        use super::peer::PollMessage::*;
305
306        match stream.pending_recv.pop_front(&mut self.buffer) {
307            Some(Event::Headers(Server(request))) => request,
308            _ => unreachable!("server stream queue must start with Headers"),
309        }
310    }
311
312    /// Called by the client to get pushed response
313    pub fn poll_pushed(
314        &mut self,
315        cx: &Context,
316        stream: &mut store::Ptr,
317    ) -> Poll<Option<Result<(Request<()>, store::Key), proto::Error>>> {
318        use super::peer::PollMessage::*;
319
320        let mut ppp = stream.pending_push_promises.take();
321        let pushed = ppp.pop(stream.store_mut()).map(|mut pushed| {
322            match pushed.pending_recv.pop_front(&mut self.buffer) {
323                Some(Event::Headers(Server(headers))) => (headers, pushed.key()),
324                // When frames are pushed into the queue, it is verified that
325                // the first frame is a HEADERS frame.
326                _ => panic!("Headers not set on pushed stream"),
327            }
328        });
329        stream.pending_push_promises = ppp;
330        if let Some(p) = pushed {
331            Poll::Ready(Some(Ok(p)))
332        } else {
333            let is_open = stream.state.ensure_recv_open()?;
334
335            if is_open {
336                stream.push_task = Some(cx.waker().clone());
337                Poll::Pending
338            } else {
339                Poll::Ready(None)
340            }
341        }
342    }
343
344    /// Called by the client to get the response
345    pub fn poll_response(
346        &mut self,
347        cx: &Context,
348        stream: &mut store::Ptr,
349    ) -> Poll<Result<Response<()>, proto::Error>> {
350        use super::peer::PollMessage::*;
351
352        // Skip over any interim informational headers to find the main response
353        loop {
354            match stream.pending_recv.pop_front(&mut self.buffer) {
355                Some(Event::Headers(Client(response))) => return Poll::Ready(Ok(response)),
356                Some(Event::InformationalHeaders(_)) => {
357                    tracing::trace!("Skipping informational response in poll_response - should be consumed via poll_informational; stream_id={:?}", stream.id);
358                    continue;
359                }
360                Some(_) => panic!("poll_response called after response returned"),
361                None => {
362                    if !stream.state.ensure_recv_open()? {
363                        proto_err!(stream: "poll_response: stream={:?} is not opened;",  stream.id);
364                        return Poll::Ready(Err(Error::library_reset(
365                            stream.id,
366                            Reason::PROTOCOL_ERROR,
367                        )));
368                    }
369
370                    stream.recv_task = Some(cx.waker().clone());
371                    return Poll::Pending;
372                }
373            }
374        }
375    }
376
377    /// Called by the client to get informational responses (1xx status codes)
378    pub fn poll_informational(
379        &mut self,
380        cx: &Context,
381        stream: &mut store::Ptr,
382    ) -> Poll<Option<Result<Response<()>, proto::Error>>> {
383        use super::peer::PollMessage::*;
384
385        // Try to pop the front event and check if it's an informational response
386        // If it's not, we put it back
387        if let Some(event) = stream.pending_recv.pop_front(&mut self.buffer) {
388            match event {
389                Event::Headers(Client(response)) => {
390                    // Final response
391                    stream
392                        .pending_recv
393                        .push_front(&mut self.buffer, Event::Headers(Client(response)));
394                    return Poll::Ready(None);
395                }
396                Event::InformationalHeaders(Client(response)) => {
397                    // Found an informational response, return it
398                    return Poll::Ready(Some(Ok(response)));
399                }
400                other => {
401                    // Not an informational response, put it back at the front
402                    stream.pending_recv.push_front(&mut self.buffer, other);
403                }
404            }
405        }
406
407        // No informational response available at the front
408        if stream.state.ensure_recv_open()? {
409            // Request to get notified once more frames arrive
410            stream.recv_task = Some(cx.waker().clone());
411            Poll::Pending
412        } else {
413            // No more frames will be received
414            Poll::Ready(None)
415        }
416    }
417
418    /// Transition the stream based on receiving trailers
419    pub fn recv_trailers(
420        &mut self,
421        frame: frame::Headers,
422        stream: &mut store::Ptr,
423    ) -> Result<(), Error> {
424        // Transition the state
425        stream.state.recv_close()?;
426
427        if stream.ensure_content_length_zero().is_err() {
428            proto_err!(stream: "recv_trailers: content-length is not zero; stream={:?};",  stream.id);
429            return Err(Error::library_reset(stream.id, Reason::PROTOCOL_ERROR));
430        }
431
432        let trailers = frame.into_fields();
433
434        // Push the frame onto the stream's recv buffer
435        stream
436            .pending_recv
437            .push_back(&mut self.buffer, Event::Trailers(trailers));
438        stream.notify_recv();
439
440        Ok(())
441    }
442
443    /// Releases capacity of the connection
444    pub fn release_connection_capacity(&mut self, capacity: WindowSize, task: &mut Option<Waker>) {
445        tracing::trace!(
446            "release_connection_capacity; size={}, connection in_flight_data={}",
447            capacity,
448            self.in_flight_data,
449        );
450
451        // Decrement in-flight data
452        self.in_flight_data -= capacity;
453
454        // Assign capacity to connection
455        // TODO: proper error handling
456        let _res = self.flow.assign_capacity(capacity);
457        debug_assert!(_res.is_ok());
458
459        if self.flow.unclaimed_capacity().is_some() {
460            if let Some(task) = task.take() {
461                task.wake();
462            }
463        }
464    }
465
466    /// Releases capacity back to the connection & stream
467    pub fn release_capacity(
468        &mut self,
469        capacity: WindowSize,
470        stream: &mut store::Ptr,
471        task: &mut Option<Waker>,
472    ) -> Result<(), UserError> {
473        tracing::trace!("release_capacity; size={}", capacity);
474
475        if capacity > stream.in_flight_recv_data {
476            return Err(UserError::ReleaseCapacityTooBig);
477        }
478
479        self.release_connection_capacity(capacity, task);
480
481        // Decrement in-flight data
482        stream.in_flight_recv_data -= capacity;
483
484        // Assign capacity to stream
485        // TODO: proper error handling
486        let _res = stream.recv_flow.assign_capacity(capacity);
487        debug_assert!(_res.is_ok());
488
489        if stream.recv_flow.unclaimed_capacity().is_some() {
490            // Queue the stream for sending the WINDOW_UPDATE frame.
491            self.pending_window_updates.push(stream);
492
493            if let Some(task) = task.take() {
494                task.wake();
495            }
496        }
497
498        Ok(())
499    }
500
501    /// Release any unclaimed capacity for a closed stream.
502    pub fn release_closed_capacity(
503        &mut self,
504        stream: &mut store::Ptr,
505        task: &mut Option<Waker>,
506        counts: &mut Counts,
507    ) {
508        debug_assert_eq!(stream.ref_count, 0);
509
510        if stream.in_flight_recv_data != 0 {
511            tracing::trace!(
512                "auto-release closed stream ({:?}) capacity: {:?}",
513                stream.id,
514                stream.in_flight_recv_data,
515            );
516
517            self.release_connection_capacity(stream.in_flight_recv_data, task);
518            stream.in_flight_recv_data = 0;
519        }
520
521        self.clear_recv_buffer(stream, task, counts);
522    }
523
524    /// Set the "target" connection window size.
525    ///
526    /// By default, all new connections start with 64kb of window size. As
527    /// streams used and release capacity, we will send WINDOW_UPDATEs for the
528    /// connection to bring it back up to the initial "target".
529    ///
530    /// Setting a target means that we will try to tell the peer about
531    /// WINDOW_UPDATEs so the peer knows it has about `target` window to use
532    /// for the whole connection.
533    ///
534    /// The `task` is an optional parked task for the `Connection` that might
535    /// be blocked on needing more window capacity.
536    pub fn set_target_connection_window(
537        &mut self,
538        target: WindowSize,
539        task: &mut Option<Waker>,
540    ) -> Result<(), Reason> {
541        tracing::trace!(
542            "set_target_connection_window; target={}; available={}, reserved={}",
543            target,
544            self.flow.available(),
545            self.in_flight_data,
546        );
547
548        // The current target connection window is our `available` plus any
549        // in-flight data reserved by streams.
550        //
551        // Update the flow controller with the difference between the new
552        // target and the current target.
553        let current = self
554            .flow
555            .available()
556            .add(self.in_flight_data)?
557            .checked_size();
558        if target > current {
559            self.flow.assign_capacity(target - current)?;
560        } else {
561            self.flow.claim_capacity(current - target)?;
562        }
563
564        // If changing the target capacity means we gained a bunch of capacity,
565        // enough that we went over the update threshold, then schedule sending
566        // a connection WINDOW_UPDATE.
567        if self.flow.unclaimed_capacity().is_some() {
568            if let Some(task) = task.take() {
569                task.wake();
570            }
571        }
572        Ok(())
573    }
574
575    pub(crate) fn apply_local_settings(
576        &mut self,
577        settings: &frame::Settings,
578        store: &mut Store,
579    ) -> Result<(), proto::Error> {
580        if let Some(val) = settings.is_extended_connect_protocol_enabled() {
581            self.is_extended_connect_protocol_enabled = val;
582        }
583
584        if let Some(target) = settings.initial_window_size() {
585            let old_sz = self.init_window_sz;
586            self.init_window_sz = target;
587
588            tracing::trace!("update_initial_window_size; new={}; old={}", target, old_sz,);
589
590            // Per RFC 7540 ยง6.9.2:
591            //
592            // In addition to changing the flow-control window for streams that are
593            // not yet active, a SETTINGS frame can alter the initial flow-control
594            // window size for streams with active flow-control windows (that is,
595            // streams in the "open" or "half-closed (remote)" state). When the
596            // value of SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST adjust
597            // the size of all stream flow-control windows that it maintains by the
598            // difference between the new value and the old value.
599            //
600            // A change to `SETTINGS_INITIAL_WINDOW_SIZE` can cause the available
601            // space in a flow-control window to become negative. A sender MUST
602            // track the negative flow-control window and MUST NOT send new
603            // flow-controlled frames until it receives WINDOW_UPDATE frames that
604            // cause the flow-control window to become positive.
605
606            match target.cmp(&old_sz) {
607                Ordering::Less => {
608                    // We must decrease the (local) window on every open stream.
609                    let dec = old_sz - target;
610                    tracing::trace!("decrementing all windows; dec={}", dec);
611
612                    store.try_for_each(|mut stream| {
613                        stream
614                            .recv_flow
615                            .dec_recv_window(dec)
616                            .map_err(proto::Error::library_go_away)?;
617                        Ok::<_, proto::Error>(())
618                    })?;
619                }
620                Ordering::Greater => {
621                    // We must increase the (local) window on every open stream.
622                    let inc = target - old_sz;
623                    tracing::trace!("incrementing all windows; inc={}", inc);
624                    store.try_for_each(|mut stream| {
625                        // XXX: Shouldn't the peer have already noticed our
626                        // overflow and sent us a GOAWAY?
627                        stream
628                            .recv_flow
629                            .inc_window(inc)
630                            .map_err(proto::Error::library_go_away)?;
631                        stream
632                            .recv_flow
633                            .assign_capacity(inc)
634                            .map_err(proto::Error::library_go_away)?;
635                        Ok::<_, proto::Error>(())
636                    })?;
637                }
638                Ordering::Equal => (),
639            }
640        }
641
642        Ok(())
643    }
644
645    pub fn is_end_stream(&self, stream: &store::Ptr) -> bool {
646        if !stream.state.is_recv_end_stream() {
647            return false;
648        }
649
650        stream.pending_recv.is_empty()
651    }
652
653    pub fn recv_data(&mut self, frame: frame::Data, stream: &mut store::Ptr) -> Result<(), Error> {
654        // could include padding
655        let sz = frame.flow_controlled_len();
656
657        // This should have been enforced at the codec::FramedRead layer, so
658        // this is just a sanity check.
659        assert!(sz <= MAX_WINDOW_SIZE as usize);
660
661        let sz = sz as WindowSize;
662
663        let is_ignoring_frame = stream.state.is_local_error();
664
665        if !is_ignoring_frame && !stream.state.is_recv_streaming() {
666            // TODO: There are cases where this can be a stream error of
667            // STREAM_CLOSED instead...
668
669            // Receiving a DATA frame when not expecting one is a protocol
670            // error.
671            proto_err!(conn: "unexpected DATA frame; stream={:?}", stream.id);
672            return Err(Error::library_go_away(Reason::PROTOCOL_ERROR));
673        }
674
675        tracing::trace!(
676            "recv_data; size={}; connection={}; stream={}",
677            sz,
678            self.flow.window_size(),
679            stream.recv_flow.window_size()
680        );
681
682        if is_ignoring_frame {
683            tracing::trace!(
684                "recv_data; frame ignored on locally reset {:?} for some time",
685                stream.id,
686            );
687            return self.ignore_data(sz);
688        }
689
690        // Ensure that there is enough capacity on the connection before acting
691        // on the stream.
692        self.consume_connection_window(sz)?;
693
694        if stream.recv_flow.window_size() < sz {
695            // http://httpwg.org/specs/rfc7540.html#WINDOW_UPDATE
696            // > A receiver MAY respond with a stream error (Section 5.4.2) or
697            // > connection error (Section 5.4.1) of type FLOW_CONTROL_ERROR if
698            // > it is unable to accept a frame.
699            //
700            // So, for violating the **stream** window, we can send either a
701            // stream or connection error. We've opted to send a stream
702            // error.
703            return Err(Error::library_reset(stream.id, Reason::FLOW_CONTROL_ERROR));
704        }
705
706        // use payload len, padding doesn't count for content-length
707        if stream.dec_content_length(frame.payload().len()).is_err() {
708            proto_err!(stream:
709                "recv_data: content-length overflow; stream={:?}; len={:?}",
710                stream.id,
711                frame.payload().len(),
712            );
713            return Err(Error::library_reset(stream.id, Reason::PROTOCOL_ERROR));
714        }
715
716        if frame.is_end_stream() {
717            if stream.ensure_content_length_zero().is_err() {
718                proto_err!(stream:
719                    "recv_data: content-length underflow; stream={:?}; len={:?}",
720                    stream.id,
721                    frame.payload().len(),
722                );
723                return Err(Error::library_reset(stream.id, Reason::PROTOCOL_ERROR));
724            }
725
726            if stream.state.recv_close().is_err() {
727                proto_err!(conn: "recv_data: failed to transition to closed state; stream={:?}", stream.id);
728                return Err(Error::library_go_away(Reason::PROTOCOL_ERROR));
729            }
730        }
731
732        // Received a frame, but no one cared about it. fix issue#648
733        if !stream.is_recv {
734            tracing::trace!(
735                "recv_data; frame ignored on stream release {:?} for some time",
736                stream.id,
737            );
738            self.release_connection_capacity(sz, &mut None);
739            return Ok(());
740        }
741
742        // Update stream level flow control
743        stream
744            .recv_flow
745            .send_data(sz)
746            .map_err(proto::Error::library_go_away)?;
747
748        // Track the data as in-flight
749        stream.in_flight_recv_data += sz;
750
751        // Auto-release padding overhead (pad_len field + padding bytes),
752        // since the user only sees the data payload via `payload()`.
753        let padding = (frame.flow_controlled_len() - frame.payload().len()) as WindowSize;
754        if padding > 0 {
755            tracing::trace!(
756                "recv_data; auto-releasing padding of {:?} for {:?}",
757                padding,
758                stream.id,
759            );
760            let _res = self.release_capacity(padding, stream, &mut None);
761            // cannot fail, we JUST added more in_flight data above.
762            debug_assert!(_res.is_ok());
763        }
764
765        // An empty DATA frame without END_STREAM has no effect on the HTTP
766        // message. Padding has already been accounted for and released above,
767        // so there is no event to pass to the user.
768        if frame.payload().is_empty() && !frame.is_end_stream() {
769            return Ok(());
770        }
771
772        let is_budgeted = !frame.is_end_stream();
773        let event = Event::Data(DataEvent {
774            payload: frame.into_payload(),
775            is_budgeted,
776        });
777
778        // Push the frame onto the recv buffer
779        stream.pending_recv.push_back(&mut self.buffer, event);
780        stream.notify_recv();
781
782        Ok(())
783    }
784
785    pub fn ignore_data(&mut self, sz: WindowSize) -> Result<(), Error> {
786        // Ensure that there is enough capacity on the connection...
787        self.consume_connection_window(sz)?;
788
789        // Since we are ignoring this frame,
790        // we aren't returning the frame to the user. That means they
791        // have no way to release the capacity back to the connection. So
792        // we have to release it automatically.
793        //
794        // This call doesn't send a WINDOW_UPDATE immediately, just marks
795        // the capacity as available to be reclaimed. When the available
796        // capacity meets a threshold, a WINDOW_UPDATE is then sent.
797        self.release_connection_capacity(sz, &mut None);
798        Ok(())
799    }
800
801    pub fn consume_connection_window(&mut self, sz: WindowSize) -> Result<(), Error> {
802        if self.flow.window_size() < sz {
803            tracing::debug!(
804                "connection error FLOW_CONTROL_ERROR -- window_size ({:?}) < sz ({:?});",
805                self.flow.window_size(),
806                sz,
807            );
808            return Err(Error::library_go_away(Reason::FLOW_CONTROL_ERROR));
809        }
810
811        // Update connection level flow control
812        self.flow.send_data(sz).map_err(Error::library_go_away)?;
813
814        // Track the data as in-flight
815        self.in_flight_data += sz;
816        Ok(())
817    }
818
819    pub fn recv_push_promise(
820        &mut self,
821        frame: frame::PushPromise,
822        stream: &mut store::Ptr,
823    ) -> Result<(), Error> {
824        stream.state.reserve_remote()?;
825        if frame.is_over_size() {
826            // A frame is over size if the decoded header block was bigger than
827            // SETTINGS_MAX_HEADER_LIST_SIZE.
828            //
829            // > A server that receives a larger header block than it is willing
830            // > to handle can send an HTTP 431 (Request Header Fields Too
831            // > Large) status code [RFC6585]. A client can discard responses
832            // > that it cannot process.
833            //
834            // So, if peer is a server, we'll send a 431. In either case,
835            // an error is recorded, which will send a PROTOCOL_ERROR,
836            // since we don't want any of the data frames either.
837            tracing::debug!(
838                "stream error PROTOCOL_ERROR -- recv_push_promise: \
839                 headers frame is over size; promised_id={:?};",
840                frame.promised_id(),
841            );
842            return Err(Error::library_reset(
843                frame.promised_id(),
844                Reason::PROTOCOL_ERROR,
845            ));
846        }
847
848        let promised_id = frame.promised_id();
849        let (pseudo, fields) = frame.into_parts();
850        let req = crate::server::Peer::convert_poll_message(pseudo, fields, promised_id)?;
851
852        if let Err(e) = frame::PushPromise::validate_request(&req) {
853            use PushPromiseHeaderError::*;
854            match e {
855                NotSafeAndCacheable => proto_err!(
856                    stream:
857                    "recv_push_promise: method {} is not safe and cacheable; promised_id={:?}",
858                    req.method(),
859                    promised_id,
860                ),
861                InvalidContentLength(e) => proto_err!(
862                    stream:
863                    "recv_push_promise; promised request has invalid content-length {:?}; promised_id={:?}",
864                    e,
865                    promised_id,
866                ),
867            }
868            return Err(Error::library_reset(promised_id, Reason::PROTOCOL_ERROR));
869        }
870
871        use super::peer::PollMessage::*;
872        stream
873            .pending_recv
874            .push_back(&mut self.buffer, Event::Headers(Server(req)));
875        stream.notify_recv();
876        stream.notify_push();
877        Ok(())
878    }
879
880    /// Ensures that `id` is not in the `Idle` state.
881    pub fn ensure_not_idle(&self, id: StreamId) -> Result<(), Reason> {
882        if let Ok(next) = self.next_stream_id {
883            if id >= next {
884                tracing::debug!(
885                    "stream ID implicitly closed, PROTOCOL_ERROR; stream={:?}",
886                    id
887                );
888                return Err(Reason::PROTOCOL_ERROR);
889            }
890        }
891        // if next_stream_id is overflowed, that's ok.
892
893        Ok(())
894    }
895
896    /// Handle remote sending an explicit RST_STREAM.
897    pub fn recv_reset(
898        &mut self,
899        frame: frame::Reset,
900        stream: &mut Stream,
901        counts: &mut Counts,
902    ) -> Result<(), Error> {
903        // Reseting a stream that the user hasn't accepted is possible,
904        // but should be done with care. These streams will continue
905        // to take up memory in the accept queue, but will no longer be
906        // counted as "concurrent" streams.
907        //
908        // So, we have a separate limit for these.
909        //
910        // See https://github.com/hyperium/hyper/issues/2877
911        if stream.is_pending_accept {
912            if counts.can_inc_num_remote_reset_streams() {
913                counts.inc_num_remote_reset_streams();
914            } else {
915                tracing::warn!(
916                    "recv_reset; remotely-reset pending-accept streams reached limit ({:?})",
917                    counts.max_remote_reset_streams(),
918                );
919                return Err(Error::library_go_away_data(
920                    Reason::ENHANCE_YOUR_CALM,
921                    "too_many_resets",
922                ));
923            }
924        }
925
926        // Notify the stream
927        stream.state.recv_reset(frame, stream.is_pending_send);
928
929        stream.notify_send();
930        stream.notify_recv();
931        stream.notify_push();
932
933        Ok(())
934    }
935
936    /// Handle a connection-level error
937    pub fn handle_error(&mut self, err: &proto::Error, stream: &mut Stream) {
938        // Receive an error
939        stream.state.handle_error(err);
940
941        // If a receiver is waiting, notify it
942        stream.notify_send();
943        stream.notify_recv();
944        stream.notify_push();
945    }
946
947    pub fn go_away(&mut self, last_processed_id: StreamId) {
948        assert!(self.max_stream_id >= last_processed_id);
949        self.max_stream_id = last_processed_id;
950    }
951
952    pub fn recv_eof(&mut self, stream: &mut Stream) {
953        stream.state.recv_eof();
954        stream.notify_send();
955        stream.notify_recv();
956        stream.notify_push();
957    }
958
959    pub(super) fn clear_recv_buffer(
960        &mut self,
961        stream: &mut Stream,
962        task: &mut Option<Waker>,
963        counts: &mut Counts,
964    ) {
965        let mut to_release: WindowSize = 0;
966        while let Some(event) = stream.pending_recv.pop_front(&mut self.buffer) {
967            if let Event::Data(data) = &event {
968                if data.is_budgeted {
969                    counts.release_data_frame(data.payload.len());
970                }
971                to_release = to_release
972                    .saturating_add(data.payload.len() as WindowSize)
973                    .min(stream.in_flight_recv_data);
974            }
975        }
976        // Release flow control capacity. Cases:
977        // * User read data but hasn't released: buf=0, in_flight>0 -> release 0
978        // * User released without reading: buf>0, in_flight=0 -> release 0
979        // * Normal drop without reading: buf=in_flight -> full release
980        if to_release > 0 {
981            stream.in_flight_recv_data -= to_release;
982            self.release_connection_capacity(to_release, task);
983        }
984    }
985
986    /// Get the max ID of streams we can receive.
987    ///
988    /// This gets lowered if we send a GOAWAY frame.
989    pub fn max_stream_id(&self) -> StreamId {
990        self.max_stream_id
991    }
992
993    pub fn next_stream_id(&self) -> Result<StreamId, Error> {
994        if let Ok(id) = self.next_stream_id {
995            Ok(id)
996        } else {
997            Err(Error::library_go_away(Reason::PROTOCOL_ERROR))
998        }
999    }
1000
1001    pub fn may_have_created_stream(&self, id: StreamId) -> bool {
1002        if let Ok(next_id) = self.next_stream_id {
1003            // Peer::is_local_init should have been called beforehand
1004            debug_assert_eq!(id.is_server_initiated(), next_id.is_server_initiated(),);
1005            id < next_id
1006        } else {
1007            true
1008        }
1009    }
1010
1011    pub(super) fn maybe_reset_next_stream_id(&mut self, id: StreamId) {
1012        if let Ok(next_id) = self.next_stream_id {
1013            // !Peer::is_local_init should have been called beforehand
1014            debug_assert_eq!(id.is_server_initiated(), next_id.is_server_initiated());
1015            if id >= next_id {
1016                self.next_stream_id = id.next_id();
1017            }
1018        }
1019    }
1020
1021    /// Returns true if the remote peer can reserve a stream with the given ID.
1022    pub fn ensure_can_reserve(&self) -> Result<(), Error> {
1023        if !self.is_push_enabled {
1024            proto_err!(conn: "recv_push_promise: push is disabled");
1025            return Err(Error::library_go_away(Reason::PROTOCOL_ERROR));
1026        }
1027
1028        Ok(())
1029    }
1030
1031    /// Add a locally reset stream to queue to be eventually reaped.
1032    pub fn enqueue_reset_expiration(&mut self, stream: &mut store::Ptr, counts: &mut Counts) {
1033        if !stream.state.is_local_error() || stream.is_pending_reset_expiration() {
1034            return;
1035        }
1036
1037        if counts.can_inc_num_reset_streams() {
1038            counts.inc_num_reset_streams();
1039            tracing::trace!("enqueue_reset_expiration; added {:?}", stream.id);
1040            self.pending_reset_expired.push(stream);
1041        } else {
1042            tracing::trace!(
1043                "enqueue_reset_expiration; dropped {:?}, over max_concurrent_reset_streams",
1044                stream.id
1045            );
1046        }
1047    }
1048
1049    /// Send any pending refusals.
1050    pub fn send_pending_refusal<T, B>(
1051        &mut self,
1052        dst: &mut Codec<T, Prioritized<B>>,
1053    ) -> io::Result<BufferStatus>
1054    where
1055        T: AsyncWrite + Unpin,
1056        B: Buf,
1057    {
1058        if let Some(stream_id) = self.refused {
1059            if !dst.has_send_capacity() {
1060                return Ok(BufferStatus::CodecFull);
1061            }
1062
1063            // Create the RST_STREAM frame
1064            let frame = frame::Reset::new(stream_id, Reason::REFUSED_STREAM);
1065
1066            // Buffer the frame
1067            dst.buffer(frame.into()).expect("invalid RST_STREAM frame");
1068        }
1069
1070        self.refused = None;
1071
1072        Ok(BufferStatus::Complete)
1073    }
1074
1075    pub fn clear_expired_reset_streams(&mut self, store: &mut Store, counts: &mut Counts) {
1076        if !self.pending_reset_expired.is_empty() {
1077            let now = Instant::now();
1078            let reset_duration = self.reset_duration;
1079            while let Some(stream) = self.pending_reset_expired.pop_if(store, |stream| {
1080                let reset_at = stream.reset_at.expect("reset_at must be set if in queue");
1081                // rust-lang/rust#86470 tracks a bug in the standard library where `Instant`
1082                // subtraction can panic (because, on some platforms, `Instant` isn't actually
1083                // monotonic). We use a saturating operation to avoid this panic here.
1084                now.saturating_duration_since(reset_at) > reset_duration
1085            }) {
1086                counts.transition_after(stream, true);
1087            }
1088        }
1089    }
1090
1091    pub fn clear_queues(
1092        &mut self,
1093        clear_pending_accept: bool,
1094        store: &mut Store,
1095        counts: &mut Counts,
1096    ) {
1097        self.clear_stream_window_update_queue(store, counts);
1098        self.clear_all_reset_streams(store, counts);
1099
1100        if clear_pending_accept {
1101            self.clear_all_pending_accept(store, counts);
1102        }
1103    }
1104
1105    fn clear_stream_window_update_queue(&mut self, store: &mut Store, counts: &mut Counts) {
1106        while let Some(stream) = self.pending_window_updates.pop(store) {
1107            counts.transition(stream, |_, stream| {
1108                tracing::trace!("clear_stream_window_update_queue; stream={:?}", stream.id);
1109            })
1110        }
1111    }
1112
1113    /// Called on EOF
1114    fn clear_all_reset_streams(&mut self, store: &mut Store, counts: &mut Counts) {
1115        while let Some(stream) = self.pending_reset_expired.pop(store) {
1116            counts.transition_after(stream, true);
1117        }
1118    }
1119
1120    fn clear_all_pending_accept(&mut self, store: &mut Store, counts: &mut Counts) {
1121        while let Some(stream) = self.pending_accept.pop(store) {
1122            counts.transition_after(stream, false);
1123        }
1124    }
1125
1126    pub fn buffer_pending<T, B>(
1127        &mut self,
1128        store: &mut Store,
1129        counts: &mut Counts,
1130        dst: &mut Codec<T, Prioritized<B>>,
1131    ) -> io::Result<BufferStatus>
1132    where
1133        T: AsyncWrite + Unpin,
1134        B: Buf,
1135    {
1136        // Send any pending connection level window updates
1137        if self.send_connection_window_update(dst)? == BufferStatus::CodecFull {
1138            return Ok(BufferStatus::CodecFull);
1139        }
1140
1141        // Send any pending stream level window updates
1142        if self.send_stream_window_updates(store, counts, dst)? == BufferStatus::CodecFull {
1143            return Ok(BufferStatus::CodecFull);
1144        }
1145
1146        Ok(BufferStatus::Complete)
1147    }
1148
1149    /// Send connection level window update
1150    fn send_connection_window_update<T, B>(
1151        &mut self,
1152        dst: &mut Codec<T, Prioritized<B>>,
1153    ) -> io::Result<BufferStatus>
1154    where
1155        T: AsyncWrite + Unpin,
1156        B: Buf,
1157    {
1158        if let Some(incr) = self.flow.unclaimed_capacity() {
1159            let frame = frame::WindowUpdate::new(StreamId::zero(), incr);
1160
1161            // Ensure the codec has capacity
1162            if !dst.has_send_capacity() {
1163                return Ok(BufferStatus::CodecFull);
1164            }
1165
1166            // Buffer the WINDOW_UPDATE frame
1167            dst.buffer(frame.into())
1168                .expect("invalid WINDOW_UPDATE frame");
1169
1170            // Update flow control
1171            self.flow
1172                .inc_window(incr)
1173                .expect("unexpected flow control state");
1174        }
1175
1176        Ok(BufferStatus::Complete)
1177    }
1178
1179    /// Send stream level window update
1180    pub fn send_stream_window_updates<T, B>(
1181        &mut self,
1182        store: &mut Store,
1183        counts: &mut Counts,
1184        dst: &mut Codec<T, Prioritized<B>>,
1185    ) -> io::Result<BufferStatus>
1186    where
1187        T: AsyncWrite + Unpin,
1188        B: Buf,
1189    {
1190        loop {
1191            // Ensure the codec has capacity
1192            if !dst.has_send_capacity() {
1193                return Ok(BufferStatus::CodecFull);
1194            }
1195
1196            // Get the next stream
1197            let stream = match self.pending_window_updates.pop(store) {
1198                Some(stream) => stream,
1199                None => return Ok(BufferStatus::Complete),
1200            };
1201
1202            counts.transition(stream, |_, stream| {
1203                tracing::trace!("pending_window_updates -- pop; stream={:?}", stream.id);
1204                debug_assert!(!stream.is_pending_window_update);
1205
1206                if !stream.state.is_recv_streaming() {
1207                    // No need to send window updates on the stream if the stream is
1208                    // no longer receiving data.
1209                    //
1210                    // TODO: is this correct? We could possibly send a window
1211                    // update on a ReservedRemote stream if we already know
1212                    // we want to stream the data faster...
1213                    return;
1214                }
1215
1216                // TODO: de-dup
1217                if let Some(incr) = stream.recv_flow.unclaimed_capacity() {
1218                    // Create the WINDOW_UPDATE frame
1219                    let frame = frame::WindowUpdate::new(stream.id, incr);
1220
1221                    // Buffer it
1222                    dst.buffer(frame.into())
1223                        .expect("invalid WINDOW_UPDATE frame");
1224
1225                    // Update flow control
1226                    stream
1227                        .recv_flow
1228                        .inc_window(incr)
1229                        .expect("unexpected flow control state");
1230                }
1231            })
1232        }
1233    }
1234
1235    pub fn next_incoming(&mut self, store: &mut Store) -> Option<store::Key> {
1236        self.pending_accept.pop(store).map(|ptr| ptr.key())
1237    }
1238
1239    pub fn poll_data(
1240        &mut self,
1241        cx: &Context,
1242        stream: &mut Stream,
1243    ) -> Poll<Option<Result<DataEvent, proto::Error>>> {
1244        match stream.pending_recv.pop_front(&mut self.buffer) {
1245            Some(Event::Data(data)) => Poll::Ready(Some(Ok(data))),
1246            Some(event) => {
1247                // Frame is trailer
1248                stream.pending_recv.push_front(&mut self.buffer, event);
1249
1250                // Notify the recv task. This is done just in case
1251                // `poll_trailers` was called.
1252                //
1253                // It is very likely that `notify_recv` will just be a no-op (as
1254                // the task will be None), so this isn't really much of a
1255                // performance concern. It also means we don't have to track
1256                // state to see if `poll_trailers` was called before `poll_data`
1257                // returned `None`.
1258                stream.notify_recv();
1259
1260                // No more data frames
1261                Poll::Ready(None)
1262            }
1263            None => self.schedule_recv(cx, stream),
1264        }
1265    }
1266
1267    pub fn poll_trailers(
1268        &mut self,
1269        cx: &Context,
1270        stream: &mut Stream,
1271    ) -> Poll<Option<Result<HeaderMap, proto::Error>>> {
1272        match stream.pending_recv.pop_front(&mut self.buffer) {
1273            Some(Event::Trailers(trailers)) => Poll::Ready(Some(Ok(trailers))),
1274            Some(event) => {
1275                // Frame is not trailers.. not ready to poll trailers yet.
1276                stream.pending_recv.push_front(&mut self.buffer, event);
1277                stream.recv_task = Some(cx.waker().clone());
1278                Poll::Pending
1279            }
1280            None => self.schedule_recv(cx, stream),
1281        }
1282    }
1283
1284    fn schedule_recv<T>(
1285        &mut self,
1286        cx: &Context,
1287        stream: &mut Stream,
1288    ) -> Poll<Option<Result<T, proto::Error>>> {
1289        if stream.state.ensure_recv_open()? {
1290            // Request to get notified once more frames arrive
1291            stream.recv_task = Some(cx.waker().clone());
1292            Poll::Pending
1293        } else {
1294            // No more frames will be received
1295            Poll::Ready(None)
1296        }
1297    }
1298}
1299
1300#[cfg(test)]
1301mod tests {
1302    use super::*;
1303
1304    #[test]
1305    fn clear_recv_buffer_caps_capacity_before_overflow() {
1306        const FRAME_LEN: usize = 1 << 20;
1307        const FRAME_COUNT: usize = (u32::MAX as usize / FRAME_LEN) + 1;
1308
1309        let config = Config {
1310            initial_max_send_streams: 0,
1311            local_max_buffer_size: 0,
1312            local_next_stream_id: 2.into(),
1313            local_push_enabled: false,
1314            extended_connect_protocol_enabled: false,
1315            local_reset_duration: Duration::ZERO,
1316            local_reset_max: 0,
1317            remote_reset_max: 0,
1318            remote_init_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
1319            remote_max_initiated: None,
1320            local_max_error_reset_streams: None,
1321            data_frame_budget: DEFAULT_DATA_FRAME_BUDGET,
1322        };
1323        let mut recv = Recv::new(peer::Dyn::Server, &config);
1324        let mut store = Store::new();
1325        let mut stream = store.insert(
1326            StreamId::from(1),
1327            Stream::new(StreamId::from(1), 0, DEFAULT_INITIAL_WINDOW_SIZE),
1328        );
1329        let data = Bytes::from(vec![0; FRAME_LEN]);
1330
1331        for _ in 0..FRAME_COUNT {
1332            stream.pending_recv.push_back(
1333                &mut recv.buffer,
1334                Event::Data(DataEvent {
1335                    payload: data.clone(),
1336                    is_budgeted: true,
1337                }),
1338            );
1339        }
1340        stream.in_flight_recv_data = DEFAULT_INITIAL_WINDOW_SIZE;
1341        recv.in_flight_data = DEFAULT_INITIAL_WINDOW_SIZE;
1342
1343        let mut counts = Counts::new(peer::Dyn::Server, &config);
1344        recv.clear_recv_buffer(&mut stream, &mut None, &mut counts);
1345
1346        assert!(stream.pending_recv.is_empty());
1347        assert_eq!(stream.in_flight_recv_data, 0);
1348        assert_eq!(recv.in_flight_data, 0);
1349    }
1350}
1351
1352// ===== impl Open =====
1353
1354impl Open {
1355    pub fn is_push_promise(&self) -> bool {
1356        matches!(*self, Self::PushPromise)
1357    }
1358}
1359
1360// ===== impl RecvHeaderBlockError =====
1361
1362impl<T> From<Error> for RecvHeaderBlockError<T> {
1363    fn from(err: Error) -> Self {
1364        RecvHeaderBlockError::State(err)
1365    }
1366}