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